這篇文章將我學習Vue期間掌握的好幾個提高開發效率和效能的小技巧分享給大家,希望對大家有幫助!
$attrs
和$listeners
# #$attrs用於記錄從父組件傳入子組件的所有不被
props捕獲以及不是
class與
style的參數,而
$listeners用於記錄從父元件傳入的所有不含
.native修飾器的事件。 (學習影片分享:
vuejs影片教學)
Vue.component('child', { props: ['title'], template: '<h3>{{ title }}</h3>' }) new Vue({ data:{a:1,title:'title'}, methods:{ handleClick(){ // ... }, handleChange(){ // ... } }, template:' <child class="child-width" :a="a" b="1" :title="title" @click.native="handleClick" @change="handleChange">', })
在中
的值為
{a:1,b:"1"}
的值為
{change: handleChange}
$attrs和
$listeners作元件通信,在二次封裝元件中使用時比較高效,如:
Vue.component("custom-dialog", { // 通过v-bind="$attrs"和v-on="$listeners"把父组件传入的参数和事件都注入到el-dialog实例上 template: '<el-dialog v-bind="$attrs" v-on="$listeners"></el-dialog>', }); new Vue({ data: { visible: false }, // 这样子就可以像在el-dialog一样用visible控制custom-dialog的显示和消失 template: '<custom-dialog :visible.sync="visible">', });
Vue.component("custom-select", { template: `<el-select v-bind="$attrs" v-on="$listeners"> <el-option value="选项1" label="黄金糕"/> <el-option value="选项2" label="双皮奶"/> </el-select>`, }); new Vue({ data: { value: "" }, // v-model在这里其实是v-bind:value和v-on:change的组合, // 在custom-select里,通过v-bind="$attrs" v-on="$listeners"的注入, // 把父组件上的value值双向绑定到custom-select组件里的el-select上,相当于<el-select v-model="value"> // 与此同时,在custom-select注入的size变量也会通过v-bind="$attrs"注入到el-select上,从而控制el-select的大小 template: '<custom-select v-model="value" size="small">', });
$porps
用於記錄從父組件傳入子組件的所有被
props捕獲以及不是
class
Vue.component('child', { props: ['title'], template: '<h3>{{ title }}</h3>' }) new Vue({ data:{a:1,title:'title'}, methods:{ handleClick(){ // ... }, handleChange(){ // ... } }, template:' <child class="child-width" :a="a" b="1" :title="title">', })
在中,
$props的值為
{title:'title'}。
$props
props
都相同的情況,如:Vue.component('grand-child', { props: ['a','b'], template: '<h3>{{ a + b}}</h3>' }) // child和grand-child都需要用到来自父组件的a与b的值时, // 在child中可以通过v-bind="$props"迅速把a与b注入到grand-child里 Vue.component('child', { props: ['a','b'], template: ` <div> {{a}}加{{b}}的和是: <grand-child v-bind="$props"/> </div> ` }) new Vue({ template:' <child class="child-width" :a="1" :b="2">', })
函數式元件比起於一般的
vue元件而言,最大的差異是非響應式的。它不會監聽任何數據,也沒有實例(因此沒有狀態,意味著不存在諸如
created
mounted的生命週期)。好處是因只是函數,故渲染開銷也低很多。
<script> export default { name: "anchor-header", functional: true, // 以functional:true声明该组件为函数式组件 props: { level: Number, name: String, content: String, }, // 对于函数式组件,render函数会额外传入一个context参数用来表示上下文,即替代this。函数式组件没有实例,故不存在this render: function (createElement, context) { const anchor = { props: { content: String, name: String, }, template: '<a :id="name" :href="`#${name}`"> {{content}}</a>', }; const anchorEl = createElement(anchor, { props: { content: context.props.content, //通过context.props调用props传入的变量 name: context.props.name, }, }); const el = createElement(`h${context.props.level}`, [anchorEl]); return el; }, }; </script>
##其實我們在生產環境下也可以呼叫vue-devtools
去進行調試,只要更改Vue.config.devtools
配置既可,如下所示:
// 务必在加载 Vue 之后,立即同步设置以下内容 // 该配置项在开发版本默认为 `true`,生产版本默认为 `false` Vue.config.devtools = true;
我們可以透過偵測cookie
裡的使用者角色資訊去決定是否開啟該配置項,從而提高線上bug 查找的便利性。
<script> import { debounce } from "lodash"; export default { methods: { search: debounce(async function (keyword) { // ... 请求逻辑 }, 500), }, }; </script>
上面的search
函數賦值為debounce返回的結果,也就是具有防手震功能的請求函數。這種方式可以避免我們在元件裡要自己寫一遍防手震邏輯。
這裡有個例子sandbox,大家可以點進去看看經過高階函數處理的
method
method的效果區別,如下所示:除此之外,method
還可以定義為
,如果我們有函數需要執行時很強調順序,而且需要在
data裡定義變數來記錄上一次的狀態,則可以考慮使用生成器。
例如有個很常見的場景:微信的視訊通話在接通的時候會顯示計時器來記錄通話時間需要每秒更新一次,即取得,這個
通話時間
通話時間的函數需要每秒執行一次,如果寫成普通函數則需要在data裡存放記錄時間的變數。但如果用生成器則能很巧妙地解決,如下所示:
<template> <div id="app"> <h3>{{ timeFormat }}</h3> </div> </template> <script> export default { name: "App", data() { return { // 用于显示时间的变量,是一个HH:MM:SS时间格式的字符串 timeFormat: "", }; }, methods: { genTime: function* () { // 声明存储时、分、秒的变量 let hour = 0; let minute = 0; let second = 0; while (true) { // 递增秒 second += 1; // 如果秒到60了,则分加1,秒清零 if (second === 60) { second = 0; minute += 1; } // 如果分到60了,则时加1,分清零 if (minute === 60) { minute = 0; hour += 1; } // 最后返回最新的时间字符串 yield `${hour}:${minute}:${second}`; } }, }, created() { // 通过生成器生成迭代器 const gen = this.genTime(); // 设置计时器定时从迭代器获取最新的时间字符串 const timer = setInterval(() => { this.timeFormat = gen.next().value; }, 1000); // 在组件销毁的时候清空定时器和迭代器以免发生内存泄漏 this.$once("hook:beforeDestroy", () => { clearInterval(timer); gen = null; }); }, }; </script>
程式碼位址: https://codesandbox.io/s/jovial-williams-nkouf?file=/src/App.vue
但要注意的是:method 不能是箭頭函數
plus: () => this.a )。理由是箭頭函數綁定了父級作用域的上下文,所以
this 將不會按照期望指向 Vue 實例,
this.a
<script> export default { data() { return { value: "", }; }, methods: { fn1() {}, fn2() {}, }, watch: { value: { handler() { fn1(); fn2(); }, immediate: true, deep: true, }, }, }; </script>
虽然fn1
和fn2
都需要在value
变动的时候调用,但两者的调用时机可能不同。fn1
可能仅需要在deep
为false
的配置下调用既可。因此,Vue
在watch
的值添加了Array
类型来针对上面所说的情况,如果用watch
为Array
的写法处理可以写成下面这种形式:
<script> watch:{ 'value':[ { handler:function(){ fn1() }, immediate:true }, { handler:function(){ fn2() }, immediate:true, deep:true } ] } </script>
$options
$options
是一个记录当前Vue
组件的初始化属性选项。通常开发中,我们想把data
里的某个值重置为初始化时候的值,可以像下面这么写:
this.value = this.$options.data().value;
这样子就可以在初始值由于需求需要更改时,只在data
中更改即可。
这里再举一个场景:一个el-dialog
中有一个el-form
,我们要求每次打开el-dialog
时都要重置el-form
里的数据,则可以这么写:
<template> <div> <el-button @click="visible=!visible">打开弹窗</el-button> <el-dialog @open="initForm" title="个人资料" :visible.sync="visible"> <el-form> <el-form-item label="名称"> <el-input v-model="form.name"/> </el-form-item> <el-form-item label="性别"> <el-radio-group v-model="form.gender"> <el-radio label="male">男</el-radio> <el-radio label="female">女</el-radio> </el-radio-group> </el-form-item> </el-form> </el-dialog> </div> </template> <script> export default { name: "App", data(){ return { visible: false, form: { gender: 'male', name: 'wayne' } } }, methods:{ initForm(){ this.form = this.$options.data().form } } }; </script>
每次el-dialog
打开之前都会调用其@open
中的方法initForm
,从而重置form
值到初始值。如下效果所示:
以上代码放在sanbox里
如果要重置data
里的所有值,可以像下面这么写:
Object.assign(this.$data, this.$options.data()); // 注意千万不要写成下面的样子,这样子就更改this.$data的指向。使得其指向另外的与组件脱离的状态 this.$data = this.$options.data();
v-pre
用于跳过被标记的元素以及其子元素的编译过程,如果一个元素自身及其自元素非常打,而又不带任何与Vue
相关的响应式逻辑,那么可以用v-pre
标记。标记后效果如下:
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
对于部分在首次渲染后就不会再有响应式变化的元素,可以用v-once
属性去标记,如下:
<el-select> <el-option v-for="item in options" v-once :key="item.value" :label="item.label" :value="item.value" >{{i}}</el-option > </el-select>
如果上述例子中的变量options
很大且不会再有响应式变化,那么如例子中用上v-once
对性能有提升。
如果想监听子组件的生命周期时,可以像下面例子中这么做:
<template> <child @hook:mounted="removeLoading" /> </template>
这样的写法可以用于处理加载第三方的初始化过程稍漫长的子组件时,我们可以加loading
动画,等到子组件加载完毕,到了mounted
生命周期时,把loading
动画移除。
初次之外hook
还有一个常用的写法,在一个需要轮询更新数据的组件上,我们通常在created
里开启定时器,然后在beforeDestroy
上清除定时器。而通过hook
,开启和销毁定时器的逻辑我们都可以在created
里实现:
<script> export default { created() { const timer = setInterval(() => { // 更新逻辑 }, 1000); // 通过$once和hook监听实例自身的beforeDestroy,触发该生命周期时清除定时器 this.$once("hook:beforeDestroy", () => { clearInterval(timer); }); }, }; </script>
像上面这种写法就保证了逻辑的统一,遵循了单一职责原则。
以上是9個提高開發效率和效能的Vue小技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!