1。前言最近要求用vue前后端分离开发微信公众号。经过不断摸索和踩坑,总结了以下vue项目开发中常见的问题及解决方法。如果你是vue老大,请无视小弟的拙见。列表传参数到详情页的问题。本地开发环境请求服务端接口的跨域问题。axios封装,API接口统一管理按需加载UI库如何优雅的只覆盖当前页面UI库中组件的样式Timer问题导入rem文件Vue-Awesome-Swiper基本可以解决所有你的carousel需要在打包后生成一个大的.map文件。fastClick的300ms延迟解决方案组件中写options的顺序2.列表进入详情页传递参数。页面,需要传递一个productid;进入详情页c的路径页面是http://localhost:8080/#/detail?id=1,可以看到传递了一个参数id=1,即使页面刷新,id依然存在。此时在c页面,可以通过id获取到对应的详细数据。获取id的方式是this.$route.query.idvue。vue参数传递方式包括:query、params+动态路由参数传递。下面说说两者的区别:query通过path切换路由,params通过name切换路由//query通过path切换路由进入详情页//params按名称切换路由进入详情页query通过this.$route.query接收参数,params通过this.$route.params接收参数。//query通过this.$route.querycreated(){constid=this.$route.query.id;}//params通过this.$route.paramscreated(){constid=this.$route接收参数.params.id;}查询参数传递的url显示方式:/detail?id=1&user=123&identity=1&更多参数params+动态路由url方式:/detail/123params动态路由参数必须在路由定义参数中,然后路由跳转的时候一定要加参数,否则就是空白页面{path:'/detail/:id',name:'Detail',component:Detail},注意params传参的时候,如果没有参数定义在路由中,可以同时传递和接收,但是一旦刷新页面,该参数将不复存在。这对于某些操作需要依赖参数的行为是不可行的,因为你永远不能要求用户不要刷新页面。例如://在定义的路由中,只定义了一个id参数{path:'detail/:id',name:'Detail',components:Detail}//模板中的路由参数,//一个id参数是passed和一个token参数//id是route中已经定义的参数,但是没有定义token进入详情页//在详情页接收created(){//可以正常获取以下内容//但是页面刷新后,id还是可以的获取到,此时token不存在constid=this.$route.params.id;consttoken=this.$route.params.token;}3.本地开发环境请求服务端接口跨域。上面的错误大家都很熟悉了。该错误表示没有访问权限(跨域问题)。本地开发项目请求服务端接口时,由于客户端的同源策略,导致跨域问题。我们先来演示一个没有配置允许本地跨域的情况:可以看到,当我们点击获取数据的时候,浏览器提示我们跨域。所以我们无法访问数据。然后我们来演示设置跨域权限后的数据获取:我们在1中设置了本地跨域权限,2中访问接口时要注意/api,这里的/api指的是我们要请求的接口的域名。如果我们不想每个接口都带上/api,我们可以改变axios的默认配置axios.defaults.baseURL='/api';这样我们就可以直接请求接口this.$axios.get('app.php?m=App&c=Index&a=index'),非常简单。此时,如果在网络中查看xhr请求,会发现显示的是localhost:8080/api的请求地址。没什么大惊小怪的,它只是一个代理:好了,最后附上proxyTable的代码:proxyTable:{//以'/api'开头,将所有请求代理到目标服务器'/api':{target:'http://jsonplaceholder.typicode.com',//接口域名changeOrigin:true,//是否开启跨域pathRewrite:{//'^/api':''}}}注意:配置完成后一定要关闭原始服务器并重新启动npmrundev启动项目。否则无效。axios的封装主要是用来帮助我们拦截请求和响应的。在请求拦截中,我们可以携带userToken、post请求头、post提交数据的qs序列化等。在response的拦截中,我们可以根据状态码等进行统一的错误处理。axios接口的统一管理是做项目时必经的过程。这样方便我们管理自己的接口,不用在接口更新的时候再回到自己的业务代码去修改接口。4、UI库的按需加载为什么要用按需加载的方式而不是一次性全部导入,原因就不多说了。这里以vant的按需加载为例,演示vue中的ui库是如何按需加载的:安装:cnpmivant-S安装babel-plugin-import插件,使其按需加载:cnpmibabel-plugin-import-D在.babelrc文件中添加插件配置:libraryDirectory{"plugins":[//这里是原代码部分//…………//这里是我们要配置的代码["import",{"libraryName":"vant","libraryDirectory":"es","style":true}]]}根据需要在main.js中加载你需要的插件://引入vant组件为需要从'vant'导入{DatetimePicker,Button,List};使用组件://使用vant组件Vue.use(DatetimePicker).use(Button).use(List);最后在页面中使用:buttonps:出自vant库,像antiUi、elementUi等,很多ui库都支持按需加载,你可以去看文档,上面会提到。基本上,它通过安装babel-plugin-import插件来支持按需加载。使用方法和vant完全一样,直接用就行了。5、如何在当前页面优雅的覆盖ui库中组件的样式。首先我们vue文件的样式都是写在标签中,加上scoped让样式只在当前页面有效。那么问题来了,看图:我们正常写的所有样式都会加上[data-v-23d425f8]属性(如图1),但是第三方组件里面的标签是没有编译的[data-v-23d425f8]这个属性。所以,我们要想修改组件的样式,也是没有办法的。怎么办,有的小伙伴给第三方组件写一个class,然后在公共css文件或者当前页面写一个不带socped属性的style标签,然后直接修改第三方组件的样式在里面。这是一种方法,但是存在全局污染和命名冲突的问题。通过约定特定的命名方法,可以避免命名冲突。但还是不够优雅。作为一个杰出的、有强迫症的前病患者,怎么可能允许这种情况发生?好吧,让我们谈谈优雅的解决方案:通过深度选择器。比如要修改上图中组件中van-ellipsis类的样式,可以这样做:.van-tabs/deep/.van-ellipsis{color:blue};编译结果是:这不会给van-ellipsis也添加了[data-v-23d425f8]属性。至此,你就可以愉快的修改第三方组件的样式了。当然这里的深度选择器/deep/是因为我用的语言比较少。如果不用less/sass等,可以用>>>符号。更多关于深度选择器的内容将在本文后面介绍。6.定时器问题我在a页面写了一个定时器,让他每秒打印一个1,然后跳转到b页面,可以看到定时器还在运行。这是非常耗费性能的。如下图所示:解决方案1??首先我在数据函数中定义定时器名称:data(){return{timer:null//定时器名称}},然后这样使用定时器:this.timer=(()=>{//someoperation},1000)最后清除beforeDestroy()生命周期中的定时器:beforeDestroy(){clearInterval(this.timer);this.timer=null;}有两个不好的地方方案一地方,引用友达的话:timer方案二这种方法是在定时器定义后,通过$once事件监听器的位置来清除定时器。以下是完整代码:consttimer=setInterval(()=>{//sometimeroperation},500);//定时器被$once监听,可以清除beforeDestroy钩子。this.$once('hook:beforeDestroy',()=>{clearInterval(timer);})方案二感谢@zzx18023评论区提供的解决方案。类似于其他需要在当前页面使用,离开后需要销毁的组件(比如一些第三方库的picker组件等),可以使用该方法解决运行在离开后的背景。一般来说,我们推荐使用方案2,这样可以让代码更易读,一目了然。如果不知道once,on,$off的用法,这里是官网的地址教程,在programmaticeventlistener中:https://cn.vuejs.org/v2/guide/components-edge-案例。html#%E7%A8%8B%E5%BA%8F%E5%8C%96%E7%9A%84%E4%BA%8B%E4%BB%B6%E4%BE%A6%E5%90%AC%E5%99%A8。7、导入.rem文件的问题当我们在移动端工作时,适配是一个必须要处理的问题。比如我们适配的方案是写一个rem.js。原理很简单,就是根据网页的大小来计算html的font-size。基本上大家都知道,这里直接附上代码,就不做介绍了。(function(c,d){vare=document.documentElement||document.body,a="orientationchange"inwindow?"orientationchange":"resize",b=function(){varf=e.clientWidth;e.style.fontSize=f>=750?"100px":100*(f/750)+"px";};b();c.addEventListener(a,b,false);})(窗口);引入的问题很简单。在main.js中,直接导入'./config/rem'即可。导入路径根据你的文件路径填写。8.Vue-Awesome-Swiper基本可以解决你所有的轮播需求。我们使用的很多ui库(vant、antiUi、elementUi等)都有轮播组件,对于普通的轮播效果来说已经足够了。但是,有的时候,我们的轮播效果可能会比较炫,这时候ui库中的轮播就不一定能如愿以偿了。当然,如果技术和时间没问题,你可以自己造一个更炫的轮子。这里我就说说轮播组件vue-awesome-swiper,它确实很强大,基本可以满足我们的轮播需求。相信很多人都用过swiper,很好用,也很方便我们二次开发自定义自己需要的轮播效果。vue-awesome-swiper组件本质上是基于swiper,或者说是一个可以在vue中运行的swiper。下面是使用方法:cnpminstallvue-awesome-swiper--save//引入组件import'swiper/dist/css/swiper.css'import{swiper,swiperSlide}from'vue-awesome-swiper'//在组件中注册组件components:{swiper,swiperSlide}//模板中使用的轮播//ref为当前轮播//callback为回调//更多参数用法参考文档1