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

Vue利用computed解決單項數(shù)據(jù)流的問題

 更新時間:2023年08月27日 09:05:50   作者:子辰Web草廬  
Vue是一個非常流行和強(qiáng)大的前端框架,它讓我們可以用簡潔和優(yōu)雅的方式來構(gòu)建用戶界面,但是,Vue也有一些需要注意和掌握的細(xì)節(jié)和技巧,今天我們來分享一個Vue中非常經(jīng)典的問題,也是一個非常實用的技巧,Vue利用computed解決單項數(shù)據(jù)流,需要的朋友可以參考下

Vue 是一個非常流行和強(qiáng)大的前端框架,它讓我們可以用簡潔和優(yōu)雅的方式來構(gòu)建用戶界面。

但是,Vue 也有一些需要注意和掌握的細(xì)節(jié)和技巧。

今天我們來分享一個 Vue 中非常經(jīng)典的問題,也是一個非常實用的技巧。

這個問題涉及到 Vue 的一個核心特性:單向數(shù)據(jù)流。

讓人頭痛的單向數(shù)據(jù)流

如果你不了解單向數(shù)據(jù)流是什么,或者你不知道如何在 Vue 中正確地使用它,那么請繼續(xù)往下看,我保證你會有所收獲。

這個問題在你使用 Vue 去封裝一個表單組件的時候,就會非常明顯地體現(xiàn)出來。

表單組件是前端開發(fā)中非常常見和重要的一種組件,它可以讓用戶輸入和提交數(shù)據(jù),從而實現(xiàn)各種功能。

比如說,我們這里我們封裝了一個搜索條的簡單示例,來以小見大:

這個組件很簡單:

<template>
  <el-input v-model="modelValue.keyword" :placeholder="modelValue.placeholder">
    <template #prepend>
      <el-select v-model="modelValue.selectedValue" placeholder="Select" style="width: 85px">
        <el-option v-for="item in modelValue.options" :key="item.value" :label="item.label" :value="item.value"></el-option>
      </el-select>
    </template>
    <template #append>
      <el-button :icon="Search" />
    </template>
  </el-input>
</template>
<script setup>
  import { Search } from '@element-plus/icons-vue';	
  const props = defineProps({
    modelValue: {
      type: Object,
      required: true,
    },
  });
</script>

通過 props 傳入一個對象,這個對象里包括所以我們需要的數(shù)據(jù),比如:占位符 placeholder、文本框的輸入值 keyword、下拉框的選中值 selectedValue、下拉框的選項值 options。

這些數(shù)據(jù)都給我們,我們將這個界面渲染出來。

那么父組件是這樣的:

<template>
  <div>
    <SearchBar v-model="searchData" />
  </div>
</template>
<script setup>
import { ref } from 'vue';
import SearchBar from './components/SearchBar.vue';
const searchData = ref({
  keyword: '',
  placeholder: '請輸入你要查詢的關(guān)鍵字',
  options: [
    { label: '視頻', value: 'video' },
    { label: '文章', value: 'article' },
    { label: '用戶', value: 'user' },
  ],
  selectedValue: 'video',
});
</script>

父組件在使用時自然而然會傳遞一些數(shù)據(jù),這個數(shù)據(jù)也很簡單,一看就明白了。

我們使用 v-model 來綁定數(shù)據(jù),這樣只要這個組件改動了這個數(shù)據(jù),那么我們父組件就能收到通知,能夠?qū)@個數(shù)據(jù)做相應(yīng)的變化。

這個組件結(jié)構(gòu)是非常清晰的,就是這么一種結(jié)構(gòu):

這都是基礎(chǔ)知識,沒什么好說的,但是實際情況是什么樣的呢?

現(xiàn)在的問題是子組件的文本框使用的是 v-model 綁定數(shù)據(jù),但是這一綁定就把父組件傳遞的屬性它里邊的數(shù)據(jù)綁定進(jìn)去了,那現(xiàn)在就變成了這種結(jié)構(gòu)了:

于是這種情況就打破了單項數(shù)據(jù)流,打破單向數(shù)據(jù)流是要付出代價的,打破一次你的工程就距離“ shǐ山”更進(jìn)一步。

那么我們希望不要打破單項數(shù)據(jù)流,回歸到正常的模式,那該怎么做呢?

解決辦法

最笨的辦法就是在子組件里不使用 v-model ,不然的話文本框一變這個父組件的數(shù)據(jù)就會跟著變,所以我們把 v-model 拆成原始的形式。

<template>
  <!-- 將 v-model 拆分 -->
  <el-input 
    :modelValue="modelValue.keyword" 
    @update:modelValue="handleKeywordChange" 
    :placeholder="modelValue.placeholder">
    <!-- etc... -->
  </el-input>
</template>
<script setup>
  // etc...
  // 定義一個 emit 事件
  const emit = defineEmits(['update:modelValue'])
  function handleKeywordChange(val) {
    console.log('val >>> ', val)
    // 觸發(fā)子組件的 update:modelValue 事件
    emit('update:modelValue', {
      // 因為這里我們只是修改了 keyword 的值
      // 所以我們將 props.modelValue 展開之后,單獨將 keyword 的值賦值為新的值
      ...props.modelValue,
      keyword: val
    })
  }
</script>

一個是 modelValue 用于綁定值。

另外一個是 update:modelValue 用于監(jiān)控這個組件的 update 事件,當(dāng)事件觸發(fā)的時候調(diào)用 handleKeywordChange 函數(shù)。

handleKeywordChange 函數(shù),要做的事情就是去觸發(fā)子組件 update:modelValue 事件,通知父組件去更改數(shù)據(jù),所以我們定義了一個 emit 事件,數(shù)據(jù)變化的時候調(diào)用 emit 返回更新的數(shù)據(jù)。

雖然說這樣很麻煩,但是我們保證了單項數(shù)據(jù)流了。

那么有沒有一種簡介的方法呢?

其實面對這個問題,Vue 官方也好還是一些第三方庫,比如:vueuse 他們都有一種解決辦法,就是使用計算屬性去給它包一層:

父組件的數(shù)據(jù)傳遞過來之后,并沒有直接綁定到內(nèi)部的文本框,而是在中間加了一個計算屬性,然后用這個計算屬性去綁定這個文本框,這個計算屬性要同時設(shè)置它的 getter 和 setter,當(dāng)讀這個計算屬性的時候,讀的其實就是 modelValue 里的東西,所以讀是沒問題的。

但是這個文本框由于綁定了 v-model 這個文本框會變動的,變動的話改的就是這個計算屬性,也就觸發(fā)了這個計算屬性的 setter,那么在 setter 里邊我們就可以寫代碼去觸發(fā)這個 emit 事件。

這樣就簡化了代碼,同時又保證了單項數(shù)據(jù)流,官方就是這樣建議的,我們?nèi)L試一下好不好用:

<template>
  <!-- 將計算屬性綁定到文本框之上 -->
  <el-input v-model="keyword" :placeholder="modelValue.placeholder">
  <!-- etc... -->
  </el-input>
</template>
<script setup>
// etc...
// 定義一個 emit 事件
const emit = defineEmits(['update:modelValue'])
// 寫一個計算屬性,同時提供 get 和 set 
const keyword = computed({
  // 讀取的時候直接返回讀取的值
  get() {
    return props.modelValue.keyword;
  },
  // 當(dāng)修改的時候我們執(zhí)行 emit 的操作
  set(val) {
    console.log('val >>> ', val)
    emit('update:modelValue', {
      ...props.modelValue,
      keyword: val
    })
  }
})
</script>

這樣我們就不需要拆分 v-model 了,雖然有所簡化,但是簡化的并不多,因為下拉框的選中值 selectedValue、下拉框的選項值 options 都要做成計算屬性。

那么我們能不能想一個辦法,就是說這個計算屬性不要只返回給我們一個字段,而是字節(jié)把整個對象返回,像這種模式:

<template>
  <!-- 綁定的時候直接綁定計算屬性上的字段 -->
  <el-input v-model="model.keyword" :placeholder="model.placeholder">
    <template #prepend>
      <el-select v-model="model.selectedValue" placeholder="Select" style="width: 85px">
        <el-option v-for="item in model.options" :key="item.value" :label="item.label" :value="item.value"></el-option>
      </el-select>
    </template>
    <template #append>
      <el-button :icon="Search" />
    </template>
  </el-input>
</template>
<script setup>
  import { Search } from '@element-plus/icons-vue';
  const props = defineProps({
    modelValue: {
      type: Object,
      required: true,
    },
  });
  const emit = defineEmits(['update:modelValue'])
  const model = computed({
    get() {
      return props.modelValue;
    },
    set(val) {
      emit('update:modelValue', val)
    }
  })
</script>

將來修改計算屬性的時候就觸發(fā)事件,綁定值得到話就綁定計算屬性的字段。

這樣就能通過一個計算屬性屬性,搞定全部的問題了。

但是現(xiàn)在修改是無效的,因為綁定的是 model 里的一個字段,并不是 model,所以修改的也是 model 的字段,所以并不會觸發(fā) set 的更新:

因為只有改動了 model 本身的時候,它才會去運行 setter,改動的是某一個字段就不會運行 setter,那現(xiàn)在就不好辦了。

但是,轉(zhuǎn)折來了,有一個奇招可以解決這個問題:

const model = computed({
  get() {
    // 我們這里返回一個代理對象,代理 props.modelValue 這個屬性
    return new Proxy(props.modelValue, {
      // 因為這是一個代理對象,那么將來修改代理對象的某個值時
      // 就會運行這個 set 函數(shù)
      // 函數(shù)中可以拿到 
      //   obj:改動的對象 
      //   name:改動的屬性名 
      //   val:改動的屬性值
      set(obj, name, val) {
        console.log('Emit >>> ', name, val)
        // 當(dāng)我們想改的一個對象的屬性時并不去真正的修改
        // 而是在這里也觸發(fā) emit,然后生成一個新的對象
        emit('update:modelValue', {
          ...obj, // 展開以前對象的值
          [name]: val // 將其中的修改的屬性修改為新的值
        })
        return true; // 最后返回一個 true
      },
    });
  },
  set(val) {
    emit('update:modelValue', val)
  }
})

這就正常的觸發(fā)了事件函數(shù),那么這樣一來代碼就進(jìn)一步得到簡化了。

我們使用一個計算屬性屬性就可以替代里邊的所有字段,特別是在一個大表單里,有很多很多的字段,這一招非常的好用。

在子組件里無論有多少個文本框選項,都去用這個計算屬性去綁定就可以了。

既不會打破單向數(shù)據(jù)流,而且實現(xiàn)代碼也非常少。

擴(kuò)展

其實我們還可以把這個問題擴(kuò)展一下,因為我們在實際開發(fā)中,封裝表單是一件常事,所以在每一次封裝表單的都是都去寫一次這樣的代碼有點繁瑣,我們可以把它提出去,寫成一個輔助函數(shù)。

import { computed } from 'vue';
/**
 * props:屬性對象
 * propName:要做成計算屬性的名字
 * emit:emit 函數(shù)
 */
export function useVModel(props, propName, emit) {
  return computed({
    get() {
      return new Proxy(props[propName], {
        set(obj, name, val) {
          console.log('emit', name, val);
          emit('update:' + propName, {
            ...obj,
            [name]: val,
          });
          return true;
        },
      });
    },
    set(val) {
      emit('update:' + propName, val);
    },
  });
}

這樣就可以通過一個輔助函數(shù)幫我們把要做的事情實現(xiàn),使用起來就非常的舒服了:

<template>
  <el-input v-model="model.keyword" :placeholder="model.placeholder">
    <template #prepend>
      <el-select v-model="model.selectedValue" placeholder="Select" style="width: 85px">
        <el-option v-for="item in model.options" :key="item.value" :label="item.label" :value="item.value"></el-option>
      </el-select>
    </template>
    <template #append>
      <el-button :icon="Search" />
    </template>
  </el-input>
</template>
<script setup>
  import { Search } from '@element-plus/icons-vue';
  import { useVModel } from './useVModel'; // 導(dǎo)入輔助函數(shù)
  const props = defineProps({
    modelValue: {
      type: Object,
      required: true,
    },
  });
  const emit = defineEmits(['update:modelValue']);
  // 調(diào)用函數(shù)將需要的參數(shù)傳遞進(jìn)去
  const model = useVModel(props, 'modelValue', emit);
</script>

以后無論是非常簡單的表單封裝,還是非常龐大的表單封裝,都可以用這么幾行代碼來解決問題了。

既保護(hù)了單項數(shù)據(jù)流,又簡化了代碼的書寫,在實際開發(fā)中用起來是非常的好用。

總結(jié)

通過這篇文章,你應(yīng)該對 Vue 的單向數(shù)據(jù)流有了更深入的理解和掌握。

你學(xué)習(xí)了如何在封裝表單組件時避免打破單向數(shù)據(jù)流,以及如何使用計算屬性和輔助函數(shù)來簡化和優(yōu)化你的代碼。

這些技巧不僅能讓你寫出更高質(zhì)量和更易維護(hù)的代碼,還能讓你提高你的開發(fā)效率和水平。

希望你能在你的項目中運用這些技巧,讓你的 Vue 組件更加完美和高效!

以上就是Vue利用computed解決單項數(shù)據(jù)流的問題的詳細(xì)內(nèi)容,更多關(guān)于Vue computed解決單項數(shù)據(jù)流的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue3實現(xiàn)provide/inject的示例詳解

    Vue3實現(xiàn)provide/inject的示例詳解

    Vue3 的 Provide / Inject 的實現(xiàn)原理其實就是巧妙利用了原型和原型鏈來實現(xiàn)的。本文將通過示例為大家介紹下provide/inject的具體實現(xiàn),需要的可以參考一下
    2022-11-11
  • vue?elementui二次封裝el-table帶插槽問題

    vue?elementui二次封裝el-table帶插槽問題

    這篇文章主要介紹了vue?elementui二次封裝el-table帶插槽問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • element如何初始化組件功能詳解

    element如何初始化組件功能詳解

    Element UI是一套基于Vue的桌面端組件庫,封裝好了很多常用的UI組件,下面這篇文章主要給大家介紹了關(guān)于element如何初始化組件功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 詳解使用vue實現(xiàn)tab 切換操作

    詳解使用vue實現(xiàn)tab 切換操作

    這篇文章主要介紹了詳解使用vue實現(xiàn)tab操作,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Vue通知提醒框(Notification)圖文詳解

    Vue通知提醒框(Notification)圖文詳解

    最近有個項目需求就是在客戶端的右上角要實時展示提醒消息,下面這篇文章主要給大家介紹了關(guān)于Vue通知提醒框(Notification)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Vue?UI創(chuàng)建項目詳細(xì)步驟

    Vue?UI創(chuàng)建項目詳細(xì)步驟

    本文主要介紹了Vue?UI創(chuàng)建項目詳細(xì)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • vue前端開發(fā)層次嵌套組件的通信詳解

    vue前端開發(fā)層次嵌套組件的通信詳解

    vue通過provide & inject兩個關(guān)鍵字完成父組件向子孫組件直接傳值,很像子類能夠使用父類的屬性一樣方便。provide & inject一般用于多層之間的傳值,兩層之間還是使用props進(jìn)行
    2021-10-10
  • vue跨域處理方式(vue項目中baseUrl設(shè)置問題)

    vue跨域處理方式(vue項目中baseUrl設(shè)置問題)

    這篇文章主要介紹了vue跨域處理方式(vue項目中baseUrl設(shè)置問題),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue實現(xiàn)兩個區(qū)域滾動條同步滾動

    vue實現(xiàn)兩個區(qū)域滾動條同步滾動

    這篇文章主要為大家詳細(xì)介紹了vue實現(xiàn)兩個區(qū)域滾動條同步滾動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • 詳細(xì)聊聊Vue的混入和繼承

    詳細(xì)聊聊Vue的混入和繼承

    混入(mixin)是一種非常靈活的方式,用來分發(fā)Vue組件中可復(fù)用的功能,一個混入對象可以包含任意組件選項,下面這篇文章主要給大家介紹了關(guān)于Vue混入和繼承的相關(guān)資料,需要的朋友可以參考下
    2021-09-09

最新評論

咸丰县| 海淀区| 达尔| 揭阳市| 定西市| 吉首市| 运城市| 类乌齐县| 莎车县| 岑溪市| 札达县| 道孚县| 霍林郭勒市| 乌海市| 滨海县| 延吉市| 泸溪县| 闽侯县| 任丘市| 博客| 锦州市| 许昌县| 元朗区| 潼关县| 桃源县| 柳河县| 墨竹工卡县| 斗六市| 台北市| 沾化县| 嘉峪关市| 东方市| 高密市| 临澧县| 嵊泗县| 洪雅县| 兰西县| 淮阳县| 永川市| 大新县| 武威市|