组件进阶
v-model 原理
语法糖:v-model本质上是 value属性和input事件的一层包装 v-model的作用:
- 提供数据的双向绑定数据发生了改变,页面会自动变 v-bind:value
- 页面输入改变 ,数据会自动变化 v-on:input
v-model给组件使用
v-model相当于给父组件添加了:value=""和@input=""
<template>
<div>
<add-table v-model="num"></add-table>
<!-- 相当于做了以下步骤 -->
<!-- <add-table :value="num" @input="input"></add-table> -->
<h2>父组件的num:{{ num }}</h2>
</div>
</template>
<script>
import addTable from "./components/add-table.vue";
export default {
components: {
"add-table": addTable,
},
data() {
return {
num: 100,
};
},
// 不用再给methods写input事件,v-model自动把传过来的值赋给value
};
</script>
<style>
</style>
子组件中props的"value"和$emit中的"input"是固定单词,不能修改
<template>
<div>
<h2>子组件的num:{{ value }}</h2>
<button @click="fn">改为300</button>
</div>
</template>
<script>
export default {
props: ["value"], // value是固定的写法
methods: {
fn() {
this.$emit("input", 300); // input是固定的写法
},
},
};
</script>
<style>
</style>
ref 和 $refs
作用:利用 ref 和 $refs 可以用于 获取 dom 元素,或者组件实例 步骤:
- 给目标标签添加ref属性,ref="任意名字aaa"
- 通过 this.$refs.aaa,获取组件内容
- 通过this.$refs.aaa.属性/方法,可以调用组件里的属性/方法
<template>
<div>
<input type="text" ref="inputA" />
<button @click="fn">获取</button>
</div>
</template>
<script>
export default {
methods: {
fn() {
// 调用方法
this.$refs.inputA.focus();
},
},
};
</script>
$nextTick
问题:当数据发生改变时,由于Vue更新DOM是异步的,无法即是获取更新后的DOM内容 解决方案:nextTick(callback)
<template>
<div>
<input type="text" ref="inputA" v-show="showInput" />
<button @click="fn">获取</button>
</div>
</template>
<script>
export default {
data() {
return {
showInput: false,
};
},
methods: {
fn() {
this.showInput = true;
// 如果没有$nextTick,此时vue识别到的v-show还是false的状态
this.$nextTick(() => {
console.log(this.$refs.inputA);
});
},
},
};
</script>
同一个组件多次调用,数据不会相互影响
<template>
<div>
<Subject-table ref="count"></Subject-table>
<Subject-table ref="count2"></Subject-table>
<Subject-table ref="count3"></Subject-table>
<button @click="fn">123</button>
</div>
</template>
<script>
import subjectTable from './components/subject-table.vue'
export default {
components: {
"Subject-table":subjectTable
},
methods: {
fn() {
console.log(this.$refs.count.num); // 当其中某一个数据改变时,其他的数据不会跟着变化
console.log(this.$refs.count2.num);
console.log(this.$refs.count3.num);
}
}
}
</script>
<style>
</style>
动态组件
定义:可以改变的组件 使用场景:多组件同一位置, 切换显示的需求 基本语法:
- <component + :is=" (哪个组件)">
- 修改 is 属性绑定的值 => 切换组件
props校验
作用:提高 子组件被使用时 的稳定性,防止props传值类型等传错
props: {参数名:类型,},
// 类型错误能允许,但是报错
插槽
使用场景:要在页面中显示一个对话框, 封装成一个组件
基本语法
- 子组件内用占位
- 使用时,给子组件标签内容传入标签替换slot
<!-- 子组件 -->
<template>
<div>
<h1>友情提醒</h1>
<slot></slot>
<button>关闭</button>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<tang-chuang>
<h3>请输入正确的技师号码</h3>
<h3>请输入正确的技师号码</h3>
</tang-chuang>
</div>
</template>
具名插槽
使用场景:需要传多个插槽 步骤
- 子组件中的slot添加一个name属性,slot的可以添加默认内容,如果父组件没有传则显示默认内容
- 父组件中在子组件标签内容写<template v-slot:任意名>插入的内容
- 其中v-slot:任意名 可以简写为#任意名
<!-- 子组件 -->
<template>
<div>
<!-- 插槽内的是默认内容,不传则会显示 -->
<slot name="title"><h1>友情提示</h1></slot>
<slot name="body"></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<tang-chuang>
<template v-slot:title>
<h1>标题</h1>
</template>
<!-- 可以简写 -->
<template #body>
<h1>内容</h1>
</template>
<template #footer>
<button>关闭</button>
</template>
</tang-chuang>
</div>
</template>
作用域插槽
定义:定义 slot 插槽的同时, 是可以传值的。给插槽上可以绑定数据,将来使用组件时可以用。 使用场景: 步骤
-
把弹窗组件的标题用一个变量存储
- 如:dialogTitle: "友情提示"
-
在弹窗组件内部,给插槽传参数
- 如:
- 会得到obj = { dialogTitle: "友情提示" }
-
在父组件,在对应插槽接受传过来的参数
- 如:<template #title="obj">
-
在父组件插槽内,使用参数
-
{{ obj.title }}
-
<template>
<div>
<!-- 2.传参 -->
<slot name="title" :title="dialogTitle">
<h1>默认提示</h1>
</slot>
</div>
</template>
<script>
export default {
data() {
return {
// 1.存值
dialogTitle: "友情提示",
};
},
};
</script>
<template>
<div>
<tang-chuang>
<!-- 3.用一个obj接收 -->
<template #title="obj">
<!-- 4.使用 -->
<h1 :style="{ color: 'red' }">{{ obj.title }}</h1>
</template>
</tang-chuang>
</div>
</template>
<script>
import tangchuang from "./components/tang-chuang.vue";
export default {
components: {
"tang-chuang": tangchuang,
},
};
</script>
</style>