溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue項目中常用的實用技巧總結(jié)

發(fā)布時間:2021-07-07 17:23:01 來源:億速云 閱讀:135 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Vue項目中常用的實用技巧總結(jié)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Vue項目中常用的實用技巧總結(jié)”吧!

目錄
  • 前言

  • 1. 使用 $attrs 和 $listeners 進(jìn)行多層級的數(shù)據(jù)和事件傳遞

  • 2. 實現(xiàn)數(shù)據(jù)的雙向綁定,方便維護(hù)數(shù)據(jù)

    • 使用 .sync 實現(xiàn) Prop 的“雙向綁定”

    • 使用 model 選項

  • 3. 使用 Mixins

    • 4. 使用動態(tài)組件去懶加載組件

      • 5. 在組件作用域內(nèi)的 CSS 中使用 ::v-deep  修改組件樣式

        • 6. 使用裝飾器優(yōu)化代碼

          • 7. 利用 require.context 去獲取項目目錄信息

            • 總結(jié)

              • 引用

                前言

                在 Vue 項目開發(fā)中,很容易產(chǎn)生一些問題,比如代碼重復(fù)、繁雜等,其實 Vue 項目開發(fā)中有很多技巧可以使用,本文將列出一些簡單且很好用的幾個技巧,幫助我們寫出漂亮的代碼。用到的技術(shù)棧是 Vue2.0 + TypeScript +  vue-property-decorator + ElementUI。將用到以下幾個技巧:

                • 使用 $attrs 和 $listeners 進(jìn)行多層級的數(shù)據(jù)和事件傳遞

                • 實現(xiàn)數(shù)據(jù)的雙向綁定,方便維護(hù)數(shù)據(jù)

                • 使用 Mixins

                • 使用動態(tài)組件去懶加載組件

                • 在組件作用域內(nèi)的 CSS 中使用 ::v-deep  修改組件樣式

                • 使用裝飾器優(yōu)化代碼

                • 利用 require.context 去獲取項目目錄信息

                1. 使用 $attrs 和 $listeners 進(jìn)行多層級的數(shù)據(jù)和事件傳遞

                先聊聊如何傳遞 Prop,可以分為靜態(tài)和動態(tài)的 Prop:

                <!-- 靜態(tài)的prop -->
                <blog-post title="My journey with Vue"></blog-post>
                <!-- 動態(tài)的prop -->
                <blog-post v-bind:title="post.title"></blog-post>
                <!-- 動態(tài)的prop傳遞可以簡寫成 -->
                <blog-post :title="post.title"></blog-post>
                <!-- 需要傳遞多個prop的時候,可以一起寫在v-bind上 -->
                <blog-post v-bind="{ editable, title: post.title}"></blog-post>

                了解了 Props 的傳遞方式,在看看官方文檔是怎么定義 $attrs 的,  在尤大大的文檔中這樣介紹了 $attrs:

                $attrs:  包含了父作用域中不作為 prop 被識別 (且獲取) 的 attribute 綁定 class 和 style 除外)。當(dāng)一個組件沒有聲明任何 prop 時,這里會包含所有父作用域的綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件

                $attrs  包含了傳入到父作用域中沒有在 props 聲明的其他 props,因此我們可以用 $attrs 去代替那些父組件中不需要的而子組件需要的 props, 通過 v-bind="$attrs" 統(tǒng)一傳遞給后代。這樣就避免了一個個聲明然后再一個個傳遞。

                <blog-post v-bind="$attrs"></blog-post>

                上面這一行代碼就通過 v-bind="$attrs" 的方式將本作用域中不作為 prop 的其他屬性傳遞給了 blog-post 組件。

                父組件通過 $attrs 傳遞給后代組件后,后代組件如果想通過觸發(fā)事件來更新父組件狀態(tài)該如何處理?如果一級一級地往上 emit 事件,會不會弄得代碼太繁瑣復(fù)雜了?在 Vue 中可以通過 $listeners 解決這個問題,先看看官方文檔關(guān)于  $listeners 的說明:

                包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器。它可以通過 v-on="$listeners" 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時非常有用。

                文檔中說了 $listeners 包含了父作用域中的事件監(jiān)聽器。意思就是 $listeners 表示了父組件中的事件監(jiān)聽器集合,只要是觸發(fā)父組件的事件,而不是自己的,就可以用一個 v-on="$listeners"表示。

                <!-- 父組件(第一層組件) -->
                <componentA @on-change="handleChange" v-bind="{ editable, title: post.title}" />
                
                <!-- 中間層的組件 -->
                <Child v-bind="$attrs" v-on="$listeners"/>
                
                <!-- 數(shù)據(jù)傳遞的目標(biāo)組件,事件觸發(fā)的組件 -->
                <div @click="handleClick">{{ title }} </div>
                <script>
                  export default {
                    props: {
                      title: String
                    }
                    handleClick() {
                      this.$emit('on-change', 'New Title');
                    }
                  }
                </script>

                上面的代碼示例中,中間層的組件內(nèi)通過 v-bind="$attrs" 將其余的 Prop 傳遞給了 Child 組件,再通過 v-on="$listeners" 綁定父作用域中的事件監(jiān)聽器,一旦 emit 就會傳給了父組件。

                2. 實現(xiàn)數(shù)據(jù)的雙向綁定,方便維護(hù)數(shù)據(jù)

                有很多這樣的場景,父組件需要傳遞數(shù)據(jù)給子組件,且在子組件觸發(fā)數(shù)據(jù)更新的時候,馬上反饋給父組件,父組件數(shù)據(jù)更新,單向數(shù)據(jù)流向子組件,最后子組件更新。通常情況用 props + $emit 的方式去更新狀態(tài),但是這種處理方式有點笨拙,且不易維護(hù),所以可以通過實現(xiàn)數(shù)據(jù)的“雙向綁定”來提高代碼的可維護(hù)性??梢酝ㄟ^這以下方式去實現(xiàn):

                使用 .sync 實現(xiàn) Prop 的“雙向綁定”

                在 v-bind prop的時候添加  .sync 修飾符,賦新值的時候用  this.$emit('update:propName', newValue)

                <!-- .sync是 v-on:update這種模式的一種縮寫 -->
                <Child v-on:update:title="title" />
                <!-- 相當(dāng)于 -->
                <Child :title.sync="title" />

                如果要更新上述代碼中的 title 值,只需要   this.$emit('update:title', '新標(biāo)題'),完成數(shù)據(jù)更新。

                使用 model 選項

                model 是2.2.0+ 新增的選項,一個組件上的 v-model 默認(rèn)會利用名為 value  的 Prop  和名為 input 的事件, 而 model 選項可以規(guī)定 Prop 名稱和事件名稱來實現(xiàn) v-model,好處是在實現(xiàn) v-model 的同時也避免了 Prop 和事件名的沖突。

                <!-- 父組件 -->
                <Model v-model="checked"/>
                
                <!-- Model組件 -->
                <div @click="handleClick">
                  <p>自定義組件的 v-model</p>
                  checked {{checked}}
                </div>
                <script lang="ts">
                export default {
                  model: {
                    prop: 'checked',
                    event: 'change'
                  },
                  props: {
                    checked: Boolean
                  },
                  methods: {
                    handleClick() {
                      this.$emit('change', !this.checked);
                    }
                  }

                在上述代碼中,只需要在 model 選項中添加 prop 和 event,就可以實現(xiàn)了 v-model。而在 Vue + TS 項目中 vue-property-decorator 中提供了 Model 的裝飾器,需要這么寫:

                @Model('change', { type: Boolean }) readonly checked!: boolean
                handleClick() {
                  this.$emit('change', !this.checked);
                }

                只需要通過 .sync 和 model 就可以實現(xiàn)數(shù)據(jù)的“雙向綁定”,這樣書寫代碼可以一定程度上減少我們的代碼,而且另代碼變得更優(yōu)雅且可維護(hù)。

                3. 使用 Mixins

                Mixins 可以用于兩種場景:

                1. 利用它去抽取成組件內(nèi)的公共代碼加強(qiáng)代碼復(fù)用,不要在全局內(nèi)套來套去,最好在組件內(nèi)或者頁面中使用。

                2. 利用它去分離功能點,有時候會遇到一種情況,就是業(yè)務(wù)功能很多導(dǎo)致寫起來的 Vue 文件行數(shù)很多,導(dǎo)致代碼很難以維護(hù),功能點代碼不好追蹤??梢酝ㄟ^抽取功能代碼的方式,讓這個龐大的 Vue 文件更好維護(hù)。

                首先寫一個公共的 mixin 文件, 把高復(fù)用的狀態(tài)和函數(shù)寫進(jìn)去。

                export default class CommonMixins extends Vue{
                    public paginations = {
                        pageSize: 20,
                        total: 0,
                        currentPage: 1,
                    }
                    handleChangePageSize (pageSize: number, cb: Function) {
                        this.paginations.pageSize = pageSize;
                        cb();
                    }
                    handleChangePageNum (currentPage: number, cb: Function) {
                        this.paginations.currentPage = currentPage;
                        cb();
                    }
                }

                vue-property-decorator 提供了 Mixins 的裝飾器,在業(yè)務(wù)頁面中引入 Mixin 只需要往里 Mixins 傳入 , 可以傳多個,表示混入多個 Mixin。

                <script lang="ts">
                import { Component, Mixins } from 'vue-property-decorator';
                import CommonMixins from "./common-mixin";
                import PermissionMixins from "./permission-mixin";
                @Component({})
                export default class Parent extends Mixins(CommonMixins, PermissionMixins) {
                }
                </script>

                如果只需要一個的話,也可以直接繼承

                <script lang="ts">
                import { Component, Mixins } from 'vue-property-decorator';
                import CommonMixins from "./common-mixin";
                @Component({})
                export default class Parent extends CommonMixins {
                }
                </script>

                在遇到功能點多,代碼量大的頁面時,我們可以利用 Mixin 抽離一些功能點,通過文件去管理這些功能,這樣會比較方便去管理代碼。

                4. 使用動態(tài)組件去懶加載組件

                組件在加載都是同步的,但當(dāng)頁面內(nèi)容很多,有些組件并不需要一開始就加載出來的比如彈窗類的組件,這些就可以用動態(tài)組件,當(dāng)用戶執(zhí)行了某些操作后再加載出來,這樣可以提高主模塊加載的性能, 在 Vue 中可以使用 component 動態(tài)組件, 依 is 的值,來決定哪個組件被渲染。

                <template>
                  <div>
                    主頁面 <br/>
                    <button @click="handleClick1">點擊記載組件1</button><br/>
                    <button @click="handleClick2">點擊記載組件2</button><br/>
                    <component :is="child1"></component>
                    <component :is="child2"></component>
                  </div>
                </template>
                <script lang="ts">
                import { Component, Vue } from 'vue-property-decorator';
                @Component({})
                export default class AsyncComponent extends Vue {
                  public child1:Component = null;
                  public child2:Component = null;
                  handleClick1() {
                    this.child1 = require('./child1').default;
                  }
                  handleClick2() {
                    this.child2 = require('./child2').default;
                  }
                }
                </script>

                示例代碼中,只有當(dāng)點擊的時候才會去加載組件。component 還可以配合 v-show 去控制顯示和隱藏,這樣這個component 只會 mounted 一次,優(yōu)化性能。

                5. 在組件作用域內(nèi)的 CSS 中使用 ::v-deep  修改組件樣式

                有很多場景想更改 UI 組件樣式,然后怕影響別人的使用,加上 scoped 后又不能生效,可以使用  ::v-deep 深度作用選擇器去修改組件作用域內(nèi)的 CSS 的樣式。在 CSS 中我們可以使用 >>> 操作符,但在預(yù)處理器中的寫法就要用 /deep/ 或 ::v-deep。

                <style scoped>
                >>> .ivu-tabs-tabpane {
                        background: #f1f1f1;
                    }
                </style>
                <style lang="scss" scoped>
                /deep/ .ivu-tabs-tabpane {
                        background: #f1f1f1;
                    }
                </style>
                <style lang="scss" scoped>
                ::v-deep .ivu-tabs-tabpane {
                        background: #f1f1f1;
                    }
                </style>

                ::v-deep 和 /deep/ 作用是一樣的,但不推薦使用 /deep/, 在 Vue3.0 中將不支持 /deep/ 這種寫法。

                6. 使用裝飾器優(yōu)化代碼

                裝飾器增加了代碼的可讀性,清晰地表達(dá)了意圖,而且提供一種方便的手段,增加或修改類的功能,比如給類其中的方法提供防抖的功能。

                import debounce from 'lodash.debounce';
                export function Debounce(delay: number, config: object = {}) {
                  return (target: any, prop: string) => {
                    return {
                      value: debounce(target[prop], delay, config),
                    };
                  };
                }

                這樣的好處是使用起來非常方便,另外增加了代碼的可讀性。

                @Debounce(300)
                onIdChange(val: string) {
                  this.$emit('idchange', val);
                }

                7. 利用 require.context 去獲取項目目錄信息

                關(guān)于 require.context,webpack 文檔是這么描述的:

                可以給這個函數(shù)傳入三個參數(shù):一個要搜索的目錄,一個標(biāo)記表示是否還搜索其子目錄, 以及一個匹配文件的正則表達(dá)式。
                webpack 會在構(gòu)建中解析代碼中的 require.context() 。如果想引入一個文件夾下面的所有文件,或者引入能匹配一個正則表達(dá)式的所有文件,這個功能就會很有幫助

                根據(jù)這個提示,我們可以引用到一個文件夾下面的所有文件,由此可以利用獲取的文件信息去做一些操作,比如在注冊組件的時候,原本我們注冊組件的時候需要一個個引入并且一個個注冊,而且后面想加新的,又要再寫上,現(xiàn)在可以通過 require.context 去優(yōu)化這一段代碼。

                // import WmsTable from './wms-table/table/index';
                import Table from './table/index.vue';
                import CustomHooks from './custom-hooks/custom-hooks-actions/index';
                import SFilter from './s-filter/filter-form';
                import WButton from './button/index';
                import CreateForm from './createForm/create-form/CreateForm.vue';
                import Action from './table/action-table-column.vue';
                import DetailItem from './detail-item.vue';
                
                
                Vue.component('w-filter', SFilter);
                Vue.component('w-button', WButton);
                Vue.component('custom-hooks', CustomHooks);
                Vue.component('create-form', CreateForm);
                Vue.component('w-table', Table);
                Vue.component('w-table-action', Action);
                Vue.component('zonetime-date-picker', ZonetimeDatePicker);
                Vue.component('detail', DetailItem);

                注冊全局組件的時候,不需要一個一個 import,和一個個去注冊,使用 require.context 可以自動導(dǎo)入模塊,這樣的好處在于,當(dāng)我們新建一個組件,不用自己再去手寫注冊,而在一開始就幫我們自動完成。

                const contexts = require.context('./', true, /\.(vue|ts)$/);
                export default {
                  install (vm) {
                    contexts.keys().forEach(component => {
                      const componentEntity = contexts(component).default;
                      if (componentEntity.name) {
                        vm.component(componentEntity.name, componentEntity);
                      }
                    });
                  }
                };

                總結(jié)

                本文介紹了在 Vue 實戰(zhàn)中經(jīng)常用到的一些技巧,這些技巧的目的都是為了提升開發(fā)效率,比如簡單地實現(xiàn)雙向數(shù)據(jù)綁定和數(shù)據(jù)跨級傳遞等,另外也可以提高代碼的可維護(hù)性、可讀性,比如很實用的裝飾器和利用 Mixin 拆分代碼和管理功能點。

                到此,相信大家對“Vue項目中常用的實用技巧總結(jié)”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

                向AI問一下細(xì)節(jié)

                免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

                vue
                AI