基础
computed 和 watch
computed 和 watch 的区别
- computed 有缓存,data 不变则不会重新计算
- watch 监听引用类型,拿不到 oldVal
watch 如何深度监听?
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default{
data(){
return {
message:"卡哇伊"
}
},
watch:{
message:{
// 开启深度监听
deep: true,
// 将立即以表达式的当前值触发回调
immediate: true,
// 回调方法
handler(newValue, oldValue) {
console.log("newValue=",newValue," oldValue=",oldValue);
},
}
}
}
</script>
高级特性
自定义 v-model
<!-- CustomModel.vue -->
<template>
<div>
<input type="text" :value="val" @input="$emit('change',$event.target.value))"
</div>
</template>
<script>
export default{
model:{
prop:val, // 对应 props val
event:"change"
}
props:{
val:{
type: String,
default: ""
}
}
}
</script>
<!-- Main.vue -->
<template>
<div>
<p>{{name}}</p>
<CustomModel v-model="name" />
</div>
</template>
<script>
export default{
data(){
return {
name: ""
}
}
}
</script>
$nextTick
Vue 是异步渲染
data改变之后,DOM不会立刻渲染
$nextTick 会在DOM渲染之后被触发,以获取最新得DOM节点
多次修改 data 只会渲染一次
<template>
<div>
<div>
<input type="text" v-model="value" @keydown.enter="handlePush" />
<button @click="handlePush">push</button>
</div>
<ul class="list-box" ref="listRef">
<li v-for="(item,index) in list" :key="item.id" @click="deleteItem(index)">{{item.content}}</li>
</ul>
</div>
</template>
<script>
export default {
name:"TodoList",
data() {
return {
value: '',
list: [],
};
},
methods: {
handlePush() {
if(this.value.trim()){
this.list.unshift({
id:Math.random().toString().replace(".",""),
content:this.value
});
this.value = '';
// 在这里测试 $nextTick
// 不调用的情况,不能获取真正的节点情况
console.log('不调用 $nextTick 的情况=>',this.$refs.listRef.childNodes.length);
this.$nextTick(()=>{
// 在数据驱动更新模板之后,并且模板appendChild到DOM上之后,才会回调到
console.log('调用 $nextTick 的情况=>',this.$refs.listRef.childNodes.length);
})
}
},
deleteItem(index){
this.list.splice(index,1)
}
},
};
</script>
slot
- 基本使用
<!-- Demo.vie -->
<template>
<div>
<h3>{{title}}</h3>
<slot>这个是默认的内容</slot>
</div>
</template>
<script>
export default{
name:"Demo",
props:{
title:{
type:String,
default:""
}
}
}
</script>
<!-- Main.vue -->
<template>
<Demo title="提示">
吃饭饭
</Demo1>
</template>
- 作用域插槽
<!-- Demo.vie -->
<template>
<div>
<h3>{{title}}</h3>
<slot :data="item">这个是默认的内容</slot>
</div>
</template>
<script>
export default{
name:"Demo",
props:{
title:{
type:String,
default:""
}
},
data(){
return {
item:{
name:"卡哇伊"
}
}
}
}
</script>
<!-- Main.vue -->
<template>
<Demo title="提示">
<template v-slot="slotProp">
<!-- 会渲染成 卡哇伊 -->
{{slotProp.data.name}}
</template>
</Demo1>
</template>
- 具名插槽
<!-- Demo.vie -->
<template>
<div>
<h3>{{title}}</h3>
<slot name="content" :data="item">这个是默认的内容</slot>
</div>
</template>
<script>
export default{
name:"Demo",
props:{
title:{
type:String,
default:""
}
},
data(){
return {
item:{
name:"卡哇伊"
}
}
}
}
</script>
<!-- Main.vue -->
<template>
<Demo title="提示">
<!-- 缩写 <template #:content="slotProp"> -->
<template v-slot:content="slotProp">
<!-- 会渲染成 卡哇伊 -->
{{slotProp.data.name}}
</template>
</Demo1>
</template>
动态组件
-
按需加载,异步加载大组件
-
基本使用
<!-- :is="componentName" 的用法 -->
<template>
<component :is="componentName" />
</template>
<script>
export default{
data(){
return {
componentName:"Demo"
}
},
components:{ Demo:()=>import('@/components/Demo') }
}
</script>
- 需要根据数据,动态渲染的场景。即组件类型不确定
异步组件
- import() 函数
<template>
<div>
<Demo v-if="show" />
<button @click="show=!show">显示组件</button>
</div>
</template>
<script>
export default{
data(){
return {
data: false
}
},
components:{
// 异步引用,什么时候需要,什么时候加载,推荐这种引用组件的方式
Demo:()=>import('@/components/Demo'),
}
}
</script>
keep-alive
- 缓存组件
- 频繁切换,不需要重复渲染
- Vue 常见性能优化
mixin
- 多个组件有相同的逻辑,抽离出来
- mixin 并不是完美的解决方案,会有一些问题
- 变量来源不明确,不利于阅读
- 多个 mixin 可能会造成命名冲突
- mixin 和组件可能出现多对多的关系,复杂度较高
- Vue3 提出的 Comosition API 旨在解决这些问题
相关面试技巧
- 可以不太深入,但必须知道
- 熟悉基本用法,了解使用场景
- 最好能和自己的项目经验结合起来