使用v-model完成数据的双向绑定

创作灵感

面试问道了,没答出来,呜呜呜~

v-model实现双向绑定的原理

首先我们要知道,v-model实现的双向绑定其实只是props与emit的简化版本。其中,props负责父组件向子组件传递值,emit负责子组件向父组件传递值。

在不考虑v-model的使用情况下,我们要实现双向绑定,应当是父组件向子组件使用props传值,子组件接收到这个值以后,在子组件内部使用并监视这个值的改变,识别到其改变后,使用emit将新的值传递给父组件,父组件拿到新的值后再去更新该值。

上述情况这样做确实能完成双向绑定,但缺点就是太麻烦了,而且父组件自己还要手动去更新子组件的值,这就丢失了封装的意义了。因此,使用v-model简化这个过程就显得尤为重要了。下面向大家具体介绍一下v-model的使用:

v-model的具体使用

在使用v-model时,正常的格式一般需要指定父组件的哪个值和子组件的哪个值绑定。比如,我们需要绑定输入框组件的输入值,应当有v-model:子组件的值=父组件的值。但是我们在使用element-plus组件等时,发现别人封装的组件并未说明需要在使用v-model时指定子组件的值。这是因为v-model会默认绑定modelValue值。因此我们在封装组件时,如果向要实现v-model进行父子组件值的绑定,子组件就需要接收modeValue值,并监听这个值,如果其发生改变,则向父组件通知更新值。但传统的更新肯定是不行的,我们需要使用自动更新,在emit事件中,添加一个"updata:modelValue"事件即可

下面就向大家展示一下v-model的一个具体使用:

父组件:

<template>
    <div>
        <searchComponent class="searchComponent" v-model="content" @returnResults="getResults"/>
        <el-divider />
        <div class="show"> 
            <el-empty v-if="users.data.length==0" description="空空如也~" />
            <div class="everyOne" v-else v-for="item in users.data" :key="item">
                <el-avatar class="everyOne-avatar" shape="square" :src="item.avatar_url" />
                <div class="everyOne-text">
                    <el-text line-clamp="1" class="everyOne-name" size="small">姓名:{{ item.name }}</el-text>
                    <el-text line-clamp="1" class="everyOne-account" size="small">学号:{{ item.account }}</el-text>
                    <el-text line-clamp="1" class="everyOne-email" size="small">邮箱:{{ item.email }}</el-text>
                </div>
                <div class="everyOne-tag">
                    <el-tag class="everyOne-sex" :type="item.sex=='male'?'primary':item.sex=='female'?'danger':'info'">
                        {{ item.sex=='male'?'男':item.sex=='female'?'女':'保密' }}</el-tag>
                    <el-tag class="everyOne-isIdentification" :type="item.isIdentification=='0'?'info':'primary'">
                        {{ item.isIdentification=='0'?'未认证':'已认证' }}</el-tag>
                    <el-tag class="everyOne-type" :type="item.type=='student'?'primary':'success'">
                        {{ item.type=='student'?'学生':'教师' }}</el-tag>
                </div>
                <button class="everyOne-detail" @click="toUserDetail(item.id)">详情>></button>
            </div>
        </div>
        <el-pagination v-if="total!=0" class="pagination" @current-change="changePage" background layout="prev, pager, next" :total="total" />
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
import API from '@/untils/axios'
import searchComponent from "@/components/searchComponent.vue"

export default defineComponent({
    components:{
        searchComponent
    },
    setup(){
        var users:any=reactive({
            data:[]
        })
        var total=ref(0)
        var content=ref("2")
        function getResults(e:any){
            users.data=e.users
            total.value=e.total
            content.value=e.content
        }
        function changePage(e:any){//改变当前页
            API.get("admin/changeUserPages",{
                params:{
                    content:content.value,
                    start:(e-1)*10
                }
            }).then((res:any|undefined)=>{
                if(res==undefined){
                    return
                }
                users.data=res.data
            })
        }
        return{
            users,
            total,
            content,
            getResults,
            changePage
        }
    },
    methods:{
        toUserDetail(e:number){
            this.$router.push({
                path:"/home/manngerUser/searchUser/userDetail/"+e
            })
        }
    }
})
</script>

子组件:

<template>
    <div class="mt-4">
        <el-input
            v-model="content"
            style="max-width: 600px"
            placeholder="请输入用户信息"
            class="input-with-select"
        >
        <template #prepend>
            <el-select v-model="select" placeholder="账号" style="width: 115px">
                <el-option :disabled="noSelect==1" label="账号" value="1" />
                <el-option :disabled="noSelect==2" label="姓名" value="2" />
            </el-select>
        </template>
        <template #append>
            <el-button @click="search" icon="Search" />
        </template>
        </el-input>
    </div>
</template>

<script lang="ts">
import { defineComponent,reactive, ref, toRaw,watch } from 'vue'
import API from '@/untils/axios'
import { ElMessage } from 'element-plus'

export default defineComponent({
    props:['noSelect','modelValue'],
    emits:["returnResults","update:modelValue"],
    name:"searchComponent",
    setup(props,emits){
        var content=ref(props.modelValue)
        watch([content],(newValue)=>{
            emits.emit("update:modelValue",newValue[0])
        },{
            deep:true
        })
        var select=ref("1")
        var users=reactive({//返回的前十位用户信息
            data:[]
        })
        var total=ref(0)
        return{
            select,
            users,
            total,//总的记录数
            content
        }
    },
    methods:{
        search(){
            if(this.content==""){
                ElMessage({
                    message:"搜索值为空",
                    type:"warning"
                })
                return
            }
            API.get("admin/searchUsers",{
                params:{
                    type:this.select,
                    content:this.content                
                }
            }).then((res:any)=>{
                if(res==undefined){
                    return
                }
                if(res.data.users.length==0){
                    ElMessage({
                        message:"搜索为空",
                    })
                } else {
                    ElMessage({
                        message:"搜索成功",
                        type:"success"
                    })
                }
                this.users.data=res.data.users
                this.total=res.data.total
                var result={
                    users:toRaw(this.users.data),//搜索出来的前10位信息
                    total:this.total,
                    content:this.content
                }
                this.$emit("returnResults",result)
            })
        }
    }
})
</script>

上述案例中,父组件使用了v-model,但未指定子组件需绑定的值,因此会默认绑定modeValue,子组件在监视该值时,使用"update:modeValue"进行自动更新。通过上述方法便可实现父子组件间的双向绑定了。

总结

一般来说,要想实现父子组件间的双向绑定,就是父组件向子组件通信,子组件向父组件通信的一个过程。而v-model就是简化了这一双向过程。感谢观看!

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易烊子豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值