一、高级特性
1. 自定义 v-model
- 定义vue
<template> <input type="text" :value="text" @input="$emit('change', $event.target.value)" > <!-- 1. 上面的 input 使用了 :value 而不是 v-model 2. 上面的 change 和 model.event 要对应起来 3. text 属性对应起来 --> </template> <script> export default { model: { prop: 'text', // 对应 props text1 event: 'change' }, props: { text: String, default() { return '' } } } </script>
- 用法vue
<template> <div> <!-- 自定义 v-model --> <p>{{name}}</p> <CustomVModel v-model="name"/> </div> </template> <script> import CustomVModel from './CustomVModel'; export default { components: { CustomVModel }, data() { return { name: "自定义v-model", }; }, }; </script>
2. $nextTick 【组件更新之后,获取最新的 DOM 】
- Vue 是异步渲染
- data 改变之后,DOM 不会立即渲染
- $nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点
- 详细参看
3. slot
正常使用
vue<template> <a :href="url"> <slot> 默认内容,即父组件没设置内容时,这里显示 </slot> </a> </template> <script> export default { props: ['url'], data() { return {} } } </script>
vue<template> <div> <!-- slot --> <SlotDemo :url="website.url"> {{website.title}} </SlotDemo> </div> </template> <script> import SlotDemo from './SlotDemo' export default { components: { SlotDemo }, data() { return { website: { url: "https://www.baidu.com/", title: "百度", subTitle: "面向百度编程", }, }; }, }; </script>
作用域插槽
父组件获取子组件 slot 的值
vue<template> <a :href="url"> <slot :slotData="website"> {{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 --> </slot> </a> </template> <script> export default { props: ['url'], data() { return { website: { url: '子组件url', title: '子组件的标题', subTitle: '子组件副标题' } } } } </script>
vue<template> <div> <!-- slot --> <ScopedSlotDemo :url="website.url"> <template v-slot="slotProps"> {{slotProps.slotData.title}} </template> </ScopedSlotDemo> </div> </template> <script> import ScopedSlotDemo from './ScopedSlotDemo' export default { components: { ScopedSlotDemo }, data() { return { website: { url: "https://www.baidu.com/", title: "百度", subTitle: "面向百度编程", }, }; }, }; </script>
具名插槽
vue<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
vue<!-- #header 是 v-slot 的缩写 --> <base-layout> <template #header> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template #footer> <p>Here's some contact info</p> </template> </base-layout>
4. 动态组件
- 用法
:is="component-name"
- 需要根据数据类型,动态渲染的场景。即组件类型不确定
- 场景
- tab 页的切换
- 详情页显示
5. 异步组件
- import() 函数
- 按需加载。异步加载大组件
- 常用于拥有 v-if 逻辑的组件vue
<template> <div> <!-- 异步组件 --> <FormDemo v-if="showFormDemo"/> <button @click="showFormDemo = true">show form demo</button> </div> </template> <script> export default { components: { FormDemo: () => import('../BaseUse/FormDemo'), }, data() { return { showFormDemo: false, }; }, }; </script>
6. keep-alive
缓存组件
频繁窃魂,不需要重复渲染
Vue 常用性能优化
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'"/> <!-- 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>
vue<template> <p>state A</p> </template> <script> export default { mounted() { console.log('A mounted') }, destroyed() { console.log('A destroyed') } } </script>
vue<template> <p>state B</p> </template> <script> export default { mounted() { console.log('B mounted') }, destroyed() { console.log('B destroyed') } } </script>
vue<template> <p>state C</p> </template> <script> export default { mounted() { console.log('C mounted') }, destroyed() { console.log('C destroyed') } } </script>
7. mixin
多个组件有相同的逻辑,抽离出来
mixin 存在一些问题,容易混乱
- 多 mixin 容易造成命名冲突,直接覆盖
- mixin 和组件可能出现多对多的关系,复杂度较高
在 vue3 的 Composition API 得到了很好的解决
jsexport default { data() { return { city: '北京' } }, methods: { showName() { console.log(this.name) } }, mounted() { console.log('mixin mounted', this.name) } }
vue<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>