前言
我从接触 Vue
框架,到开发实战,再到深入学习源码思想,至今已有4年的时间。今天主要从实际开发出发,通过“编码风格、性能、安全”3个方面来聊聊 Vue
的最佳实践!
参考官网:cn.vuejs.org/v2/style-gu…
编码风格
平时开发编码时,我们需要多注意提升代码可读性。因为同一个项目可能有多个开发童鞋在维护,挖坑太多会被吐槽哦~
下面我根据官网再结合实战开发总结了几个好的编码风格:
- 命名组件时用多个单词,避免跟现有及未来的
HTML
元素相冲突 prop
属性定义应尽量详细,至少要指定类型
// 好例子
props: {
status: String
}
// 更好的做法!
props: {
status: {
type: String,
required: true,
validator: function (value) {
return [
'syncing',
'synced',
'version-conflict',
'error'
].indexOf(value) !== -1
}
}
}
复制代码
- 组件
data
必须是个函数,避免多个组件数据互相影响
// 好例子
export default {
data () {
return {
foo: 'bar'
}
}
}
复制代码
- 使用
v-for
务必加上key
,且避免和v-if
写在一起
// 好例子
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
复制代码
- 为组件样式设置作用域
- 使用
scoped
属性
<template>
<button class="button button-close">X</button>
</template>
<!-- 使用 `scoped` attribute -->
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>
复制代码
<template>
<button :class="[$style.button, $style.buttonClose]">X</button>
</template>
<!-- 使用 CSS Modules -->
<style module>
.button {
border: none;
border-radius: 2px;
}
.buttonClose {
background-color: red;
}
</style>
复制代码
在 JavaScript
还可以访问到类名:
<script>
export default {
created () {
// 获取button编译后的类名:
// _1mB1nfbAEqzAETAbkaBZDV_0
console.log(this.$style.button)
}
}
</script>
复制代码
- BEM 的策略:组件库推荐使用
<template>
<button class="c-Button c-Button--close">X</button>
</template>
<!-- 使用 BEM 约定(Block独立的页面、Element元素标签、Modifier修饰符:元素处于的一种状态 -->
<style>
.c-Button {
border: none;
border-radius: 2px;
}
.c-Button--close {
background-color: red;
}
</style>
复制代码
- 私有
property
名,使用$_
前缀,避免产生冲突
// 好例子
var myGreatMixin = {
// ...
methods: {
$_myGreatMixin_update: function () {
// ...
}
}
}
复制代码
更多好的编码风格指南,可参考官网
性能
当项目业务代码不断剧增时,项目运行开销变大,构建速度变慢,我们就需要考虑性能优化。从vue
编码的角度来看,我们可以从以下几个方面来着手优化:
1. 组件按需加载
路由懒加载(使用import)
当打包构建时,JavaScript
包变得非常大,影响页面加载,我们可以把不同路由对应的组件分割成不同的代码块,当路由被访问的时候才加载对应组件。使用 import
动态导入,配合 webpack
tree-shaking
摇树功能,没有用到的组件就不会打包到 chunk
,从而提升加载性能。
const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about')
复制代码
2. 提升首屏加载速度
webpack体积优化
如今商业化前端项目大多都是工程化应用,vue
/react
/angular
等框架编码,webpack
打包构建编译,页面首屏加载慢,主要原因是打包构建的 chunk
体积过大。要提升首屏加载速度,首先需要优化 webpack
打包后的体积,优化措施可参考之前整理的技术博文:
可改造成SSR,减少首屏加载时间
使用SSR
服务端渲染,将组件或是页面通过服务器生成html
字符串,再发送到浏览器,这样可以加快首屏加载渲染的速度,提前显示文档内容。
可参考:SSR-完全指南
3. 不需要更新的内容静态化
利用 vue
的 v-once
指令一次性插值的功能,可以将不需要更新的节点内容静态化,这样可以优化更新性能。
4. 尽量减少DOM层级嵌套
DOM
渲染需要的性能开销比较大,我们在开发过程中尽量简化 div
结构,可以减少不必要的 DOM
层级嵌套。对于组件来说,我们应该尽量减少不必要的组件抽象,不必要的组件抽象无疑会增加 DOM
层级嵌套。
5. 大数据量的渲染优化
长列表采用虚拟滚动加载
长列表的数量一般在几百条范围内不会出现意外的效果,浏览器本身足以支撑。可一旦数量级达到上千,页面渲染过程会出现明显的卡顿。数量突破上万甚至十几万时,网页可能直接崩溃了。
为了解决长列表造成的浏览器渲染压力,出现了相应的应对技术——虚拟滚动。
实现原理:
虚拟滚动的实现,实际上就是在首屏加载时,只加载可视区域的列表项,当滚动发生时,动态计算获取可视区域内的列表项,并将非可视区域的列表项删除。
不活动的组件,可用<keep-alive>
缓存
<keep-alive>
是 Vue 的内置组件,用它来包裹动态组件时,会缓存不活动的组件实例。和 <transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中。
// 基本使用
<keep-alive>
<component :is="view"></component>
</keep-alive>
复制代码
<keep-alive>
主要用于保留组件状态或是避免重新渲染。
安全
XSS防御
- 不使用不可信的模板直接渲染,可用变量动态拼接模板再渲染
<template>
<div>{{ msg }}</div>
</template>
复制代码
- 小心使用
v-html
,:url
,:style
等,避免html
、url
、样式
等发生xss
注入。对于后端返回的数据可进行转义解析,校验不配对的DOM
标签。 - 等等......
CSRF防御
- token验证
- 第一步:后端随机生成一个
token
值,把这个token
保存到session
状态中;同时后端把这个token
传给前端页面; - 第二步:前端页面提交请求时,把
token
加到请求入参或是头信息中,一起传给后端; - 最后一步:后端验证前端传来的
token
与session
中的是否一致,一致则合法,否则是非法请求。
- 第一步:后端随机生成一个
- referer验证
验证 referer
请求来源,这种方法成本最低,但是并不能保证100%有效,因为服务器并不是什么时候都能取到 referer
,而且低版本的浏览器存在伪造 referer
的风险。
- 验证码
强制用户必须与页面应用交互,成功验证验证码才能完成最终的请求。这种方式很好的遏制 csrf
,但用户体验比较差。
总结
上述主要从 “编码风格、性能、安全” 3个方面总结了一些vue
开发的实战经验,希望能对开发小伙伴有所帮助~~