接上文
(十四)封装mock使用虚拟数据
14.1 引入mockjs
yarn add mockjs
14.2新建文件夹
在目录中新建一个mock文件夹
在json文件中 写入自己想要模拟实现的数据
mockServe中的内容为
// 先引入mockjs模块 import Mock from 'mockjs' // 引入.json数据 json数据可以不用对外暴漏但是可以直接引入 // 原因 webpack默认对外暴漏图片和JSON数据 import banner from './banner.json' import floor from './floor.json' // mock数据: 第一个参数请求地址 第二个参数是请求数据{data{code:200 //代表请求成功}} Mock.mock('/mock/banner',{code:200,data:banner}) Mock.mock('/mock/floor',{code:200,data:floor}) // 之后在入口文件引入使执行
之后就是在api文件夹中 新建一个mock的axios 请求
// 对axios二次封装 import axios from 'axios' // 引入进度条 import nprogress from 'nprogress' // 引入进度条样式 import "nprogress/nprogress.css" const mockrequests = axios.create({ // 配置对象 // 基础路径,发送请求的时候,路径当众会出现api baseURL:'/mock', timeout:5000 }) // 添加请求拦截器 mockrequests.interceptors.request.use(function (config) { // 在发送请求之前做些什么 //引入进度条 nprogress.start() return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); }); // 添加响应拦截器 mockrequests.interceptors.response.use(function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 // 进度条结束 nprogress.done() return response.data; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 return Promise.reject(error); }); //导出 export default mockrequests
之后就可以像一个后台发送来的接口一样 可以正常使用了
(十五)swiper的使用
想要使用swiper需要完成以下四部
(1)安装swiper
(2)在需要使用轮播图的组件内导入swpier和它的css样式
(3)在组件中创建swiper需要的dom标签(html代码,参考官网代码)
(4)创建swiper实例
注意:在创建swiper对象时,我们会传递一个参数用于获取展示轮播图的DOM元素,官网直接通过class(而且这个class不能修改,是swiper的css文件自带的)获取。但是这样有缺点:当页面中有多个轮播图时,因为它们使用了相同的class修饰的DOM,就会出现所有的swiper使用同样的数据,这肯定不是我们希望看到的。
解决方法:在轮播图最外层DOM中添加ref属性
通过ref属性值获取DOM let mySwiper = new Swiper(this.$refs.cur,{...})
<!--banner轮播--> <div class="swiper-container" id="mySwiper" ref="cur"> <div class="swiper-wrapper"> <div class="swiper-slide" v-for="(carouse,index) in bannerList" :key="carouse.id"> <img :src="carouse.imgUrl" /> </div> </div> <!-- 如果需要分页器 --> <div class="swiper-pagination"></div> <!-- 如果需要导航按钮 --> <div class="swiper-button-prev" ></div> <div class="swiper-button-next"></div> </div> <script> //引入Swiper import Swiper from 'swiper' //引入Swiper样式 import 'swiper/css/swiper.css' </script>
接下来要考虑的是什么时候去加载这个swiper,我们第一时间想到的是在mounted中创建这个实例。
但是会出现无法加载轮播图片的问题。
原因:
我们在mounted中先去异步请求了轮播图数据,然后又创建的swiper实例。由于请求数据是异步的,所以浏览器不会等待该请求执行完再去创建swiper,而是先创建了swiper实例,但是此时我们的轮播图数据还没有获得,就导致了轮播图展示失败。
mounted() { //请求数据 this.$store.dispatch("getBannerList") //创建swiper实例 let mySwiper = new Swiper(document.getElementsByClassName("swiper-container"),{ pagination:{ el: '.swiper-pagination', clickable: true, }, // 如果需要前进后退按钮 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, // 如果需要滚动条 scrollbar: { el: '.swiper-scrollbar', }, }) },
解决方法一:等我们的数据请求完毕后再创建swiper实例。只需要加一个1000ms时间延迟再创建swiper实例.。将上面代码改为:
mounted() { this.$store.dispatch("getBannerList") setTimeout(()=>{ let mySwiper = new Swiper(document.getElementsByClassName("swiper-container"),{ pagination:{ el: '.swiper-pagination', clickable: true, }, // 如果需要前进后退按钮 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, // 如果需要滚动条 scrollbar: { el: '.swiper-scrollbar', }, }) },1000) },
方法一肯定不是最好的,但是我们开发的第一要义就是实现功能,之后再完善。
解决方法二:我们可以使用watch监听bannerList轮播图列表属性,因为bannerList初始值为空,当它有数据时,我们就可以创建swiper对象
watch:{ bannerList(newValue,oldValue){ let mySwiper = new Swiper(this.$refs.cur,{ pagination:{ el: '.swiper-pagination', clickable: true, }, // 如果需要前进后退按钮 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, // 如果需要滚动条 scrollbar: { el: '.swiper-scrollbar', }, }) } }
即使这样也还是无法实现轮播图,原因是,我们轮播图的html中有v-for的循环,我们是通过v-for遍历bannerList中的图片数据,然后展示。我们的watch只能保证在bannerList变化时创建swiper对象,但是并不能保证此时v-for已经执行完了。假如watch先监听到bannerList数据变化,执行回调函数创建了swiper对象,之后v-for才执行,这样也是无法渲染轮播图图片(因为swiper对象生效的前提是html即dom结构已经渲染好了)。
完美解决方案:使用watch+this.$nextTick()
官方介绍:this. $nextTick它会将回调延迟到下次 DOM 更新循环之后执行(循环就是这里的v-for)。
个人理解:无非是等我们页面中的结构都有了再去执行回调函数
完整代码
<template> <!--列表--> <div class="list-container"> <div class="sortList clearfix"> <div class="center"> <!--banner轮播--> <div class="swiper-container" id="mySwiper"> <div class="swiper-wrapper"> <div class="swiper-slide" v-for="(carouse,index) in bannerList" :key="carouse.id"> <img :src="carouse.imgUrl" /> </div> </div> <!-- 如果需要分页器 --> <div class="swiper-pagination"></div> <!-- 如果需要导航按钮 --> <div class="swiper-button-prev" ></div> <div class="swiper-button-next"></div> </div> </div> </div> </div> </div> </template> <script> //引入Swiper import Swiper from 'swiper' //引入Swiper样式 import 'swiper/css/swiper.css' import {mapState} from "vuex"; export default { name: "index", //主键挂载完毕,ajax请求轮播图图片 mounted() { this.$store.dispatch("getBannerList") }, computed:{ ...mapState({ //从仓库中获取轮播图数据 bannerList: (state) => {return state.home.bannerList} }) }, watch:{ bannerList(newValue,oldValue){ //this.$nextTick()使用 this.$nextTick(()=>{ let mySwiper = new Swiper(document.getElementsByClassName("swiper-container"),{ pagination:{ el: '.swiper-pagination', clickable: true, }, // 如果需要前进后退按钮 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, // 如果需要滚动条 scrollbar: { el: '.swiper-scrollbar', }, }) }) } } } </script>
注意:之前我们在学习watch时,一般都是监听的定义在data中的属性,但是我们这里是监听的computed中的属性,这样也是完全可以的,并且如果你的业务数据也是从store中通过computed动态获取的,也需要watch监听数据变化执行相应回调函数,完全可以模仿上面的写法。
转载自:https://blog.csdn.net/weixin_43424325/article/details/121684101