父组件:
主要按钮
子组件:
<template>
<button
class="biu-button"
:class="[
`biu--button--${type}`,
{
'is-plain': plain,
'is-disabled': disabled,
'is-round': round,
'is-circle': circle,
},
]"
@click="handleClick"
:disabled="disabled"
>
<i v-if="icon" :class="`biu-icon-${icon}`">i>
<span v-if="$slots.default"><slot>slot>span>
button>
template>
<script>
export default {
name: "BiuButton",
props: {
type: {
type: String,
default() {
return "default";
},
},
plain: {
type: Boolean,
default: false,
},
round: {
type: Boolean,
default: false,
},
circle: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
icon: {
type: String,
default: "",
},
},
};
script>
主要使用下面方式接收:
props: {
type: {
type: String,
default() {
return "default";
},
},
}
父组件:
<template>
<div id="app">
<biu-dialog
title="温馨提示"
:visible="visible"
v-on:handleClose="handleClose"
>
biu-dialog>
div>
template>
<script>
export default {
name: "App",
data() {
return {
visible: true,
};
},
methods: {
handleClose() {
this.visible = false;
},
},
};
script>
子组件:
<template>
<div class="biu-dialog_wrapper" v-show="visible">
<div class="biu-dialog">
<div class="biu-dialog_header">
<button class="biu-dialog_headerbtn">
<i class="biu-icon-basic_refresh1" @click="handleClose">i>
button>
div>
div>
div>
template>
<script>
export default {
name: "biu-dialog",
props: {
visible: {
type: Boolean,
default() {
return false;
},
},
},
methods: {
handleClose() {
this.$emit("handleClose", false);
},
},
};
script>
子组件通过@click="handleClose"调用子组件的
this.$emit(“handleClose”, false);从而调用 父组件的handleClose函数,修改父组件的visible值。然后visible单向传递给子组件。
vue提供了一个.sync
修饰符来简化第二节中的代码:
父组件:
<template>
<div id="app">
<div>
<biu-dialog title="温馨提示" :visible.sync="visible">
biu-dialog>
div>
template>
<script>
export default {
name: "App",
components: {},
data() {
return {
visible: true,
};
},
methods: {},
};
script>
子组件:
也就是父组件不需要再绑定子组件需要触发的事件了。
在直接使用input的时候,可以直接使用v-mode进行数据的双向绑定,而当我们使用自定义组件的时候。也可以利用这一点。
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件,
这时候就可以在父组件中:
<template>
<div id="app">
<biu-input
v-model="username"
>biu-input>
div>
template>
<script>
export default {
name: "App",
data() {
return {
username: "",
};
}
};
script>
也就是使用了v-model的组件biu-input,该子组件内部默认会生成名为value的prop,和绑定名为input的事件。(而该input事件,就是更新父组件的v-model绑定的属性)
于是可以在这个子组件中进行接收使用名为value的prop:
子组件先接收value,子组件触发input修改事件handleInput后触发父组件的input事件,从而修改了父组件的username值。
自定义组件的v-model 和 .sync修饰符其实本质上都是vue的语法糖,用于实现父子组件的“数据”双向绑定,vue3中已经不再有.sync修饰符了,新的v-model取代了vue2中的v-model和.sync修饰符。
相比较之下,.sync
更加灵活,它可以给多个 prop
使用,而 v-model
在一个组件中只能有一个。(Vue3中v-model已经可以给多个prop使用了)
从语义上来看,v-model
绑定的值是指这个组件的绑定值,比如 input 组件,select 组件,日期时间选择组件,颜色选择器组件,这些组件所绑定的值使用 v-model
比较合适。其他情况,没有这种语义,个人认为使用 .sync
更好。
在第四节中,v-model是配合@input方法,让子组件调用父组件的input方法。
实际上,还可以在子组件使用compute的set和get方法实现这一功能。
父组件:
<biu-radio v-model="gender" label="0">男</biu-radio>
data() {
return {
gender: "",
};
}
子组件:
<input
type="radio"
class="one-radio_original"
:value="label"
v-model="model"
/>
//计算属性
computed: {
model: {
get() {
return this.value;
},
set(value) {
// 触发父组件的input事件
this.$emit("input", value);
},
},
},
input的值是label定义的。当选中时,input的绑定值变成label,触发computed的set,就会调用父组件的input函数,从而修改父组件的gender值。
(上文说过,自定义组件的v-model会给子组件内部默认生成名为value的prop,和绑定名为input的事件)
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
祖先组件:
子孙组件:
export default {
inject: {
RadioGroup: {
default: "",
},
},
}
这样,RadioGroup默认是是空字符串,如果有传入,则是组件RadioGroup。子组件中就可以直接使用了。