最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue3封裝自定義v-model的hooks示例詳解

 更新時間:2022年07月27日 09:57:25   作者:油箱上的蔥花  
這篇文章主要為大家介紹了vue3封裝自定義v-model的hooks示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

??前言

  • 基礎篇:簡單介紹vue3setup語法如何自定義v-model;
  • 進階篇:如何提取v-model語法作為一個公用hooks

??基礎

基礎篇可繞過,只是對于官網(wǎng)給出的教程,進行了總結概括并給出demo

基本的v-model

子組件中滿足兩個點,即可完成自定義雙向綁定:

  • props中定義一個值xxx
  • emit中定義一個update:xxx事件

下面我們來寫一個最基本的v-model組件:

  • props中定義一個modelValue值,并綁定到inputvalue屬性上;
  • emit中定義一個update:modelValue事件

需要注意的是,當modelValue作為props傳入,update:modelValue事件將被自動注冊到emit事件中

<template>
  <input
    type="text"
    @input="emit('update:modelValue', $event.target.value)"
    :value="props.modelValue"
  />
</template>
<script setup>
const emit = defineEmits();
const props = defineProps({
  modelValue: String,
});
</script>

父組件中,引入modelComp子組件,并綁定test值到v-model上,test便完成了一次雙向綁定。

<template>
  <modelComp v-model="test"></modelComp>
</template>
<script setup>
import { ref, watch } from "vue";
import modelComp from "./components/model/modelComp.vue";
const test = ref("");
</script>

這便是一個最基本的自定義v-model組件;

多個v-model綁定

當我們需要多個雙向綁定時,如下:

<modelComp
  v-model="test"
  v-model:test1="test1"
  v-model:test2="test2"
></modelComp>
<script setup>
import { ref, watch } from "vue";
import modelComp from "./components/model/modelComp.vue";
const test = ref("");
const test1 = ref("");
const test2 = ref("");
</script>

子組件中,同樣按著兩個點來定義:

  • props中定義兩個值,test1test2
  • emits中定義兩個事件,update:test1update:test2
<template>
  <input
    type="text"
    @input="emit('update:modelValue', $event.target.value)"
    :value="props.modelValue"
  />
  <input
    type="text"
    @input="emit('update:test1', $event.target.value)"
    :value="props.test1"
  />
  <input
    type="text"
    @input="emit('update:test2', $event.target.value)"
    :value="props.test2"
  />
</template>
<script setup>
const emit = defineEmits(["update:modelValue","update:test1", "update:test2"]);
const props = defineProps({
  modelValue: String,
  test1: String,
  test2: String,
});
</script>

v-model修飾符

vue提供了一些v-model修飾符,我們可以在v-model中使用他們:

<modelComp
  v-model.trim="test"
  v-model:test1.lazy="test1"
  v-model:test2.trim.lazy="test2"
></modelComp>

在一些場景下,我們需要自己定義修飾符,來滿足我們的需求,舉個栗子:

<modelComp
  v-model.a="test"
  v-model:test1.b.c="test1"
></modelComp>

默認v-model中我們綁定了a修飾符,v-model:test1中則綁定bc兩個修飾符;

對于修飾符,我們需要滿足以下條件:

對于默認v-model來說,需要props中定義兩個值

  • modelValue
  • modelModifiers,接受修飾符key

對于自定義v-model:xxx來說,props中:

  • xxx
  • xxxModeifiers,接受修飾符key

由此,上代碼:

<template>
  <input type="text" @input="vModelInput" :value="props.modelValue" />
  <input type="text" @input="vModelTest1" :value="props.test1" />
</template>
<script setup>
const emit = defineEmits(["update:modelValue", "update:test1"]);
const props = defineProps({
  modelValue: String,
  //接受v-model的修飾符
  modelModifiers: {
    default: () => ({}),
  },
  test1: String,
  //接受v-model:test1的修飾符
  test1Modifiers: {
    default: () => ({}),
  }
});
const vModelInput = (e) => {
  let value = e.target.value
  console.log(props.modelModifiers);
  //{a:true}
  if(props.modelModifiers.a){
      //處理value值
  }
  emit("update:modelValue", value);
};
const vModelTest1 = (e) => {
  let value = e.target.value
  console.log(props.test1Modifiers);
  //{b:true,c:true}
  if(props.modelModifiers.b){
      //處理value值
  }
  if(props.modelModifiers.c){
      //處理value值
  }
  emit("update:test1", value);
};
</script>

??進階

問題背景

基礎篇中已經(jīng)講解了如何封裝一個自定義v-model的組件,可是在實際開發(fā)中,子組件中使用@input:value來綁定我們的值,會比較麻煩,有沒有更簡單的辦法呢?

我們通常想要對需要雙向綁定的子組件,直接進行v-model綁定:

<!-- 子組件 -->
<input type="text" v-model="xxx" />

問題來了,在子組件中接受到父組件的傳值時,xxx我們應該綁定誰?直接綁定props.modelValue么?

<!-- 子組件 -->
<input type="text" v-model="props.modelValue"/>

我們會得到一個錯誤:

??reactivity.esm-bundler.js:512 Set operation on key "modelValue" failed: target is readonly.

因為props是一個readonly的值(isReadonly(props) === true),所以我們不能直接這么使用

所以,我們是需要一個中間值來綁定v-model

方式一:通過watch中轉

借助內部變量綁定v-model,使用watch監(jiān)聽它,并同步數(shù)據(jù)props.xxx

<!-- 子組件 -->
<template>
  <input type="text" v-model="proxy" />
</template>
<script setup>
import { ref, watch } from "vue";
const emit = defineEmits();
const props = defineProps({
  modelValue: String,
});
const proxy = ref(props.modelValue);
watch(
  () => proxy.value,
  (v) => emit("update:modelValue",v)
);
</script>

因為有時候我們雙向綁定的可能是一個對象或者數(shù)組,因此我們可以使用watch里的deep選項來深度監(jiān)聽并同步proxy;

watch(
  () => proxy.value,
  (v) => emit("update:modelValue",v),
  {deep:true}
);

當然,props.modelValue可能存在默認值傳入,所以我們也可以加上immediate選項,使得組件在創(chuàng)建時,就直接給proxy賦上默認值;

方式二:computed的get和set

我們也可以借助computed提供的getset來進行數(shù)據(jù)同步

const proxy = computed({
  get() {
    return props.modelValue;
  },
  set(v) {
    emit("update:modelValue", v);
  },
});

??終極:封裝v-model的hooks

我們先來提取watch這種方式,將其封裝為一個hooks

<!-- 子組件 -->
<template>
  <input type="text" v-model="proxy" />
</template>
<script setup>
import { ref, watch, computed } from "vue";
const emit = defineEmits();
const props = defineProps({
  modelValue: String,
});
const proxy = ref(props.modelValue);
watch(
  () => proxy.value,
  (v) => emit("update:modelValue", v)
);
</script>

在子組件中,我們用v-modelinput上綁定了一個內部值proxy,并以props.modelValue的值初始化proxy變量(ref(props.modelValue));

watch中,我們監(jiān)聽input上的綁定值proxy,在input進行輸入其值變化時,向外分發(fā)emit('update:modelValue',v)事件,將改變的值動態(tài)傳到外部組件上

提取公用邏輯

// useVmodel1.js
import { ref, watch } from "vue";
export function useVmodel(props, emit) {
  const proxy = ref(props.modelValue);
  watch(
    () => proxy.value,
    (v) => emit("update:modelValue", v)
  );
  return proxy;
}

一個最簡單的hooks便被封裝好了;

<template>
  <input type="text" v-model="proxy" />
</template>
<script setup>
import { ref, watch, computed } from "vue";
import { useVmodel } from "./hooks/useVmodel1";
const emit = defineEmits();
const props = defineProps({
  modelValue: String,
});
const proxy = useVmodel(props, emit);
</script>

繼續(xù)抽離封裝

考慮到以下幾個點,繼續(xù)進行抽離封裝:

  • emit可以不傳,更簡潔的調用方式
  • 多個v-model:test1這種情況的事件,emit("update:xxxx")中的xxxx事件名需要提取

我們可以通過vue3提供的getCurrentInstance方法,獲取當前的組件實例,而modelValue可覆蓋,則抽取成變量:

//useVmodel2.js
import { ref, watch, getCurrentInstance } from "vue";
export function useVmodel(props, key = "modelValue", emit) {
  const vm = getCurrentInstance();
  const _emit = emit || vm?.emit;
  const event = `update:${key}`;
  const proxy = ref(props[key]);
  watch(
    () => proxy.value,
    (v) => _emit(event, v)
  );
  return proxy;
}

好了,現(xiàn)在我們可以更簡單的調用我們的hooks了:

<!-- 子組件 childModel -->
<template>
  <input type="text" v-model="modelValue" />
  <input type="text" v-model="test" />
</template>
<script setup>
import { useVmodel } from "./hooks/useVmodel2";
const emit = defineEmits();
const props = defineProps({
  modelValue: String,
  test: String,
});
const modelValue = useVmodel(props);
const test = useVmodel(props, "test");
</script>
<!-- 父組件 -->
<template>
  <Model v-model="modelValue" v-model:test="test" />
</template> 
<script setup>
import { ref, watch } from "vue";
import Model from "./childModel.vue";
const modelValue = ref("");
const test = ref("");
</script>

最后

封裝computed這種方式本文暫不贅述,小伙伴們可進行自行封裝抽離,以上就是vue3自定義封裝v-model的hooks示例詳解的詳細內容,更多關于vue3封裝v-model hooks的資料請關注腳本之家其它相關文章!

相關文章

  • vue.js數(shù)據(jù)加載完成前顯示原代碼{{代碼}}問題及解決

    vue.js數(shù)據(jù)加載完成前顯示原代碼{{代碼}}問題及解決

    這篇文章主要介紹了vue.js數(shù)據(jù)加載完成前顯示原代碼{{代碼}}問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • vue-dplayer視頻播放器組件的使用詳解

    vue-dplayer視頻播放器組件的使用詳解

    Vue-DPlayer是一個易于使用、高性能的基于Vue.js的視頻播放器組件,這篇文章將為大家詳細介紹一下vue-dplayer視頻播放器組件的安裝與使用,需要的小伙伴可以參考下
    2023-09-09
  • 詳解vue-cli 腳手架項目-package.json

    詳解vue-cli 腳手架項目-package.json

    本篇文章主要介紹了詳解vue-cli 腳手架項目-package.json,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • 在vue中使用v-bind:class的選項卡方法

    在vue中使用v-bind:class的選項卡方法

    今天小編就為大家分享一篇在vue中使用v-bind:class的選項卡方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • 將vue項目打包成電腦端應用.exe的完整步驟

    將vue項目打包成電腦端應用.exe的完整步驟

    最近接了個小活,其中甲方要求把vue項目打包成exe安裝在windows上,其中有也會出現(xiàn)一些小問題和優(yōu)化,特此記錄,這篇文章主要給大家介紹了關于將vue項目打包成電腦端應用.exe的完整步驟,需要的朋友可以參考下
    2023-10-10
  • 為vue中的data賦值computed計算屬性后,出現(xiàn)undefined原因及解決

    為vue中的data賦值computed計算屬性后,出現(xiàn)undefined原因及解決

    這篇文章主要介紹了為vue中的data賦值computed計算屬性后,出現(xiàn)undefined原因及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • vue3的父傳子問題(單項數(shù)據(jù)流)

    vue3的父傳子問題(單項數(shù)據(jù)流)

    這篇文章主要介紹了vue3的父傳子問題(單項數(shù)據(jù)流),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • vue3中的reactive、readonly和shallowReactive使用詳解

    vue3中的reactive、readonly和shallowReactive使用詳解

    在 Vue3 中,可以使用 shallowReactive 函數(shù)創(chuàng)建一個淺層響應式對象,它接收一個普通對象作為參數(shù),返回一個淺層響應式代理對象,本文給大家介紹vue3中的reactive、readonly和shallowReactive使用,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Vue監(jiān)視數(shù)據(jù)的原理詳解

    Vue監(jiān)視數(shù)據(jù)的原理詳解

    這篇文章主要為大家詳細介紹了Vue監(jiān)視數(shù)據(jù)的原理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境

    Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境

    這篇文章主要為大家介紹了Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08

最新評論

大连市| 英吉沙县| 蓬溪县| 交口县| 永丰县| 南阳市| 康平县| 平顶山市| 蓬莱市| 清水县| 来凤县| 铜山县| 施秉县| 高安市| 阳春市| 扶风县| 兖州市| 武隆县| 沙河市| 来安县| 鄂州市| 左权县| 肥乡县| 清镇市| 邵东县| 三亚市| 永春县| 南京市| 磴口县| 甘德县| 宜宾市| 射洪县| 新河县| 武功县| 漠河县| 镇远县| 文化| 祁阳县| 岢岚县| 石阡县| 通江县|