最近做的项目快要结尾了,本项目用前后端分离的,然后前端是用vue开发的,为什么选vue呢?一来公司要求效率要高些的,那就应该用到三大流行的框架之一,然后项目的内容不太复杂的,觉得用vue更合适的。二来正好应该要“炒熟”vue了哈。其中陷入了不少坑,一个一个爬过来的,总结下入坑的原因,另外会给出官方文档的对应内容,以便加深理解的。如有不足之处,请提出来哈~
异步加载组件
- 我们都知道vue一般都是单页面的,也就意味着一开始就要加载全部的组件,这太不友好的,加载时间会慢些。这时候我们就用到异步组件~
const Index=()=>import('@/page/Index'); const Home=()=>import('@/page/Home'); const router=new Router({ routes:[ { path:'/index', component:Index }, { path:'/home', component:Home } ] })
然后你会发现js被分开的,这就是所谓的异步加载~
页面后退时,保持之前的状态,不刷新
- 在app.vue文件中
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"/>
- 在router.js中
const router = new Router({ routes: [ { path: '/index', components:Index, meta:{ keepAlive:false } }, { path:'/goods', component:Goods, meta:{ keepAlive:true } }, }
用meta中的keepAlive来判断需不需要缓存,keep-alive就是保存缓存的组件。
在相同路由的情况下,再次点击导航栏上的本路由,再次刷新
在vue中,路由地址相同的情况下,是不会再次刷新的,即使点击本路由的导航文字上。一开始我没想到解决的方案,后来寻求大佬商量,大佬说可以用事件传递的。然后他告诉我一句话的,
vue.js一定不会阻碍传统方法实现的。
这话说得我惭愧,我意识到我太依赖vue.js的框架,没拓展思维的。再次感谢大佬的点拔~
- 对,是可以用事件传递来实现的。在主路由上绑定isFresh,判断需不需要刷新子路由,然后在子路由上绑定事件,传递到主路由的事件。主路由监听到事件的,就把isFresh变为false,以防下面还会需要到。不设置为false,下面的就不会刷新。看代码如下:
- App.vue
<router-view :isFresh="isFresh" @tempBtn="tempBtn"/> //data data(){ return { isFresh:false, } } //事件函数 tempbtn(){ this.isFresh=false; }
- Index.vue
watch:{ isFresh(){ //console.log('ShopisFresh:'+this.isFresh); if(this.isFresh){ Object.assign(this.$data,this.$options.data()); this.fetchData(); } } }, //然后加载完后,还要绑定事件,传递到主路由的tempbtn事件 this.$emit('tempbtn');
嗯,在子路由上监听到isFresh为true,表示要刷新的,Object.assign是利用data的初始化数据覆盖,然后重新加载数据。
checkbox整体点击
UI设计师要求能点击checkbox的整体,包括checkbox后面的文字,不是只能点击checkbox的框,这可把我为难了,然后艰难的爬出坑了。
<div class="group_item" @click="selfChecked = !selfChecked"> <input type="checkbox" v-bind:checked="selfChecked"> <label>点我呀</label> data(){ return { tempChecked:null } }, props:['checked'], watch:{ checked(){ this.tmpChecked=this.checked } }, computed: { selfChecked: { get: function(val){ return this.tmpChecked; }, set: function(newVal){ this.tmpChecked = newVal this.$emit('input', newVal) } } }, </div>
然后在父组件上用v-model即可。用selfChecked来判断是不是要点击,至于为什么要watch,是判断checked为真还是假,比如说在父组件上,提交后,表单要清空的,这时候要监听到checked为假的,然后传递到selfChecked的值。这样就能清空checkbox。
setInterval的问题
用了setInterval之后,切换路由的时候发现还在计时,不得了,真的会影响性能唉,就吓的赶紧啃官方文档,找到了~
beforeDestroy(){ clearInterval(this.interId); }
beforeDestroy是毁路由之前的函数,就是说毁路由之前就清除setInterval
- 参考vue的生命周期
在v-for循环中进行v-model数据绑定
<div v-for="(item,index) in list"> <textarea type="text" v-model="list[index]['content']"></textarea> </div>
下面说说和vue没关系的问题
上线时去掉console
我们一般都会用console来打印,以便检查的,万一console写多了,上线时总不能打印出console吧,要注释掉,但太费时间吧,这时候webpack神器上场(本人用webpack3)
- 在webpack.prod.config.js中
new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false, drop_debugger: true, drop_console: true } }, sourceMap: config.build.productionSourceMap, parallel: true }),
这prod是生产环境的,然后drop_console为true,是去掉console
兼容ie的问题
部署到生产环境后,测试ie11时发现空白屏的,我慌了,不是说可以兼容到ie9吗?还是说没配置好的,然后google查,ie还没支持js新的api,比如promise,所以需要babel-polyfill来转换的。真是蛋疼的ie,还能怎么办呢?当然是加babel-polyfill插件的。
npm install babel-polyfill --save //然后在webpack.base.config.js中引用这插件 module.exports=require('babel-polyfill'); module.export={ ... entry:{ app:['babel-polyfill','./src/main.js'] } }
打包第三方库
打包时把第三方库合并成vendor.js,但是这个vendor.js有hash,这就意味着每次打包时vendor.js的hash会变化的,然后在浏览器会重新加载。vendor.js的代码本来就很少被改变的,重新加载就影响加载时间的。从目前搜索的解决方案,比较好的方案有两种:
1、 第一种用dll来打包的,webpoack自带的- 首先在build里新建一个文件,命名为webpack-dll.config.js
const webpack=require('webpack') const path=require('path') module.export={ entry:{ vendors:['vue.js','axios','vue-router','vuex','vue/dist/vue.esm.js'] //加入要打包的第三方库 }, output:{ filename:'[name].dll.js', //输入的文件名 path:'path.join(__direname,'../static')', //输入的路径 library:'[name]' }, plugin:[ //为了和第三方库的dll.js对应,build时不会把这个打包进去,就是说能减少build构建的时间 new webpack.DllPlugin({ path:path.join(__direname,'../','[name]-mainfest.json'), //输入的mainfest文件的路径 name:'[name]' }) ] }
- 然后命令生成vendor-mainfest.json
//在package.json添加一行 "dll":"webpack --config build/webpack.dll.config.js"
然后npm run dll,就生成vendor-mainfest.json
- 然后还要在webpack.base.conf.js配置,改变构建的配置
//添加一行 const mainfest=require('../vendors-mainfest.json') // //在module.exports添加配置 module.exports={ ... plugins:[ new webpack.DllReferencePlugin({ mainfest }) ], ... }
然后把CommonsChunkPlugin的这块注释掉,不然要重复打包。
- 最后在index.html加上一行
<script src="./static/vendors.dll.js"></script>
2、 第二种方案就是用bootcdn