【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>
相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A4 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁4 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄4 天前
JavaScript 隐式全局变量解析
javascript
honkun64 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19914 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net