目录
1.自定义v-model
vue中的v-model指令实现了表单的双向绑定
<input type="text" v-model="message">
<p>{{message}}</p>
// v-model只是语法糖,真正的实现形式:
<input type="text" :value="message" @input="message = $event.target.value">
一个组件上的v-model默认会利用名为value的prop和名为input的事件
例子:
// 父组件
<CustomVModel v-model="name"/>
// 子组件
<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 修改只会渲染一次
this.$nextTick(() => {
// 获取 DOM 元素
const ulElem = this.$refs.ul1
// eslint-disable-next-line
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
3.refs
- ref 加在普通的元素上,用this.$refs.(ref值) 获取到的是dom元素
- ref加在子组件上,用this.$refs.(ref值)获取到的是组件实例,可以使用组件的所有方法,例如 this.$refs.child.handleDelete()
- 如果是v-for循环出来的ref,this.$refs.(ref值)获取到的是一个数组,循环处理即可
注意:ref需要在dom渲染完成后才会有,所以只能在生命周期mounted()之后再调用,
或是在this.$nextTick(()=>{}) 中调用
4.slot
插槽:父组件在子组件中插入一部分内容
slot-基本用法:
// 父组件
<SlotDemo :url="website.url"> {{website.title}} </SlotDemo>
// 子组件
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>
slot-作用域插槽:父组件访问子组件属性值
// 父组件
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
// 子组件
<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>
slot-具名插槽
// 父组件
<NameSlot>
<!--缩写<templete #header>-->
<templete v-slot:header>
<h1>将插入header slot中</h1>
</templete>
<p>将插入到 main slot 中,即未命名的slot</p>
<templete v-slot:footer>
<h1>将插入footer slot中</h1>
</templete>
</NameSlot>
// NameSlot子组件
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
5.动态组件
- :is="component-name"用法
- 需要根据数据,动态渲染的场景。即组件类型不确定
例如:新闻详情页,组件类型不确定
// 父组件
<div v-for="(val, key) in newsDate" :key="key">
<component :is="val.type"/>
</div>
<script>
import Text from './Text'
import Image from './Image'
import Video from './Video'
export default {
data() {
return {
newsDate: {
1: {
type: 'Text'
},
2: {
type: 'Image'
},
3: {
type: 'Video'
},
}
}
}
}
</script>
// 子组件
6.异步组件
- import()函数
- 按需加载,异步加载大组件
// 父组件
// 同步引入:加载页面即引入,如果组件体积特别大,影响性能
// 异步引入:什么时候用,什么时候加载,优化性能
<script>
// import FormDemofrom './FormDemo'
export default {
components: {
// FormDemofrom ,
FormDemo: () => import('./FormDemo'),
},
</script>
7.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 切换 -->
<!--v-if根据条件渲染和销毁组件-->
<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>
8.mixin
- 多个组件有相同的逻辑,抽离出来
- mixin 并不是完美的解决方案,会有一些问题
- Vue3 提出的Composition API旨在解决这些问题
mixin问题:
- 变量来源不明确
- 多mixin可能会造成命名冲突
- mixin和组件可能出现多对多的关系,复杂度较高
// 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)
}
}
使用
<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() {
// eslint-disable-next-line
console.log('component mounted', this.name)
}
}
</script>