v-if :是 真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
v-show : 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 display 属性进行切换。
所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值(当我们需要进行数值计算,并且依赖于其他数据,可以使用computed,可以利用它的缓存机制,避免每次获取值的时候,都需要重新计算)
watch:多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作(当我们需要监听数据变化来执行异步操作或者较大的操作,使用watch允许我们进行异步操作,限制我们执行操作的频率在得到最终结果前,设置中间状态)
在列表数据进行遍历渲染时,需要为每一项 item 设置唯一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值对比,较快地定位到 diff
为什么要避免使用index作为key的值
因为:vue是操作虚拟DOM。我们是通过数据来操控页面元素,假如我们使用index作为key,那么当我们的数据变化时,从index开始之后的所有数据都将重新渲染一次,反之我们只需要渲染我们修改处的地方
v-for 遍历避免同时使用 v-if
v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候,必要情况下应该替换成 computed 属性或者js提前处理好数据
Vue 组件销毁时,会自动清理它与其它实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。如果在 js 内
created() {
addEventListener(‘click’, this.click, false)
},
beforeDestroy() {
removeEventListener(‘click’, this.click, false)
}
对于图片多的页面,为了加快加载速度,很多时候我们最好将未出现在可视区域的图片暂时不做加载,当用户翻到某个位置时,再对该位置图片进行加载,这样加载性能有很大的提高,用户体验也会改善很多。项目中我们可以用vue-lazyload插件来帮助我们实现图片的懒加载。
使用方法:
第一步:安装插件 npm install vue-lazyload --save-dev
第二步:在mainJs中引入Vue.use(VueLazyload)
第三步:有特殊情况可自定义
Vue.use(VueLazyload, {
preLoad: 1.3,
error: ‘dist/error.png’,
loading: ‘dist/loading.gif’,
attempt: 1
})
第四步:
在 vue 文件中将 img 标签的 src 属性直接改为 v-lazy ,从而将图片显示方式更改为懒加载显示:
Vue 是单页面应用,可能会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来
我们在项目中经常会需要引入第三方插件,如果我们直接引入整个插件,会导致项目的体积太大,我们可以借助 babel-plugin-component ,然后可以只引入需要的组件,以达到减小项目体积的目的。以下为项目中引入 element-ui 组件库为例:
客户端渲染:用户访问 url,请求 html 文件,前端根据路由动态渲染页面内容。关键链路较长,有一定的白屏时间;
服务端渲染:用户访问 url,服务端根据访问路径请求所需数据,拼接成 html 字符串,返回给前端。前端接收到 html 时已有部分内容;
预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容
针对单页应用,服务端渲染和预渲染共同解决的问题:
SEO:单页应用的网站内容是根据当前路径动态渲染的,html 文件中往往没有内容,网络爬虫不会等到页面脚本执行完再抓取;
弱网环境:当用户在一个弱环境中访问你的站点时,你会想要尽可能快的将内容呈现给他们。甚至是在 js 脚本被加载和解析前;
低版本浏览器:用户的浏览器可能不支持你使用的 js 特性,预渲染或服务端渲染能够让用户至少能够看到首屏的内容,而不是一个空白的网页。
第一步:prerender-spa-plugin插件安装npm install prerender-spa-plugin --save
第二步:vue.config.js中增加
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV !== 'production') return;
return {
plugins: [
new PrerenderSPAPlugin({
// 生成文件的路径,也可以与webpakc打包的一致。
// 下面这句话非常重要!!!
// 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
staticDir: path.join(__dirname,'dist'),
// 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
routes: ['/', '/product','/about'],
// 这个很重要,如果没有配置这段,也不会进行预编译
renderer: new Renderer({
inject: {
foo: 'bar'
},
headless: false,
// 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
renderAfterDocumentEvent: 'render-event'
})
}),
],
};
}
}
第三步:在main.js中增加
new Vue({
router,
store,
render: h => h(App),
mounted () {
document.dispatchEvent(new Event('render-event'))
}
}).$mount('#app')
router.js 中设置mode: “history”
第四步:验证
当我们项目图片过多,并存在一些较大图片时,会出现加载慢等问题,可以使用image-webpack-loader。它能帮助我们对图片进行压缩优化,大大减少图片大小。加快加载时间,优化用户体验。
第一步:安装插件(npm install image-webpack-loader --save-dev)
第二步:在vue.config.js中配置
Babel 插件会在将 ES6 代码转换成 ES5 代码时会注入一些辅助函数
在默认情况下, Babel 会在每个输出文件中内嵌这些依赖的辅助函数代码,如果多个源代码文件都依赖这些辅助函数,那么这些辅助函数的代码将会出现很多次,造成代码冗余。为了不让这些辅助函数的代码重复出现,可以在依赖它们时通过 require(‘babel-runtime/helpers/createClass’) 的方式导入,这样就能做到只让它们出现一次。babel-plugin-transform-runtime 插件就是用来实现这个作用的,将相关辅助函数进行替换成导入语句,从而减小 babel 编译出来的代码的文件大小。
第一步:安装 babel-plugin-transform-runtime :npm install babel-plugin-transform-runtime --save-dev
第二步:在 .babelrc配置
“plugins”: [
“transform-runtime”
]
如果项目中没有去将每个页面的第三方库和公共模块提取出来,则项目会存在以下问题:
相同的资源被重复加载,浪费用户的流量和服务器的成本。
每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验。
解决方法:
需要将多个页面的公共代码抽离成单独的文件,来优化以上问题 。Webpack 内置了专门用于提取多个Chunk 中的公共部分的插件 CommonsChunkPlugin
第一步:(分离出第三方库,自定义公共模块,webpack运行文件,并且将webpack运行文件独立出来)
vue.config.js中webpack配置处新增一入口文件vendor和commonsChunkPlugin插件进行公用模块提取
entry: {
first: ‘./src/first.js’,
second: ‘./src/second.js’,
vendor: Object.keys(packagejson.dependencies)//获取生产环境依赖的库
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: [‘vendor’,‘runtime’],
filename: ‘[name].js’
}),
]
Vebdor.js在未分离之前,包括:第三方库,自定义公用模块,webpack运行文件,后面我们将webpack运行文件单独独立出来了(runtime.js)
第二步:公用模块单独抽取
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: [‘vendor’,‘runtime’],
filename: ‘[name].js’,
minChunks: Infinity
}),
new webpack.optimize.CommonsChunkPlugin({
name: ‘common’,
filename: ‘[name].js’,
chunks: [‘first’,‘second’]//从first.js和second.js中抽取commons chunk
}),
]
可以看到公用模块conmmon.js也偶从vendor中提取出来,那么vendor就只剩 第三方库了。
为什么要将第三方库,webpack运行文件,公用模块单独分离呢?
因为每次打包webpack运行文件都会变,如果不分离出来,那vendor.js的哈希值就会变化,本来第三方库是没变的浏览器可以用原来缓存的,实际因为哈希值变化后都需要重新加载。也就是为什么会造成资源重复加载问题。
SourceMap:为了方便调试快速定位代码bug出处的功能,打包会多出一个。map文件,实际生产环境不需要 ,设置为false就好。
它将浏览器请求的文件先在服务器端进行压缩,然后传递给浏览器,浏览器解压之后再进行页面的解析工作。在服务端开启Gzip支持后,我们前端需要提供资源压缩包,通过Compression-Webpack-Plugin插件build提供压缩(nginx也需要做相应配置)