vue项目技术小记

233 阅读5分钟

最近做的项目快要结尾了,本项目用前后端分离的,然后前端是用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