一、常见高级特性
- 自定义 v-model
- $nextTick
- slot
- 动态、异步组件
- keep-alive
- mixin
二,$nextTick
基本原理:
- Vue是异步渲染,data 改变之后,DOM 不会立即被渲染
- $nextTick => 等到 dom 渲染完毕再进行回调,获取最新的 dom
- 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次。
拿到 DOM 元素的节点:
在对应的 DOM 元素上面设置 ref=”xxx”, 使用 this.$ref.xxx 即可获取到对应的 DOM 元素.
三,slot
1,基本使用:让父组件往子组件中插入一段内容,即把父组件里面的一些内容,传递给子组件,取代子组件里面slot里面的相应内容
<template><div><p>vue 高级特性</p><hr><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>
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
这个时候,slot 里面的内容就会变为 http://imooc.com/
2,作用域插槽:将子组件里面的 data 数据抛给父组件,让父组件可以获取使用到子组件抛出来的数据
关键点:
在子组件里面里面定义一个自定义属性slotData,父组件里面通过引入子组件,在其子组件里面写一个 template, 给 v-slot 取一个名字slotProps, 通过 slotProps.slotData.title 来获取到对应的子组件data里面的数据
<template>
<div>
<p>vue 高级特性</p>
<hr>
<ScopedSlotDemo :url="website.url">
<!---{{website.title}}--->
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
</div>
</template>
<script>
import SlotDemo from './SlotDemo'
export default {
components: {
ScopeSlotDemo
},
data() {
return {
name: '双越',
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序员的梦工厂'
}
}
}
}
</script>
<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>
3,具名插槽
<!--- NameSlot 组件 ---->
<div class-"container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<NameSlot>
<!---- 缩写 <template #header> ----->
<template v-slot:header>
<h1>将插入 header slot 中</h1>
</template>
<p>将插入到 main slot 中,即未命名的 slot </p>
<template v-slot:footer>
<h1>将插入 footer slot 中</h1>
</template>
</NameSlot>
四,动态组件
情景:一个新闻详情页面,里面的内容由 text 组件,img组件,video组件 组合而成,但是内容不确定,这个时候,应该如何正确的渲染页面的内容?
答:使用动态组件进行处理
如下面例子所示,动态组件的用法,
// 父组件
<template>
<div>
<!--<component :is="NextTickName"/>--->
<!-- 动态组件 -->
<div v-for="(val, key) in newsData" :key="key">
<component :is="val.type"/>
</div>
</div>
</template>
<script>
import NextTick from './NextTick'
export default {
components: {
NextTick
},
data() {
return {
// NextTickName: "NextTick"
newsData: {
1:{
type: 'text
},
2:{
type: 'text
},
3:{
type: 'img
},
4:{
type: 'video
}
}
}
}
}
</script>
五,异步组件
import 函数
按需加载,异步加载大组件
<template>
<div>
<!-- 异步组件 -->
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>
</div>
</template>
<script>
// import FormDemo from '../BaseUse/FormDemo' 这样的引入方式是同步引入,打包的时候,会打包所有的组件
export default {
components: {
// FormDemo // 同步引入
FormDemo: () => import('../BaseUse/FormDemo') // import 一个函数,属于异步组件的引入方式
},
data() {
return {
showFormDemo: false
}
}
}
</script>
六,vue如何缓存组件 - keep-alive
缓存组件
场景:频繁切换,不需要重复渲染
出现地方之一:Vue 常见性能优化
<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'"/>
<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>
// 使用了keep-alive之后的情况:
打印结果: A mounted->B mounted ->C mounted
// 不使用 keep-alive的情况
打印结果: A mounted -> A destory
B mounted -> B destory
C mounted -> C destory
// KeepAliveStageA
<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>
// KeepAliveStageB
<template>
<p>state B</p>
</template>
<script>
export default {
mounted() {
// eslint-disable-next-line
console.log('B mounted')
},
destroyed() {
// eslint-disable-next-line
console.log('B destroyed')
}
}
</script>
// KeepAliveStageC
<template>
<p>state C</p>
</template>
<script>
export default {
mounted() {
// eslint-disable-next-line
console.log('C mounted')
},
destroyed() {
// eslint-disable-next-line
console.log('C destroyed')
}
}
</script>
重点:
使用了 keep-alive 之后,组件在进行切换的时候,上一个组件就不会被销毁,下一次点击的时候就不需要重新渲染一遍这个组件,提高了性能。
七,mixin
- 多个组件有相同的逻辑,抽离出来
- mixin 并不是完美解决方案,会有一些问题
- Vue 3 提出的 Composition API 旨在解决这些问题
min 示例讲解:
// 主入口文件 index.vue
// 引入对应的 MixinDemo 组件
<template>
<div>
<MixinDemo/>
</div>
</template>
<script>
import MixinDemo from './MixinDemo'
export default {
components: {
MixinDemo
},
data() {
return {
}
}
}
</script>
// MixinDemo.vue 文件
// 通过 mixins: [myMixin] 的方式来引入 myMixin 组件里面抽离出来的一些公共属性和公共方法,以便可以在此使用
// city 属性就是 myMixin 里面的内容
<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: '双越',
major: 'web 前端'
}
},
methods: {
},
mounted() {
console.log('component mounted', this.name)
}
}
</script>
// mixin.js
// 用来抽离出一些公共的属性和方法,以便可以在其他组件里面使用这些对应的公共内容,避免在其他文件里面写重复的
代码
// 使用了 export 的方法,导出对应的内容(data,methods, 生命周期函数等)
<script>
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)
}
}
</script>
mixin 的问题
- 变量来源不明确,不利于阅读(代码可读性差)
- 多 mixin 可能会造成命名冲突(不同 mixin 混合可能会出现变量覆盖,函数同名,功能错误等问题)
- mixin 和组件可能会出现多对多的关系,复杂度较高
八,相关的面试技巧
- 可以不太深入,但是必须知道
- 熟悉基本用法,了解使用场景
- 最好能和自己的项目经验结合起来
