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

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

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

前言

在面向對象(OOP)的設計模式中,裝飾器的應用非常多,比如在 Java 和 Python 中,都有非常多的應用。ES6 也新增了裝飾器的功能,本文會介紹 ES6 的裝飾器的概念、作用以及在 Vue + ElementUI 的項目實戰(zhàn)中的應用。

裝飾模式(Decorator)

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

優(yōu)點:

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

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

ES6 裝飾器

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

  • 類的裝飾

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

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

使用的時候直接用 @ + 函數名,就可以為對象添加 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ōu)點:

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

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

裝飾器應用

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

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

Validate

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

完整的代碼如下:

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

這里有幾個問題:

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

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

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); // 在這里調用“被裝飾的方法”
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    };
  };
}

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

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

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

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

CatchError

在寫代碼的時候經常用 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 的功能作為裝飾函數

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!')
  }
}

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

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

那么提交表單的函數最終可以被裝飾器優(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ā)現了沒有,提交表單的代碼中,完完全全只有業(yè)務邏輯代碼了!而其他的功能作為裝飾器引入并作用到這個方法上。而且這些裝飾功能就像是個語法糖一樣,當我下次還需要用到的時候,只需要引用在我的方法上即可,十分方便。

Confirmation

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

代碼實現:

<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>

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

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

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>

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

總結

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

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

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

參考

ECMAScript 6 入門

相關文章

  • vue中關于checkbox使用的問題

    vue中關于checkbox使用的問題

    這篇文章主要介紹了vue中關于checkbox使用的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 詳解Vue2.0配置mint-ui踩過的那些坑

    詳解Vue2.0配置mint-ui踩過的那些坑

    這篇文章主要介紹了詳解Vue2.0配置mint-ui踩過的那些坑,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • vue中組件的3種使用方式詳解

    vue中組件的3種使用方式詳解

    這篇文章主要給大家介紹了關于vue中組件的3種使用方式,文中通過示例代碼介紹的非常詳細,對大家學習或者使用vue具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03
  • vue element 生成無線級左側菜單的實現代碼

    vue element 生成無線級左側菜單的實現代碼

    這篇文章主要介紹了vue element 生成無線級左側菜單的實現代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • Vue3?中自定義插件的實現方法

    Vue3?中自定義插件的實現方法

    在 Vue 中,一些簡單的功能,我們可以直接定義為全局方法,然后掛到 Vue 上就能使用了,這篇文章主要介紹了Vue3?中自定義插件的實現,需要的朋友可以參考下
    2022-08-08
  • vue中的scope使用詳解

    vue中的scope使用詳解

    這篇文章主要介紹了vue中的scope使用詳解,需要的朋友可以參考下
    2017-10-10
  • Nuxt使用Vuex解讀

    Nuxt使用Vuex解讀

    這篇文章主要介紹了Nuxt使用Vuex的方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue中內置指令與自定義指令語法詳解

    Vue中內置指令與自定義指令語法詳解

    這篇文章主要為大家介紹了Vue中內置指令與自定義指令語法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Vue使用Markdown文檔的示例

    Vue使用Markdown文檔的示例

    本文主要介紹了Vue使用Markdown文檔的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • 使用vue-cli創(chuàng)建vue2項目的實戰(zhàn)步驟詳解

    使用vue-cli創(chuàng)建vue2項目的實戰(zhàn)步驟詳解

    相信大部分Vue開發(fā)者都使用過vue-cli來構建項目,它的確很方便,但對于很多初級開發(fā)者來說,還是要踩不少坑的,下面這篇文章主要給大家介紹了關于使用vue-cli創(chuàng)建vue2項目的實戰(zhàn)步驟,需要的朋友可以參考下
    2023-01-01

最新評論

宜宾市| 巴彦县| 宾阳县| 钟山县| 长垣县| 田东县| 抚顺市| 修水县| 双鸭山市| 视频| 普安县| 漯河市| 延吉市| 黑山县| 离岛区| 东明县| 庄浪县| 河源市| 南澳县| 美姑县| 浦城县| 南川市| 舒城县| 商城县| 上饶县| 南宫市| 新建县| 巴彦淖尔市| 华容县| 商都县| 江山市| 乐陵市| 思茅市| 礼泉县| 望奎县| 鄂托克前旗| 平陆县| 泗水县| 济宁市| 宜兰县| 高安市|