一、组合式API里的写法
1、defineModel
defineModel()返回的值是一个ref,它可以像其他ref一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用。
- 它的.value和父组件的v-model的值一起更新
- 当它的子组件变更了,会触发父组件绑定的值一起更新
因为defineModel声明了一个prop,你可以通过给它传递选项,来声明底层prop的选项
const model = defineModel('modelValue', {
requiew: true, // 必填
default: 0, // 默认值
type: Number // 类型
})
注意:该写法需Vue3.2.0及以上版本才支持
1个数据的双向绑定
// 父组件
<template>
<p>{{ data }}</p>
<button @click="data = 'xxx2'">修改子组件数据</button>
<Subcomponent v-model="data" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Subcomponent from './components/Subcomponent.vue'
const data = ref('xxx1')
</script>
// 子组件
<template>
<h1>{{ modelValue }}</h1>
<button @click="updateData('xxx2')">修改父组件的数据</button>
</template>
<script lang="ts" setup>
import { defineModel } from 'vue'
const modelValue = defineModel()
const updateData = (e: string) => {
modelValue.value = e
}
</script>
多个数据的双向绑定
// 父组件
<template>
<p>{{ data1 }}</p>
<p>{{ data2 }}</p>
<button @click="data1 = 'xxx2'">修改子组件的数据1</button>
<button @click="data2 = 'xxx2'">修改子组件的数据2</button>
<Subcomponent v-model:data1="data1" v-model:data2="data2" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Subcomponent from './components/Subcomponent.vue'
const data1 = ref('data1')
const data2 = ref('data2')
</script>
// 子组件
<template>
<h1>{{ data1 }}</h1>
<h1>{{ data2 }}</h1>
<button @click="updateData1('xxx1')">修改父组件的数据1</button>
<button @click="updateData2('xxx2')">修改父组件的数据2</button>
</template>
<script lang="ts" setup>
import { defineModel } from 'vue'
const data1 = defineModel('data1')
const data2 = defineModel('data2')
const updateData1 = (e: string) => {
data1.value = e
}
const updateData2 = (e: string) => {
data2.value = e
}
</script>
v-model
1个数据的双向绑定
// 父组件
<template>
<p>{{ data }}</p>
<button @click="data = 'xxx2'">修改子组件数据</button>
<Subcomponent v-model="data" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Subcomponent from './components/Subcomponent.vue'
const data = ref('xxx1')
</script>
// 子组件
<template>
<h1>{{ modelValue }}</h1>
<button @click="updateData('xxx2')">修改父组件的数据</button>
</template>
<script lang="ts" setup>
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<(e: "update:modelValue", value: string) => void>()
const updateData = (e: string) => {
emit('update:modelValue', e)
}
</script>
多个数据的双向绑定
// 父组件
<template>
<p>{{ data1 }}</p>
<p>{{ data2 }}</p>
<button @click="data1 = 'xxx2'">修改子组件的数据1</button>
<button @click="data2 = 'xxx2'">修改子组件的数据2</button>
<Subcomponent v-model:data1="data1" v-model:data2="data2" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Subcomponent from './components/Subcomponent.vue'
const data1 = ref('data1')
const data2 = ref('data2')
</script>
// 子组件
<template>
<h1>{{ modelValue }}</h1>
<button @click="updateData1('xxx2')">修改父组件的数据1</button>
<button @click="updateData2('xxx2')">修改父组件的数据2</button>
</template>
<script lang="ts" setup>
const props = defineProps<{
data1: string,
data2: string
}>()
const emit = defineEmits<{
(e: "update:data1", value: string): void,
(e: "update:data2", value: string): void,
}>()
const updateData1 = (e: string) => {
emit('update:data1', e)
}
const updateData2 = (e: string) => {
emit('update:data2', e)
}
</script>
常规写法
// 子组件
<template>
<p>{{ p_data }}</p>
<button @click="updateData('xxx')">子组件按钮</button>
</template>
<script lang="ts" setup>
const props = defineProps<{ p_data: string }>()
const emit = defineEmits<(e: "update", value: string) => void> ()
function updateData(e: string) {
emit('update', '修改父组件data')
}
</script>
// 父组件
<template>
<p>{{ data }}</p>
<button @click="data = 'xxx2'">修改子组件数据</button>
<Subcomponent :p_data="data" @update="updateData"/>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Subcomponent from './components/Subcomponent.vue'
const data = ref('xxx1')
function updateData(e: string) {
data.value = e
}
</script>
选项式API里的写法
// 子组件
<template>
<input :value="modelValue" @input="handleInput" />
</template>
<script>
export default {
props: {
modelValue: String // 定义v-model绑定的属性名
},
emits: ['update:modelValue'] // 声明可以发出的自定义事件
}
</script>
// 父组件
<template>
<CustomInpput v-model="inputValue" />
</template>
<script>
import CustomInput from './CustomInput.vue'
export default {
components: {
CustomInput
},
data() {
return {
inputValue: ''
}
}
}
</script>
案例 —— 自定义勾选按钮
<template>
<div class="component-container">
<i class="check-btn" v-if="!isChecked" @click="handleCheck(true)"></i>
<i class="check-btn active" v-if="isChecked" @click="handleCheck(false)"></i>
</div>
</template>
<script lang="ts" setup>
import { ref, defineModel } from 'vue'
const emits = defineEmits(['change'])
const isChecked = defineModel('isChecked', { default: false })
function handleCheck(e: boolean) {
isChecked.value = e
emits('change', isChecked.value)
}
</script>
<style lang="scss" scope>
.component-container {
.check-btn {
display: block;
border: 1px solid #d4d4d9;
width: 15px;
height: 15px;
cursor: pointer;
&.active {
background: #0055FF;
}
}
}
</style>
<CheckBtn @change="(...args) => managementFieldCheckAll(...args, it.value)"/>