【Vue】v-model进阶 && ref && nextTick

文章目录

  • [Ⅰ. v-model的进阶使用](#Ⅰ. v-model的进阶使用)
    • [一、v-model 的原理](#一、v-model 的原理)
    • [二、v-model 用在组件上](#二、v-model 用在组件上)
  • [Ⅱ. ref 属性](#Ⅱ. ref 属性)
    • 一、获取原生DOM
    • [二、调用组件实例的方法 -- `defineExpose()`](#二、调用组件实例的方法 -- defineExpose())
  • [Ⅲ. nextTick()](#Ⅲ. nextTick())

Ⅰ. v-model的进阶使用

一、v-model 的原理

v-model 实际上是个语法糖,当作用在 原生输入框时,本质是 :value + @input 的组合。

javascript 复制代码
<input v-model="msg"/>

<!-- 等同于 -->
<input type="text" :value="msg"  @input="msg = $event.target.value">

其中 $event事件对象的引用,可以用它拿到点击的元素、坐标、键盘键值等等。

二、v-model 用在组件上

v-model 除了用在表单元素上,还可以用在组件上,实现数据的双向绑定。下面以实现父组件和子组件数据的双向绑定为例:

  1. 父组件使用子组件时候绑定 v-model="数据"
  2. 子组件通过一个宏 defineModel() 接收数据 (注意返回值是 ref ,使用时候要用 .value 访问),子组件可以直接操作接收的数据,即可实现数据双向绑定

App.vue文件:

javascript 复制代码
<script setup>
    import { ref } from 'vue'
    import MySelect from './components/MySelect.vue'
    
    const activeId = ref('222')
</script>

<template>
  <MySelect v-model="activeId"/>
</template>

MySelect.vue文件:

javascript 复制代码
<script setup>
  const model = defineModel()
</script>

<template>
  <select v-model="model">
    <option value="111">北京</option>
    <option value="222">上海</option>
    <option value="333">深圳</option>
    <option value="444">杭州</option>
    <option value="555">苏州</option>
  </select>
</template>

defineModel 本身是一个便利宏。编译器将其展开为以下内容:

  • 一个名为 modelValue 的属性,本地 ref 的值与其同步;
  • 一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。

Ⅱ. ref 属性

ref 属性可以用于 获取原生DOM元素获取组件实例

步骤:

  1. 在要获取的原生DOM元素,或者组件实例标签中声明并绑定 ref 属性
  2. 需要使用时,通过 ref.value 获取

一、获取原生DOM

ECharts引入项目

这里以绘制图表为例:

App.vue文件:

javascript 复制代码
<template>
    <MyChart />
</template>

<script setup>
    import MyChart from './components2/MyChart.vue';
</script>

MyChart.vue文件:

javascript 复制代码
<template>
    <div class="chart-box" ref="box_ref"></div>
</template>

<script setup>
    import * as echarts from 'echarts';
    import { onMounted, ref } from 'vue';

    const box_ref = ref(null)

    onMounted(() => {
        // 基于准备好的dom,初始化echarts实例
        const myChart = echarts.init(box_ref.value);

        // 绘制图表
        myChart.setOption({
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            xAxis: {
                data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
            },
            yAxis: {},
            series: [
                {
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
                }
            ]
        });
    })
</script>

<style scoped>
.chart-box {
    width: 400px;
    height: 300px;
    margin: 100px auto;
    border: 3px solid #322929;
}
</style>

二、调用组件实例的方法 -- defineExpose()

组件要想让自己的方法被外部组件拿到并且使用的话,需要调用 defineExpose() 将要暴露出去的方法进行注册 ,外部组件才能通过 ref.value 来拿到该注册的方法。

components/MyForm.vue文件:

javascript 复制代码
<script setup>
    // 表单校验
    const validate = () => {
        return Math.random() > 0.5 ? true : false
    }

    // 需要暴露给组件, 目的是父组件可以通过 ref 可以拿到子组件的方法
    defineExpose({
        validate
    })
</script>

<template>
  <div class="login-box">
    账户:<input type="text" /><br /><br />
    密码:<input type="password" /><br /><br />
  </div>
</template>

App.vue文件:

javascript 复制代码
<template>
    <MyForm ref="form_ref"/>
    <button @click="loginUp">登录</button>
</template>

<script setup>
    import { ref } from 'vue';
    import MyForm from './components3/MyForm.vue';

    const form_ref = ref(null)

    const loginUp = () => {
        if(form_ref.value.validate() === true) {
            console.log("登录成功");
        } else {
            console.log("登录失败");
        }
    }
</script>

Ⅲ. nextTick()

作用:等 DOM 更新后,才会触发执行此方法里的函数体,此时不会出现拿到空的 DOM 的情况

因为 vue 为了提高效率,在更新 DOM 的时候是异步操作。

下面举个例子,代码需求:

  1. 点击编辑,显示编辑框
  2. 让编辑框,立刻获取焦点
javascript 复制代码
<template>
<div>
    <span>{{ text }}</span>
    <button @click="edit">编辑</button>
</div>
<div v-if="isInput">
    <input type="text" ref="input_ref" v-model="input_text"></input>
    <button @click="text = input_text; isInput = !isInput">确认</button>
</div>
</template>

<script setup>
    import { nextTick, ref } from 'vue';

    const text = ref('大标题')

    const isInput = ref(false) // true表示显示输入框
    const input_text = ref('') // 输入框内容

    const input_ref = ref(null) // 输入框实例

    const edit = () => {
        isInput.value = !isInput.value;

        if(isInput.value === true) {
            // 在nextTick()中完成输入框的聚焦,保证拿到的输入框实例不为null
            nextTick(() => {
                input_ref.value.focus()
            })
        }
    }
</script>
相关推荐
2501_944525543 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
打小就很皮...3 小时前
《在 React/Vue 项目中引入 Supademo 实现交互式新手指引》
前端·supademo·新手指引
C澒3 小时前
系统初始化成功率下降排查实践
前端·安全·运维开发
摘星编程3 小时前
React Native + OpenHarmony:自定义useFormik表单处理
javascript·react native·react.js
C澒3 小时前
面单打印服务的监控检查事项
前端·后端·安全·运维开发·交通物流
pas1363 小时前
39-mini-vue 实现解析 text 功能
前端·javascript·vue.js
qq_532453533 小时前
使用 GaussianSplats3D 在 Vue 3 中构建交互式 3D 高斯点云查看器
前端·vue.js·3d
Swift社区4 小时前
Flutter 路由系统,对比 RN / Web / iOS 有什么本质不同?
前端·flutter·ios
2601_949833394 小时前
flutter_for_openharmony口腔护理app实战+我的实现
开发语言·javascript·flutter
雾眠气泡水@4 小时前
前端:解决同一张图片由于页面大小不统一导致图片模糊
前端