栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > Vue.js

Vue-imooc,全模拟数据

Vue.js 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Vue-imooc,全模拟数据

目录结构

/ src

  • components —— 组件
  • mock —— 模拟数据
  • public —— 静态资源
  • router —— 路由
  • store —— 状态管理
  • views —— 页面
技术栈

vue-cli、vue-router、vuex、axios、mock.js

插件

vue-awsome-swiper、better-scroll

页面快速预览

下来玩玩

vue-imooc

重点

使用Mockjs
vue-cli项目中使用mockjs模拟数据

封装storage


let storage = (function () {

  let st = null;

  if (!window.localStorage) {
    throw new Error('sorry, your browser is not suport localStorage!')
  } else {
    st = window.localStorage
  }

  let set = function (key, val) {
    if (typeof val == 'object') {
      val = JSON.stringify(val);
    }
    st.setItem(key, val);
  }

  let get = function (key) {
    return st.getItem(key);
  }

  let clear = function () {
    st.clear();
  }

  return {
    set,
    get,
    clear
  }

})()

export default storage

需要管理的状态

state.js


export default {
  userInfo: null, // 用户信息
  shopCartInfo: null, // 购物车信息
  toast: "" // toast提示的内容
}

action.js


export default {
  set_userInfo(context, userInfo) {
    context.commit('set_userInfo', userInfo)
  },
  set_shopCartInfo(context, shopCartInfo) {
    context.commit('set_shopCartInfo', shopCartInfo)
  },
  set_toast(context, toast) {
    context.commit('set_toast', toast)
  }
}

mutations.js


export default {
  set_userInfo(state, userInfo) {
    state.userInfo = userInfo
  },
  set_shopCartInfo(state, shopCartInfo) {
    state.shopCartInfo = shopCartInfo
  },
  set_toast(state, toast) {
    state.toast = toast
  }
}

封装toast轻提示插件

toast.vue






.toast {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 1.5rem;
  margin: auto;
  max-width: 30rem;
  min-height: 4rem;
  text-align: center;
  z-index: 101;
  .toast-value {
    padding: 1rem 1.5rem;
    background-color: #474747;
    color: #fff;
    border-radius: 2rem;
    font-size: 1.2rem;
  }
}

toast.js


import store from '../../store'

let toast = (function () {

  let timer = null

  let show = function (content) {

    // 清除定时器
    clearTimeout(timer)

    // 提交set_toast方法
    store.commit('set_toast', content)

    // 只显示3秒
    timer = setTimeout(() => {
      store.commit('set_toast', '')
    }, 3000)

  }

  return {
    show
  }

})()

export default toast

登录、登出

// 登录
this.$storage.set("userInfo", userInfo);
this.$store.commit("set_userInfo", userInfo); 

// 登出
this.$storage.set("userInfo", "");
this.$store.commit("set_userInfo", ""); 

登录状态

app.vue

created() {
  let userInfo = this.$storage.get("userInfo") || null;
  userinfo && userInfo = JSON.parse(userInfo);
  this.$store.commit("set_userInfo", userInfo); 
}

其他组件判断是否已登录

if (this.$store.state.userInfo)

加入购物车动画

css

.circle {
  transition: all 1s cubic-bezier(0.075, 0.82, 0.165, 1);
}


.icon-cart {
  transition: all 0.1s ease;
  &.scale {
    transform: scale(1.5);
  }
 }
// 获取鼠标点击时的x,y坐标
let { pageX, pageY } = e;

 // 获取购物车图标的x,y坐标
let cart = document.querySelector(".icon-cart");
let { x, y } = cart.getBoundingClientRect();

// 在鼠标点击处生成小球
let circle = document.createElement("span");
circle.className = "circle";
circle.style.cssText = `top: ${pageY}px; left: ${pageX}px`; // 初始化小球位置
document.body.appendChild(circle);

// 小球移动到购物车
setTimeout(() => {
  circle.style.cssText = `top: ${y}px; left: ${x + 5}px`; // 移动到购物车的位置
  // 根据css设置的过渡时间移除小球、购物车做放大动画
  setTimeout(() => {
    circle.remove();
    cart.classList.add("scale");
    setTimeout(() => {
      cart.classList.remove("scale");
    }, 100);
  }, 900);
}, 50);

轮播图

vue-awesome-swiper文档

参数

options: {
  effect: "coverflow",
  slidesPerView: 1.1,
  spaceBetween: 65,
  centeredSlides: true,
  autoplay: {
    delay: 3000,
    disableOnInteraction: false
  },
  coverflowEffect: {
    rotate: 0,
    stretch: 10,
    depth: 100,
    modifier: 2,
    slideShadows: true
  },
  loop: true,
  pagination: {
    el: ".swiper-pagination"
  }
}

Pagination切换动画,修改样式即可

.swiper-container {
  padding-bottom: 3rem;
  .swiper-pagination {
    bottom: 0rem;
    span {
      background-color: #d9dde1;
      opacity: 0.6;
      transition: width 0.2s ease-in;
      border-radius: 0.6rem;
      &.swiper-pagination-bullet-active {
 width: 3rem;
 background-color: #d9dde1;
 opacity: 1;
      }
    }
  }
}

better-scroll,左右联动
better-scroll文档

联动脚本



data() {
  return {
    mscroll: null, // 左边的scroll区域
    cscroll: null, // 右边的scroll区域
    scrollY: 0, // 当前滚动的Y值
    listHeight: [] // 左边内容块距离顶部的距离
  }
},
initBetterScroll() {
  this.$nextTick(function() {
  setTimeout(() => {
      let wrapper = this.$refs.cwrapper;
      // 初始化better-scroll插件
      this.cscroll = new BScroll(wrapper, {
 click: true,
 probeType: 3
      });
      // 监听内容区的滚动
      this.cscroll.on("scroll", pos => {
 this.scrollY = Math.abs(Math.round(pos.y));
      });
      // 计算高度
      this.caclHeight();
    }, 500);
  });
},
// 计算右边内容块距离顶部的高度(叠加), 等scroll插件初始化完成并且内容渲染完成再开始计算
caclHeight() {
  let content = document.querySelectorAll(".content-wrapper .content-item");
  let height = 0;
  this.listHeight.push(height);
  content.forEach(item => {
    height += item.clientHeight;
    this.listHeight.push(height);
  });
},
// 选中左边的item
selectMenu(index) {
  let content = document.querySelectorAll(".content-wrapper .content-item");
  let el = content[index];
  this.cscroll.scrollToElement(el, 300);
},
computed: {
  // 当前活跃的item索引值
  currentIndex() {
    for (let i = 0; i < this.listHeight.length; i++) {
      let height1 = this.listHeight[i];
      let height2 = this.listHeight[i + 1];
      if (
 !height2 ||
 (this.scrollY >= height1 && this.scrollY <= height2 - 50)
      ) {
 return i;
      }
    }
    return 0;
  }
},

过渡动画

给单个组件添加过渡动画

template


css

.slidedown-enter-active {
  animation: bounce-in 0.3s;
}


.slidedown-leave-active {
  animation: bounce-in 0.3s reverse;
}

@keyframes bounce-in {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(0);
  }
}

上滑加载

封装onReachBottom函数

let onReachBottom = function (callback) {
  window.onscroll = function () {
    // 滚动高度 + 视窗高度 >= 内容高度
    let isBottom = window.scrollY + document.documentElement.clientHeight >= document.body.clientHeight;
    if (isBottom) {
      callback && callback();
    }
  }
}

export.default = onReachBottom;

组件内调用

import onReachBottom from 'reachbottom.js';

export default {
  data () {
    return {
      datalist: [],
      page: 0
    }
  },
  activated() {
    onReachBottom(this.getDataList);
  },
  methods: {
    getDataList() {
      this.$http.get(url).then(res => {
 // 拼接上去即可,template中遍历datalist,数据双向绑定
 this.datalist = this.datalist.concat(res.data.datalist);
 page ++; // 页数加一
      })  
    }
  }
}

查看全部

  • ... ...
查看全部
.chapter-list {
  position: relative;
  height: 50rem;
  overflow: hidden;
  transition: all 0.5s linear;
  &.show-all {
    height: auto;
  }
}

.more-mask {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 20rem;
  background: linear-gradient(
    bottom,
    #fff 0,
    rgba(255, 255, 255, 0) 100%
  );
}

数据一样,类型不一样

  • {{ item.text }}
  • methods: {
      changeType(type) { 
        let url = `/api/datalist?type=${type}`;
        this.$http.get(url).then(res => {
          this.datalist= res.data.datalist;  // 数据区遍历datalist即可
        })
      }
    }
    

    购物车的添加和删除

    此处删除的弹框没录下来

    抛开本地存储,mutations可以把set_shopCartInfo拆成add_shopCart、del_shopCart、clear_shopCart:

    
    export default {
      add_shopCart(state, shop) {
        state.shopCartInfo.push(shop);
      },
      del_shopCart(state, index) {
        // 拿到需要删除得商品索引
        state.shopCartInfo.splice(index, 1);
      },
      clear_shopCart(state) {
        state.shopCartInfo = [];
      },
    }
    

    推荐
    像我上面的都是vuex + localStorage结合,其实早就有一个vuex状态持久性方案,原理也是一样vuex-persistedstate

    欢迎所有前端爱好者关注我的个人微信公众号,我会经常分享最新,实用性高的前端文章以及技巧,祝你在前端开发的道路上刀过竹解!

    转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/240795.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号