常考的vue高级特性(知识点简记)
1. 自定义v-model
<template>
<div>
<p>vue 高级特性</p>
<hr>
<!-- 自定义 v-model -->
<p>{{name}}</p>
<CustomVModel v-model="name"/>
<MixinDemo/>
</div>
</template>
<script>
export default {
components: {
CustomVModel
},
data() {
return {
name: 'name'
}
}
}
</script>
颜色选择器 双向数据绑定
customVModel.vue
<template>
<!-- 例如:vue 颜色选择 -->
<input type="text"
:value="text1"
@input="$emit('change1', $event.target.value)">
<!--
1. 上面的 input 使用了 :value 而不是 v-model
2. 上面的 change1 和 model.event1 要对应起来
3. text1 属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text1', // 对应 props text1
event: 'change1'
},
props: {
text1: String,
default() {
return ''
}
}
}
</script>
2. $nextTick
vue是异步渲染,
data改变之后,DOM不会立刻渲染,
$nextTick会在DOM渲染之后被触发,以获得最新的DOM节点
<template>
<div id="app">
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>
</ul>
<button @click="addItem">添加一项</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
list: ['a', 'b', 'c']
}
},
methods: {
addItem() {
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
// 1. 异步渲染,$nextTick 待 DOM 渲染完再回调
// 2. 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次(使用一次$nextTick)
this.$nextTick(() => {
// 获取 DOM 元素
const ulElem = this.$refs.ul1
// eslint-disable-next-line
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
(在DOM元素定义ref=”ul1”,之后可以使用this.$refs.ul1拿到DOM元素)
不使用$nextTick的效果: 点击一次输出3,点击第二次输出6
为了使点击之后可以立刻得到渲染结果:使用$nextTick
3. slot插槽
组件插槽的作用:父组件向子组件传递内容(模板的内容)
插槽的位置:位于子组件的模板中
(1) 基本使用
<template>
<div>
<p>vue 高级特性</p>
<!-- slot -->
<SlotDemo :url="website.url">
{{website.title}}
</SlotDemo>
</div>
</template>
<script>
import SlotDemo from './SlotDemo'
export default {
components: {
SlotDemo
},
data() {
return {
name: '姓名',
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序员的梦工厂'
}
}
}
}
</script>
SlotDemo.vue
<template>
<a :href="url">
<slot>
显示默认内容,即父组件没设置内容时
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
(效果:链接会以标签形式显示并且显示title内容)
(2)作用域插槽
<template>
<a :href="url">
<slot :slotData="website">
{{website.subTitle}} <!-- 父组件不传内容时默认值显示 subTitle -->
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {
website: {
url: 'http://wangEditor.com/',
title: 'wangEditor',
subTitle: '轻量级富文本编辑器'
}
}
}
}
</script>
(如果不传入值{{website.subTitle}}},则会显示子组件的默认subtitle)
使用:子组件中作用域的data让父组件可以获取到
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
效果:页面显示子组件内容wangEditor
(思路:在slot中定义动态属性slotData,然后把他定义到website上,website中含有title和subtitle。然后在index中使用ScopedSlotDemo中定义v-slot=”slotProps”.之后可以使用slot Props.slot DaTa拿到ScopedSlotDemo组件中website的内容,从而可以拿到website的title)
(3)具名插槽
有名字的插槽---根据内容进行匹配--没有名称会默认匹配
父组件往子组件传递内容的时候需要对应好名字
4. 动态组件异步组件
(1)动态组件
用法: :is=”component-name”
需要根据数据、动态渲染的场景。即组件类型并不确定。(一般情况下组件类型是确定的)
举例使用场景:新闻详情页。(组件位置不确定或者种类不确定。即不知道要渲染甚么样的组件,只知道数据。需要根据数据确定组件的类型,这时就需要用到动态组件)
<template>
<div>
<p>vue 高级特性</p>
<!-- 动态组件 -->
<!-- <component :is="NextTickName"/> -->
<div v-for="(index, value) in newsData" :key="index">
<component :is="value.type"></component>
</div>
</div>
</template>
<script>
export default {
data() {
return {
name: 'name',
// NextTickName: "NextTick",
newsData: {
1: {type: 'text'},
2: {type: 'text'},
3: {type: 'image'},
}
}
}
}
</script>
(根据获取到的组件(text,image)进行渲染)
(2)异步组件
Import函数
按需加载、异步加载大组件
(什么时候用就什么时候加载,如果不使用永远都不会加载,适合于组件比较大比较复杂,这样会优化性能)
使用语句import SlotDemo from './SlotDemo' 是同步加载
<!-- 异步组件 -->
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>
// 然后在components里面写
components: {
FormDemo: () => import('../BaseUse/FormDemo'),
}
效果:没有点击时不会加载FormDemo,点击之后会加载然后渲染出来
5.keep-alive
缓存组件
频繁切换,不需要重复渲染
Vue常见性能优化
KeepAlive.Vue中引入三个组件KeepAliveAtageA、KeepAliveAtageB、KeepAliveAtageC是三个按钮
依次点击BC的效果:
不使用keep alive |
使用keepalive |
A mounted A destroyed B mounted B destroyed C mounted C destroyed A mounted |
A created B created C created |
<KeepAliveStageA v-if="state === 'A'"/> <KeepAliveStageB v-if="state === 'B'"/> <KeepAliveStageC v-if="state === 'C'"/>
|
<keep-alive> <!-- tab 切换 --> <KeepAliveStageA v-if="state === 'A'"/> <KeepAliveStageB v-if="state === 'B'"/> <KeepAliveStageC v-if="state === 'C'"/> </keep-alive> |
使用keep-alive和v-show的区别:
v-show是通过原生CSS控制(使用情况:标签比较简单)
Keepalive 是在vue框架层级进行的JS对象的渲染(使用情况:带有层级或者tab切换的复杂组件切换)
<template>
<div>
<button @click="changeState('A')">A</button>
<button @click="changeState('B')">B</button>
<button @click="changeState('C')">C</button>
<keep-alive> <!-- tab 切换 -->
<KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
<KeepAliveStageB v-if="state === 'B'"/>
<KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>
</div>
</template>
<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'
export default {
components: {
KeepAliveStageA,
KeepAliveStageB,
KeepAliveStageC
},
data() {
return {
state: 'A'
}
},
methods: {
changeState(state) {
this.state = state
}
}
}
</script>
keepAliveStateA.vue
<template>
<p>state A</p>
</template>
<script>
export default {
mounted() {
// eslint-disable-next-line
console.log('A mounted')
},
destroyed() {
// eslint-disable-next-line
console.log('A destroyed')
}
}
</script>
6. mixin
多个组件有相同的逻辑,从中抽离出来
Mixin并不是完美的解决方案,会有问题
Vue 3提出的composition API 旨在解决这些问题
(Mixin就是一段js代码)
Mixin的问题
(1) 变量来源不明,不利于阅读
(2) 多个mixin可能会造成命名冲突
(3) Mixin和组件可能会出现多对多的关系,复杂度较高
<template>
<div>
<p>{{name}} {{major}} {{city}}</p>
<button @click="showName">显示姓名</button>
</div>
</template>
<script>
import myMixin from './mixin'
export default {
mixins: [myMixin], // 可以添加多个,会自动合并起来
data() {
return {
name: 'zs',
major: 'web'
}
},
methods: {
},
mounted() {
// eslint-disable-next-line
console.log('component mounted', this.name)
}
}
</script>
mixin.js
export default {
data() {
return {
city: '北京'
}
},
methods: {
showName() {
// eslint-disable-next-line
console.log(this.name)
}
},
mounted() {
// eslint-disable-next-line
console.log('mixin mounted', this.name)
}
}