欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue項目之ES6裝飾器在項目實戰(zhàn)中的應(yīng)用

 更新時間:2022年06月08日 16:06:49   作者:檸檬百香果  
作為一個曾經(jīng)的Java?coder,當?shù)谝淮慰吹絡(luò)s里面的裝飾器Decorator,就馬上想到了Java中的注解,當然在實際原理和功能上面,Java的注解和js的裝飾器還是有很大差別的,這篇文章主要給大家介紹了關(guān)于Vue項目之ES6裝飾器在項目實戰(zhàn)中應(yīng)用的相關(guān)資料,需要的朋友可以參考下

前言

在面向?qū)ο螅∣OP)的設(shè)計模式中,裝飾器的應(yīng)用非常多,比如在 Java 和 Python 中,都有非常多的應(yīng)用。ES6 也新增了裝飾器的功能,本文會介紹 ES6 的裝飾器的概念、作用以及在 Vue + ElementUI 的項目實戰(zhàn)中的應(yīng)用。

裝飾模式(Decorator)

裝飾模式(Decorator Pattern)允許向一個現(xiàn)有的對象添加新的功能,同時又不改變其結(jié)構(gòu)。 這種模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個包裝。 這種模式創(chuàng)建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。

優(yōu)點:

  • 不需要通過創(chuàng)建子類的方式去拓展功能(不需要子類化),這樣可以避免代碼臃腫的問題
  • 裝飾類的方法復(fù)用性很高
  • 不會影響到原對象的代碼結(jié)構(gòu)

ES6 也開始有了裝飾器,寫法與其他語言的寫法保持了統(tǒng)一,就是使用@ + 函數(shù)名的方式

ES6 裝飾器

關(guān)于ES6 裝飾器的用法可以參考阮老師的 ECMAScript 6 入門,這里從中展示一下兩種用法。

  • 類的裝飾

裝飾器方法:給對象添加一個 isTestable 屬性

function testable(isTestable) {
  return function(target) {
    target.isTestable = isTestable;
  }
}

使用的時候直接用 @ + 函數(shù)名,就可以為對象添加 isTestable 屬性了

@testable(true)
class MyTestableClass {}

MyTestableClass.isTestable // true
  • 方法的裝飾

日志裝飾器

function log(target, name, descriptor) {
  var oldValue = descriptor.value;

  descriptor.value = function() {
    console.log(`Calling ${name} with`, arguments);
    return oldValue.apply(this, arguments);
  };
  return descriptor;
}

使用裝飾器

class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

const math = new Math();

// Calling add with arguments
math.add(2, 4);

從上面兩個簡單例子可以看出,裝飾器應(yīng)用在類和類的方法上時非常的方便,有幾個優(yōu)點:

  • 語義化,可以非常清晰看出裝飾器為對象添加了什么功能
  • 裝飾器不改變原對象的結(jié)構(gòu),原對象代碼簡潔、易維護。

接下來將介紹一下我在 Vue 項目中,利用裝飾器的功能做的代碼優(yōu)化。

裝飾器應(yīng)用

目前我們了解到,裝飾器可以用來注釋或修改類和類方法。而且裝飾器使用起來非常靈活,只需要用@ + 函數(shù)名就可以修改類,可以改善代碼結(jié)構(gòu)。那么在做項目的時候,編寫代碼時是否有些功能可以抽象成裝飾器,提高復(fù)用性和改善代碼結(jié)構(gòu)。

下面的例子所用到的技術(shù)棧是 Vue2 + ElementUI + TypeScript + vue-property-decorator

Validate

在很多 UI 組件庫中,都有表單組件,其中表單重要的功能之一就是表單校驗,以 ElementUI 的 form 舉例,首先校驗表單是否通過,如果通過,就將表單數(shù)據(jù)提交給后臺,

完整的代碼如下:

submitForm() {
  this.$refs['formName'].validate(async (valid) => {
    if (valid) {
      try {
        // 調(diào)用接口
        await this.handleTest();
        this.$message.success('Submit Successfully!')
      } catch(error) {
        console.log(error);
      }
    } else {
      console.log('error submit!!');
      return false;
    }
  });
},

這里有幾個問題:

  • 這個代碼嵌套到第三層才開始進入主邏輯代碼,嵌套太多了,萬一在主要業(yè)務(wù)邏輯代碼還有很多嵌套,看起來就十分的難受。
  • 記不住,在實際開發(fā)中,一般不回特意去記觸發(fā)校驗的寫法,通常要去找文檔或者找別人的代碼,最后抄過來
  • 此功能很常用,每做一個表單都要寫一遍,重復(fù)寫這份代碼

分析上面代碼,其實主要的代碼是在 if (valid) 的條件下,而觸發(fā)表單校驗的代碼是可以抽象出來的,因為它非常常用,而且這部分代碼是無關(guān)業(yè)務(wù)邏輯的。抽象出去,可以更好地關(guān)注到業(yè)務(wù)邏輯代碼。

export function Validate(refName: string) {
  return function (target: any, name: string, descriptor: PropertyDescriptor) {
    const fn = target[name]; // 被裝飾的方法
    descriptor.value = function (...args: any[]) {
      // 將觸發(fā)校驗的代碼封裝在此
      (this as any).$refs[refName].validate((valid: boolean) => {
        if (valid) {
          fn.call(this, ...args); // 在這里調(diào)用“被裝飾的方法”
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    };
  };
}

然后在使用的時候就非常簡單了,只需要在提交方法上方寫上 @Validate('refName'),傳入表單組件的 ref 名,就可以實現(xiàn)了觸發(fā)表單校驗的功能,這樣不但大大優(yōu)化了代碼結(jié)構(gòu),而且使用起來非常簡單,?? 再也不用擔心我記不住怎么寫了。

import { Validate } from '@/utils/decorator'
export default class TestForm extends Vue {

  @Validate('formName')
  async submitForm() {
    try {
      // 調(diào)用接口
      await this.handleTest();
      this.$message.success('Submit Successfully!')
    } catch(error) {
      console.log(error);
    }
  }
}

這樣是不是好多了!特別是在業(yè)務(wù)邏輯非常復(fù)雜的場景,減少嵌套和非業(yè)務(wù)邏輯的代碼,可以讓業(yè)務(wù)邏輯代碼更加清晰。

CatchError

在寫代碼的時候經(jīng)常用 try catch 去捕獲程序中的錯誤,但是 try catch 會加深了代碼嵌套層級,而且很常用,我們可以將 try catch 的部分抽象出去,作為裝飾器的功能。

比如原來的代碼是這樣的:

export default class TestForm extends Vue {

  async submitForm() {
    try {
      await this.handleTest();
      this.$message.success('Submit Successfully!')
    } catch(error) {
      console.log(error);
    }
  }
}

try catch 的功能作為裝飾函數(shù)

export function CatchError() {
  return function (target: any, name: string, descriptor: PropertyDescriptor) {
    const fn = target[name];
    descriptor.value = async function (...args: any[]) {
      try {
        await fn.call(this, ...args);
      } catch (error) {
        console.log('error', error);
      }
    };
    return descriptor;
  };
}

使用起來后,就少了一層 try catch 的嵌套了,而且錯誤也被捕獲到了,CatchError 的命名也很好理解,并且你可以統(tǒng)一處理捕獲到的錯誤。

import { CatchError } from '@/utils/decorator'
export default class TestForm extends Vue {
  @CatchError()
  async submitForm() {
    await this.handleTest();
    this.$message.success('Submit Successfully!')
  }
}

現(xiàn)在目前有 Validate 和 CatchError 兩種裝飾器,分別是表單校驗和錯誤捕捉的作用,而表單提交都有用到這兩種功能,裝飾器可以同時滿足它,因為一個方法可以擁有多個裝飾器。

如果同一個方法有多個裝飾器,會像剝洋蔥一樣,先從外到內(nèi)進入,然后由內(nèi)向外執(zhí)行。

那么提交表單的函數(shù)最終可以被裝飾器優(yōu)化成這樣:

import { CatchError, Validate } from '@/utils/decorator'
export default class TestForm extends Vue {
  @CatchError()
  @Validate('ruleForm')
  async submitForm() {
    await this.handleTest();
    this.$message.success('Submit Successfully!')
  }
}

發(fā)現(xiàn)了沒有,提交表單的代碼中,完完全全只有業(yè)務(wù)邏輯代碼了!而其他的功能作為裝飾器引入并作用到這個方法上。而且這些裝飾功能就像是個語法糖一樣,當我下次還需要用到的時候,只需要引用在我的方法上即可,十分方便。

Confirmation

確認消息:提示用戶確認其已經(jīng)觸發(fā)的動作,并詢問是否進行此操作時會用到此對話框。這種場景十分常見,在點擊提交表單確認、點擊刪除的時候,都會彈出提示框,在用戶點擊確認后,再提交。其中最終我們只需要點擊確認那一下按鈕提交的功能,其他的功能屬于交互功能。

代碼實現(xiàn):

<template>
  <div>
    <el-button type="text" @click="handleDelete"
      >點擊打開 Message Box 提示是否刪除</el-button
    >
  </div>
</template>

<script>
import { Vue, Component } from "vue-property-decorator";
@Component
export default class DecoratorTest extends Vue {
  handleDelete() {
    this.$confirm("此操作將永久刪除該文件, 是否繼續(xù)?", "提示", {
      confirmButtonText: "確定",
      cancelButtonText: "取消",
      type: "warning",
      showCancelButton: true,
      beforeClose: (action, instance, done) => {
        if (action === "confirm") {
          instance.confirmButtonLoading = true;
          setTimeout(() => {
            done();
            setTimeout(() => {
              instance.confirmButtonLoading = false;
            }, 300);
          }, 2000);
        } else {
          done();
        }
      },
    }).then(() => {
      this.$message({
        type: "success",
        message: "刪除成功!",
      });
    });
  }
}
</script>

同樣的問題,實現(xiàn)這樣一個通用的功能,需要太多與業(yè)務(wù)邏輯無關(guān)的代碼了。代碼嵌套很深,主要業(yè)務(wù)邏輯代碼不夠清晰可見。因此對于這種通用的功能,也可以抽離出去作為裝飾器。

同樣我們把 confirm 的功能封裝起來,instance.confirmButtonLoading 控制的是按鈕的 loading,done() 是關(guān)閉彈窗的方法,這兩個功能很好用,因此我們把 instancedone 作為參數(shù)傳給被裝飾的方法。

import Vue from "vue";
interface ConfirmationConfig {
  title: string;
  message: string;
  // eslint-disable-next-line @typescript-eslint/ban-types
  options?: object;
  type?: string;
}
export function Confirmation(config: ConfirmationConfig) {
  return function (target: any, name: string, descriptor: PropertyDescriptor) {
    const fn = target[name];
    let _instance: any = null;
    descriptor.value = function (...args: any[]) {
      Vue.prototype
        .$confirm(
          config.message,
          config.title,
          Object.assign(
            {
              beforeClose: (action: string, instance: any, done: any) => {
                _instance = instance;
                if (action === "confirm") {
                  instance.confirmButtonLoading = true;
                  fn.call(this, instance, done, ...args);
                } else {
                  done();
                }
              },
            },
            config.options || {}
          )
        )
        .then(() => {
          _instance.confirmButtonLoading = false;
        });
    };
    return descriptor;
  };
}

完成封裝 confirm 之后,這么使用即可:

<template>
  <div>
    <el-button type="text" @click="handleDelete"
      >點擊打開 Message Box 提示是否刪除</el-button
    >
  </div>
</template>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import { Confirmation } from "@/utils/decorator";
@Component
export default class DecoratorTest extends Vue {
  @Confirmation({
    title: "提示",
    message: "此操作將永久刪除該文件, 是否繼續(xù)?",
  })
  handleDelete(instance: any, done: any) {
    setTimeout(() => {
      done();
      setTimeout(() => {
        instance.confirmButtonLoading = false;
        this.$message({
          type: "success",
          message: "刪除成功!",
        });
      }, 300);
    }, 2000);
  }
}
</script>

最終這樣減少了很多代碼和嵌套,并且將這個常用的功能封裝起來了,以后遇到可以直接復(fù)用起來,使用也很方便,只需要引入并傳入 title 和 message 就可以了。

總結(jié)

裝飾器可用于給類和類的方法添加功能,且不會影響原對象的結(jié)構(gòu)。可用于拓展原對象的功能。在實際業(yè)務(wù)項目開發(fā)中,常常會把功能性代碼和業(yè)務(wù)性代碼耦合在一起,可以將功能性代碼抽象出去,作為裝飾器裝飾業(yè)務(wù)功能代碼,這樣就能專注于業(yè)務(wù)組件的業(yè)務(wù)邏輯代碼,優(yōu)化代碼結(jié)構(gòu),減少代碼嵌套等。

到此這篇關(guān)于Vue項目之ES6裝飾器在項目實戰(zhàn)中應(yīng)用的文章就介紹到這了,更多相關(guān)Vue ES6裝飾器在實戰(zhàn)應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

代碼示例已經(jīng)發(fā)布到 github 上了代碼地址 ,也可以把項目來下來跑跑看。

參考

ECMAScript 6 入門

相關(guān)文章

  • vue3中使用vuex和vue-router的詳細步驟

    vue3中使用vuex和vue-router的詳細步驟

    這篇文章主要介紹了vue3中使用vuex和vue-router的步驟,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • vue3?中使用?jsx?開發(fā)的詳細過程

    vue3?中使用?jsx?開發(fā)的詳細過程

    這篇文章主要介紹了vue3?中使用?jsx?開發(fā),本文著重說一下在使用 .vue 文件和 .jsx 文件在使用語法上的差異,需要的朋友可以參考下
    2022-09-09
  • Vue.js組件間通信方式總結(jié)【推薦】

    Vue.js組件間通信方式總結(jié)【推薦】

    組件之間通信分為三種:父-子;子-父;跨級組件通信。下面,就組件間如何通信做一些總結(jié)。需要的朋友可以參考下
    2018-11-11
  • vue.js父組件使用外部對象的方法示例

    vue.js父組件使用外部對象的方法示例

    在我們?nèi)粘i_發(fā)中經(jīng)常因為思維定式,我們會犯一些奇怪的錯誤,有時候看似簡單的問題卻給出了復(fù)雜的解決方案。下面這篇文章主要介紹了vue.js父組件使用外部對象的方法,這個看似簡單卻繞了一些彎路的問題,有必要和大家分享下,需要的朋友可以參考學(xué)習(xí),下面來看看吧。
    2017-04-04
  • vue 引入公共css文件的簡單方法(推薦)

    vue 引入公共css文件的簡單方法(推薦)

    下面小編就為大家分享一篇vue 引入公共css文件的簡單方法(推薦),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Vue實現(xiàn)極致舒適的可編輯表格

    Vue實現(xiàn)極致舒適的可編輯表格

    使用ElementPlus的Table啥都好,就是沒有可編輯表格,所以這篇文章就來和大家分享一下Vue實現(xiàn)極致舒適的可編輯表格的方法,希望對大家有所幫助
    2023-06-06
  • element滾動條組件el-scrollbar的使用詳解

    element滾動條組件el-scrollbar的使用詳解

    本文主要介紹了element滾動條組件el-scrollbar的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • vue cli使用絕對路徑引用圖片問題的解決

    vue cli使用絕對路徑引用圖片問題的解決

    這篇文章主要給大家介紹了關(guān)于vue cli使用絕對路徑引用圖片問題的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧。
    2017-12-12
  • Vue使用echarts散點圖在區(qū)域內(nèi)標點

    Vue使用echarts散點圖在區(qū)域內(nèi)標點

    這篇文章主要為大家詳細介紹了Vue使用echarts散點圖在區(qū)域內(nèi)標點,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Vue中使用provide和inject實例對比分析

    Vue中使用provide和inject實例對比分析

    這篇文章主要為大家介紹了Vue中使用provide和inject實例對比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08

最新評論