自定义v-model
Index.vue
<p>{{name}}</p>
<CustomVModel v-model="name"/>
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>
$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 修改只会渲染一次
this.$nextTick(() => {
// 获取 DOM 元素
const ulElem = this.$refs.ul1
// eslint-disable-next-line
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
slot
- 基本使用
Index.vue
<SlotDemo :url="website.url">
{{website.title}}
</SlotDemo>
SlotDemo.vue
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
- 作用域插槽
Index.vue
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
ScopedSlotDemo.vue
<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>
- 具名插槽
Index.vue
<NamedSlot>
<template v-slot:header>
header
</template>
<template v-slot:footer>
footer
</template>
</NamedSlot>
NamedSlot.vue
<div>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>
动态、异步组件
动态组件
<component :is="NextTickName"/>
<script>
import NextTick from './NextTick'
export default {
components: {
NextTick
},
data() {
return {
NextTickName: "NextTick",
}
}
}
</script>
异步组件
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>
<script>
export default {
components: {
FormDemo: () => import('./FormDemo')
},
data() {
return {
showFormDemo: false,
}
}
}
</script>
keep-alive
缓存组件
<keep-alive> <!-- tab 切换 -->
<KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
<KeepAliveStageB v-if="state === 'B'"/>
<KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>
mixin
- 变量来源不明确
- 多mixin可能会造成命名冲突
- mixin和组件可能出现多对多的关系,复杂度较高
Mixin.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: 'wilber',
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)
}
}