vue

虚拟DOM

生命周期

参考 1

常见问题及技巧

data必须是一个函数

因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

props 要比 data 先完成初始化,所以我们可以利用这一点给 data 初始化一些数据进去

export default {
    data () {
        return {
            buttonSize: this.size
        }
    },
    props: {
        size: String
    }
}
1
2
3
4
5
6
7
8
9
10

this.$set() 使用

a.数组的下标去修改数组的值,数据已经被修改了,但是不触发updated函数,视图不更新。

b.vue中检测不到对象属性的添加和删除

生命周期函数/methods/watch里面不应该使用箭头函数

箭头函数的this指向外层,即函数所在的所用域,普通函数的this指向函数的调用者

delete 与 Vue.delete ($delete)

  • 都用于数组和对象
  • delete 删除数组后,被删除的元素还占据原来的位置,变成empty或undefined,其他元素的简直不发生变化
  • Vue.delete 直接删除了数组 改变了数组的键值。

watch 的 immediate 属性

created() {
    this.fetchPostList()
},

watch: {
    searchInputValue() {
        this.fetchPostList()
    }
}
1
2
3
4
5
6
7
8
9

可直接写成这样:

watch: {
    searchInputValue: {
        handler: 'fetchPostList',
        immediate: true
    }
}
1
2
3
4
5
6

注销 watch

使用app.$watch()时,不用的时候须要注销掉,不然会引起内存泄露。该方法返回的就是一个注销方法,只要调用一下就可以了。

//注册watch
const unWatch = app.$watch('text', (newVal, oldVal) => {
  console.log(`${newVal} : ${oldVal}`);
});

// 手动注销watch
unWatch(); 
1
2
3
4
5
6
7

可以在同一个挂载点动态切换多个组件:

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! -->
</component>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

异步组件

不需要首屏加载的组件都使用异步组件的方式来加载(如多tab),包括需要触发条件的动作也使用异步组件(如弹窗) 使用方式为:v-if来控制显示时机,引入组件的Promise即可。

<template>
    <div>
        <HellowWorld v-if="showHello" />
    </div>
</template>
<script>
export default {
    components: { HellowWorld: () => import('../components/HelloWorld.vue') },
  
    data() {
        return {
            showHello: false
        }
    },

    methods: {
        initAsync() {
            addEventListener('scroll', (e) => {
                if (scrollY > 100) {
                    this.showHello = true
                }
            });
        }
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

深层组件通信 provide/inject

//父组件 parent.vu
<template>
    <div>
        <child></child>
    </div>
</template>
<script>
export default {
    name: 'parent',
    provide: {
        data: 'I am parent.vue'
    },
    components: {
        Child
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//子组件 child.vue
<template>
    <div>
        <grand-child></grand-child>
    </div>
</template>
<script>
export default {
    name: 'child',
    components: {
        GrandChild
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//孙组件 grandchild.vue
<script>
export default {
    name: 'grandchild',
    inject: ['data'],
    mounted() {
        // 控制台输出:
        // grandchild:inject: I am parent.vue
        console.log('grandchild:inject:',this.data);
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。

inject 选项应该是一个字符串数组或一个对象,该对象的 key 代表了本地绑定的名称,value 就为provide中要取值的key。

参考 1

slot-scope

父组件从子组件获取数据的方法,相当于函数中的回调 参考elementUI里的table

<el-table-column
    fixed="right"
    label="操作"
    width="100">
    <template slot-scope="scope">
        <el-button @click="handleClick(scope.row)" type="text">查看</el-button>
    </template>
</el-table-column>
1
2
3
4
5
6
7
8

参考 1

sync修饰符

父组件

<child :isShow.sync="isShow" v-show="isShow"/>
//是下面写法的语法糖
<child @update:isShow="e => isShow = e;" v-show="isShow"/>
1
2
3

子组件

<input type="button" value="点我隐身" @click="upIsShow">
<script>
    export default {
        methods:{
            upIsShow(){
                this.$emit("update:isShow",false);
            }
        }
    }
</script>
1
2
3
4
5
6
7
8
9
10

监听子组件(包括第三方子组件)的生命周期钩子

只需要这样:

<Child @hook:mounted="childMounted"/>
1
methods: {
    childMounted() {
        console.log("Child was mounted");
    }
  }
1
2
3
4
5

这里

用 Object.freeze 优化长列表性能

Vue中的错误、警告捕获

全局捕获:

//捕获错误
Vue.config.errorHandler = function(err, vm, info) {
    console.log(`Error: ${err.toString()}\nInfo: ${info}`);
}
//捕获浸膏
Vue.config.warnHandler = function(msg, vm, trace) {
    console.log(`Warn: ${msg}\nTrace: ${trace}`);
}
1
2
3
4
5
6
7
8

组件级捕获:

  • 生命周期钩子 errorCaptured
errorCaptured(err, vm, info) {
    console.log(`cat EC: ${err.toString()}\ninfo: ${info}`); 
    return false;
}
1
2
3
4
  • renderError 只在开发者环境下工作。
new Vue({
    render (h) {
        throw new Error('oops');
    },
    renderError (h, err) {
        return h('pre', { style: { color: 'red' }}, err.stack);
    }
}).$mount('#app');
1
2
3
4
5
6
7
8

参考 1 2 3 4 5 6 7

$on 或 $once 代替 beforeDestroy 或 destroyed 生命周期来销毁事件或定时器

before:

export default {
    mounted() {
        this.timer = setInterval(() => {
            console.log(Date.now())
        }, 1000)
    },
    beforeDestroy() {
        clearInterval(this.timer)
    }
}
1
2
3
4
5
6
7
8
9
10

after:

export default {
    mounted() {
        this.creatInterval('hello')
        this.creatInterval('world')
    },
    creatInterval(msg) {
        let timer = setInterval(() => {
            console.log(msg)
        }, 
        1000)
        this.$once('hook:beforeDestroy', function() {
            clearInterval(timer)
        })
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Vue 的父组件和子组件生命周期钩子执行顺序

  • 加载渲染过程: 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  • 子组件更新过程: 父beforeUpdate->子beforeUpdate->子updated->父updated
  • 父组件更新过程: 父beforeUpdate->父updated
  • 销毁过程: 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
最近更新: 6/28/2020, 9:50:04 PM