宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動態(tài)
精選推薦

vue3+Ts+Hook的方式實現(xiàn)商城核心功能sku選擇器

管理 管理 編輯 刪除

前言

Hooks是React等函數(shù)式編程框架中非常受歡迎的工具,隨著VUE3 Composition API 函數(shù)式編程風(fēng)格的推出,現(xiàn)在也受到越來越多VUE3開發(fā)者的青睞,它讓開發(fā)者的代碼具有更高的復(fù)用度且更加清晰、易于維護。

本文將通過CRMEB商城商品詳情sku選擇功能了解Hooks的使用基礎(chǔ)以及自定義HOOK開發(fā)相關(guān)的要點,快速入門。

a5943202401031729583572.jpg

Hook簡介

1.什么是hook

Hooks并不是VUE特有的概念,實際上它原本被用于指代一些特定時間點會觸發(fā)的勾子。而在React16之后,它被賦予了新的意義:

一系列以 use 作為開頭的方法,它們提供了讓你可以完全避開 class式寫法,在函數(shù)式組件中完成生命周期、狀態(tài)管理、邏輯復(fù)用等幾乎全部組件開發(fā)工作的能力

在VUE3中,Hooks的概念結(jié)合了VUE的響應(yīng)式系統(tǒng),被稱為組合函數(shù)。組合函數(shù)是VUE3組合式API中提供的新的邏輯復(fù)用的方案,是一類利用 Vue 的組合式 API 來封裝和復(fù)用有狀態(tài)邏輯的函數(shù),簡單來說,它就是一個創(chuàng)建工具的工具.

2.Hooks與composition Api

Hooks是一種基于閉包的函數(shù)式編程思維產(chǎn)物,所以通常我們會在函數(shù)式風(fēng)格的框架或組件中使用Hook,比如VUE的組合式API(Composition Api)。Hooks在VUE2所使用的選項式風(fēng)格API中也不是不可以使用,畢竟Hook本質(zhì)只是一個函數(shù),只要hook內(nèi)部所使用的api能夠得到支持,我們可以在任何地方使用它們,只是可能需要額外的支持以及效果沒有函數(shù)式組件中那么好,因為仍會被選項分割。

VUE3推出時為開發(fā)者帶來了全新的Composition API即組合式API。它是一種通過函數(shù)來描述組件邏輯的開發(fā)模式。組合式API為開發(fā)者帶來了更好的邏輯復(fù)用能力,通過組合函數(shù)來實現(xiàn)更加簡潔高效的邏輯復(fù)用。

為什么要使用Hooks

在以往VUE2的選項式API中,主要通過Mixin或是Class繼承來實現(xiàn)邏輯復(fù)用,但這種方式有三個明顯的短板:

1.不清晰的數(shù)據(jù)來源:當使用了多個mixin/class時,哪個數(shù)據(jù)是哪個模塊提供的將變得難以追尋,這將提高維護難度

2.命名空間沖突:來自多個class/mixin的開發(fā)者可能會注冊同樣的屬性名,造成沖突

3.隱性的跨模塊交流:不同的mixin/class之間可能存在某種相互作用,產(chǎn)生未知的后果

以上三種主要的缺點導(dǎo)致在大型項目的開發(fā)中,多mixin/class的組合將導(dǎo)致邏輯的混亂以及維護難度的提升,因而在VUE3的官方文檔中不再繼續(xù)推薦使用,保留mixin也只是為了遷移的需求或方便VUE2用戶熟悉。

mixin的缺點其實就是Hooks的優(yōu)點:

1.清晰一目了然的源頭

2.沒有命名沖突的問題

3.精簡邏輯

怎么開始玩Hooks

Hooks的各類規(guī)范

1.通常來講,一個Hook的命名需要以use開頭,比如useTimeOut,這是約定俗成的,開發(fā)者看到useXXX即可明白這是一個Hook。Hook的名稱需要清楚地表明其功能。

2.只在當前關(guān)注的最頂級作用域使用Hook,而不要在嵌套函數(shù)、循環(huán)中調(diào)用Hook

3.函數(shù)必須是純函數(shù),沒有副作用

4.返回值是一個函數(shù)或數(shù)據(jù),供外部使用

5.Hook內(nèi)部可以使用其他的Hook,組合功能

6.數(shù)據(jù)必須依賴于輸入,不依賴于外部狀態(tài),保持數(shù)據(jù)流的明確性

7.在Hook內(nèi)部處理錯誤,不要把錯誤拋出到外部,否則會增加hook的使用成本

8.Hook是單一功能的,不要給一個Hook設(shè)計過多功能。單個Hook只負責(zé)做一件事,復(fù)雜的功能可以使用多個Hook互相組合實現(xiàn),如果給單個Hook增加過多功能,又會陷入過于臃腫、使用成本高、難維護的問題中


下面通過一個簡單的hooks感受一下它的魅力:

這是一個控制頁面彈窗或者抽屜顯示或隱藏的hook,在以往vue2中,我們實現(xiàn)這樣一個功能,需要在data中定義一個變量,在methods中大概率會寫兩個方法分別控制彈窗的顯示和隱藏,如果頁面有多個這樣的顯隱組件,我們的代碼簡直是災(zāi)難,糟糕的事,我們的代碼中這樣的案例實在是太多了,有了hooks就完全不一樣了.

這是一個useBoolean的hooks,可以看到它拋出了一個響應(yīng)式的布爾值和四個方法.在使用的組件內(nèi)就可以多次使用該方法,從而簡化代碼


import { ref } from 'vue';

/**
 * boolean組合式函數(shù)
 * @param initValue 初始值
 */
export default function useBoolean(initValue = false) {
  const bool = ref(initValue);

  function setBool(value: boolean) {
    bool.value = value;
  }
  function setTrue() {
    setBool(true);
  }
  function setFalse() {
    setBool(false);
  }
  function toggle() {
    setBool(!bool.value);
  }

  return {
    bool,
    setBool,
    setTrue,
    setFalse,
    toggle,
  };
}

3e1e0202401031733568131.png


通過這個例子發(fā)現(xiàn),我們在vue2中大概率要寫6個方法和定義三個變量的工作在vue3配合Hooks的情況下,三行代碼就實現(xiàn)了.

下面進入我們本文的重點,通過hooks的方式實現(xiàn)sku選擇器的功能.

a183f202401031730208119.png


在CRMEB各個項目中,加購功能并不是只有在商品詳情頁使用,還有很多頁面也有使用,比如商品分類的幾個模板,購物車頁面,搭配購等,都會需要到打開sku選擇商品規(guī)格的功能,改功能包含選擇商品規(guī)格,價格,庫存,規(guī)格圖跟隨切換實時變化,還有加購數(shù)量的操作,對庫存為0的規(guī)格做不可操作的限制等等,所以這段代碼在前端是非常臃腫龐大的一部分代碼,牽扯的業(yè)務(wù)復(fù)雜,功能廣泛,若是在需要的組件內(nèi)每次復(fù)制粘貼,代碼量就會非常龐大,所以若是可以將這部分功能單獨抽離出來整理為一個可調(diào)用的方法就非常適合我們的使用場景.

先截圖看看以前vue2的方式書寫的該段代碼.

bbf1a202401031712117992.png

f4c36202401031712371200.png

下面是我用vue3+ts+hooks的方式實現(xiàn)一下,代碼如下:

import { ref, reactive, watch, unref } from 'vue';
import { cloneDeep } from 'lodash-es';
export default function useSkuSelect(productInfo: Product.Details) {
  watch(productInfo, () => {
    attr.productAttr = cloneDeep(productInfo.productAttr);
    DefaultSelect();
  });
  // 向sku選擇器傳遞的數(shù)據(jù)
  const attr = reactive({
    productAttr: [],
    productSelect: createDefaultModel(),
  });
  const attrTxt = ref('請選擇');
  const attrValue = ref('');
  attr.productAttr = productInfo.productAttr;
  function DefaultSelect() {
    let productAttr = attr.productAttr;
    let valueObj: Array = [];
    let value: Array = [];
    let productValue = productInfo.productValue;
    for (const key in productValue) {
      if (Object.prototype.hasOwnProperty.call(productValue, key)) {
        const element = productValue[key];
        if (element.stock > 0) {
          valueObj = attr.productAttr.length ? key.split(',') : [];
          break;
        }
      }
    }
    // 處理已售罄時默認選中第一個
    if (!valueObj.length && productAttr.length) {
      // value = Object.keys(productValue)[0].split(',');
    } else {
      value = valueObj;
    }
    for (let index = 0; index < productAttr.length; index++) {
      productAttr[index]!.index = value[index];
    }
    // 排序
    type selectPro = Pick;
    let productSelect: selectPro = productValue[value.join(',')];
    if (productSelect && productAttr.length) {
      attr.productSelect = createProductSelect(1, productSelect);
      attrValue.value = value.join(',');
      attrTxt.value = '已選擇';
    } else if (!productSelect && productAttr.length) {
      attr.productSelect = createProductSelect(2, productSelect);
      attrValue.value = '';
      attrTxt.value = '請選擇';
    } else if (!productSelect && !productAttr.length) {
      attr.productSelect = createProductSelect(3, productSelect);
      attrValue.value = '';
      attrTxt.value = '請選擇';
    }
  }

  function attrVal(val: Product.AttrVal) {
    const { index, indexn } = val;
    const attrValue = attr.productAttr[index]!.attr_values[indexn];
    attr.productAttr[index]!.index = attrValue;
  }
  function ChangeAttr(res: any) {
    let productSelect = productInfo.productValue[res];
    if (productSelect && productSelect.stock >= 0) {
      attr.productSelect = createProductSelect(1, productSelect);
      attrValue.value = res;
      attrTxt.value = '已選擇';
    } else {
      attr.productSelect = createProductSelect(2, productSelect);
      attrValue.value = '';
      attrTxt.value = '請選擇';
    }
  }
  /**
   *
   * @param type
   * true 加
   * false 減
   */
  function changeCartNum(type: boolean) {
    // 獲取當前變動屬性
    let proSelect = productInfo.productValue[unref(attrValue)];
    //無屬性值即庫存為0;不存在加減;
    if (!proSelect) return;
    let stock = proSelect.stock || 0;
    if (attr.productSelect.cart_num) {
      if (type) {
        attr.productSelect.cart_num++;
        if (attr.productSelect.cart_num > stock) {
          attr.productSelect.cart_num = stock ? stock : 1;
        }
      } else {
        if (attr.productSelect.cart_num <= 1) {
          attr.productSelect.cart_num = 1;
        } else {
          attr.productSelect.cart_num--;
        }
      }
    }
  }

  function createProductSelect(type: number, productSelect: any): Product.selectPro {
    let proSelect: Product.selectPro = createDefaultModel();
    if (type === 1) {
      proSelect = {
        store_name: productInfo.storeInfo.store_name,
        image: productSelect.image,
        price: productSelect.price,
        stock: productSelect.stock,
        unique: productSelect.unique,
        cart_num: 1,
        vip_price: productSelect.vip_price,
      };
    } else if (type === 2) {
      proSelect = {
        store_name: productInfo.storeInfo.store_name,
        image: productInfo.storeInfo.image,
        price: productInfo.storeInfo.price,
        stock: 0,
        unique: '',
        cart_num: 0,
        vip_price: productInfo.storeInfo.vip_price,
      };
    } else if (type === 3) {
      proSelect = {
        store_name: productInfo.storeInfo.store_name,
        image: productInfo.storeInfo.image,
        price: productInfo.storeInfo.price,
        stock: productInfo.storeInfo.stock,
        unique: '',
        cart_num: 1,
        vip_price: productInfo.storeInfo.vip_price,
      };
    }
    return proSelect;
  }

  function createDefaultModel(): Product.selectPro {
    return {
      store_name: '',
      image: '',
      price: '',
      stock: 0,
      vip_price: '',
      unique: '',
      cart_num: 0,
    };
  }

  return {
    ChangeAttr,
    attrVal,
    changeCartNum,
    attrValue,
    attrTxt,
    attr,
  };
}

在使用sku選擇器組件的頁面上使用:

08ddd202401031735273907.png

1228d20240103173613725.png

這是一個管理sku選擇器內(nèi)商品規(guī)格選擇的Hook,在使用時只需傳入該商品的詳情數(shù)據(jù)以及一些配置項即可快默認選中,節(jié)省了大量重復(fù)的控制代碼,使用該Hook后只需調(diào)用useSkuSelect即可實現(xiàn)規(guī)格的切換,加購數(shù)量的控制等等,且繼承原接口的類型.因為本人其實也是hooks小白,處于學(xué)習(xí)階段,書寫的該hook和ts代碼有可能并不規(guī)范,歡迎讀者交流指正.

總結(jié)

Hooks是VUE3中利用組合式API響應(yīng)式的特性的,實現(xiàn)簡單高效的邏輯復(fù)用、提高開發(fā)效率、提高VUE模塊可維護性的工具。Hooks的組合可以讓組件低代價、高效率地實現(xiàn)高復(fù)雜度業(yè)務(wù),Hooks之間通常相互獨立,沒有過度耦合,降低后期陷入維護地獄的風(fēng)險,而且可以使得功能模塊更加易于測試.使用開源的Hook將為開發(fā)帶來很多方便,而開發(fā)自定義Hook則需要花費一些時間,但在實現(xiàn)后,高度的定制化將為項目開發(fā)帶來巨大的便利.Hooks的出現(xiàn)不意味著拋棄Class,Hooks也有自己的缺點比如內(nèi)存泄漏和可能的性能問題。Class更加易于上手,在經(jīng)驗豐富、技術(shù)深厚的開發(fā)者手中也可以一定程度上避開Class的缺點

請登錄后查看

鄉(xiāng)關(guān)何處 最后編輯于2024-01-03 17:37:14

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認正序 回復(fù)倒序 點贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
4357
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動態(tài) 精選推薦 首頁頭條 首頁動態(tài) 首頁推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動獲取的帖子內(nèi)容,不準確時需要手動修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認打賞

微信登錄/注冊

切換手機號登錄

{{ bind_phone ? '綁定手機' : '手機登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服