說說你對vue的mixin的理解,有什麼應用場景?

来源:https://www.cnblogs.com/smileZAZ/p/18049004
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、mixin是什麼 Mixin是面向對象程式設計語言中的類,提供了方法的實現。其他類可以訪問mixin類的方法而不必成為其子類 Mixin類通常作為功能模塊使用,在需要該功能時“混入”,有利於代碼復用又避免了多繼承的複雜 Vue中的mi ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

一、mixin是什麼

Mixin是面向對象程式設計語言中的類,提供了方法的實現。其他類可以訪問mixin類的方法而不必成為其子類

Mixin類通常作為功能模塊使用,在需要該功能時“混入”,有利於代碼復用又避免了多繼承的複雜

Vue中的mixin

先來看一下官方定義

mixin(混入),提供了一種非常靈活的方式,來分發 Vue 組件中的可復用功能。

本質其實就是一個js對象,它可以包含我們組件中任意功能選項,如datacomponentsmethodscreatedcomputed等等

我們只要將共用的功能以對象的方式傳入 mixins選項中,當組件使用 mixins對象時所有mixins對象的選項都將被混入該組件本身的選項中來

Vue中我們可以局部混入跟全局混入

局部混入

定義一個mixin對象,有組件optionsdatamethods屬性

var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

組件通過mixins屬性調用mixin對象

Vue.component('componentA',{
  mixins: [myMixin]
})

該組件在使用的時候,混合了mixin裡面的方法,在自動執行created生命鉤子,執行hello方法

全局混入

通過Vue.mixin()進行全局的混入

Vue.mixin({
  created: function () {
      console.log("全局混入")
    }
})

使用全局混入需要特別註意,因為它會影響到每一個組件實例(包括第三方組件)

PS:全局混入常用於插件的編寫

註意事項:

當組件存在與mixin對象相同的選項的時候,進行遞歸合併的時候組件的選項會覆蓋mixin的選項

但是如果相同選項為生命周期鉤子的時候,會合併成一個數組,先執行mixin的鉤子,再執行組件的鉤子

二、使用場景

在日常的開發中,我們經常會遇到在不同的組件中經常會需要用到一些相同或者相似的代碼,這些代碼的功能相對獨立

這時,可以通過Vuemixin功能將相同或者相似的代碼提出來

舉個例子

定義一個modal彈窗組件,內部通過isShowing來控制顯示

const Modal = {
  template: '#modal',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

定義一個tooltip提示框,內部通過isShowing來控制顯示

const Tooltip = {
  template: '#tooltip',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

通過觀察上面兩個組件,發現兩者的邏輯是相同,代碼控制顯示也是相同的,這時候mixin就派上用場了

首先抽出共同代碼,編寫一個mixin

const toggle = {
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

兩個組件在使用上,只需要引入mixin

const Modal = {
  template: '#modal',
  mixins: [toggle]
};
 
const Tooltip = {
  template: '#tooltip',
  mixins: [toggle]
}

通過上面小小的例子,讓我們知道了Mixin對於封裝一些可復用的功能如此有趣、方便、實用

三、源碼分析

首先從Vue.mixin入手

源碼位置:/src/core/global-api/mixin.js

export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

主要是調用merOptions方法

源碼位置:/src/core/util/options.js

export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {

if (child.mixins) { // 判斷有沒有mixin 也就是mixin裡面掛mixin的情況 有的話遞歸進行合併
    for (let i = 0, l = child.mixins.length; i < l; i++) {
    parent = mergeOptions(parent, child.mixins[i], vm)
    }
}

  const options = {} 
  let key
  for (key in parent) {
    mergeField(key) // 先遍歷parent的key 調對應的strats[XXX]方法進行合併
  }
  for (key in child) {
    if (!hasOwn(parent, key)) { // 如果parent已經處理過某個key 就不處理了
      mergeField(key) // 處理child中的key 也就parent中沒有處理過的key
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key) // 根據不同類型的options調用strats中不同的方法進行合併
  }
  return options
}

從上面的源碼,我們得到以下幾點:

  • 優先遞歸處理 mixins
  • 先遍歷合併parent 中的key,調用mergeField方法進行合併,然後保存在變數options
  • 再遍歷 child,合併補上 parent 中沒有的key,調用mergeField方法進行合併,保存在變數options
  • 通過 mergeField 函數進行了合併

下麵是關於Vue的幾種類型的合併策略

  • 替換型
  • 合併型
  • 隊列型
  • 疊加型

替換型

替換型合併有propsmethodsinjectcomputed

strats.props =
strats.methods =
strats.inject =
strats.computed = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  if (!parentVal) return childVal // 如果parentVal沒有值,直接返回childVal
  const ret = Object.create(null) // 創建一個第三方對象 ret
  extend(ret, parentVal) // extend方法實際是把parentVal的屬性複製到ret中
  if (childVal) extend(ret, childVal) // 把childVal的屬性複製到ret中
  return ret
}
strats.provide = mergeDataOrFn

同名的propsmethodsinjectcomputed會被後來者代替

合併型

和並型合併有:data

strats.data = function(parentVal, childVal, vm) {    
    return mergeDataOrFn(
        parentVal, childVal, vm
    )
};

function mergeDataOrFn(parentVal, childVal, vm) {    
    return function mergedInstanceDataFn() {        
        var childData = childVal.call(vm, vm) // 執行data掛的函數得到對象
        var parentData = parentVal.call(vm, vm)        
        if (childData) {            
            return mergeData(childData, parentData) // 將2個對象進行合併                                 
        } else {            
            return parentData // 如果沒有childData 直接返回parentData
        }
    }
}

function mergeData(to, from) {    
    if (!from) return to    
    var key, toVal, fromVal;    
    var keys = Object.keys(from);   
    for (var i = 0; i < keys.length; i++) {
        key = keys[i];
        toVal = to[key];
        fromVal = from[key];    
        // 如果不存在這個屬性,就重新設置
        if (!to.hasOwnProperty(key)) {
            set(to, key, fromVal);
        }      
        // 存在相同屬性,合併對象
        else if (typeof toVal =="object" && typeof fromVal =="object") {
            mergeData(toVal, fromVal);
        }
    }    
    return to
}

mergeData函數遍歷了要合併的 data 的所有屬性,然後根據不同情況進行合併:

  • 當目標 data 對象不包含當前屬性時,調用 set 方法進行合併(set方法其實就是一些合併重新賦值的方法)
  • 當目標 data 對象包含當前屬性並且當前值為純對象時,遞歸合併當前對象值,這樣做是為了防止對象存在新增屬性

隊列性

隊列性合併有:全部生命周期和watch

function mergeHook (
  parentVal: ?Array<Function>,
  childVal: ?Function | ?Array<Function>
): ?Array<Function> {
  return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}

LIFECYCLE_HOOKS.forEach(hook => {
  strats[hook] = mergeHook
})

// watch
strats.watch = function (
  parentVal,
  childVal,
  vm,
  key
) {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) { parentVal = undefined; }
  if (childVal === nativeWatch) { childVal = undefined; }
  /* istanbul ignore if */
  if (!childVal) { return Object.create(parentVal || null) }
  {
    assertObjectType(key, childVal, vm);
  }
  if (!parentVal) { return childVal }
  var ret = {};
  extend(ret, parentVal);
  for (var key$1 in childVal) {
    var parent = ret[key$1];
    var child = childVal[key$1];
    if (parent && !Array.isArray(parent)) {
      parent = [parent];
    }
    ret[key$1] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child];
  }
  return ret
};

生命周期鉤子和watch被合併為一個數組,然後正序遍歷一次執行

疊加型

疊加型合併有:componentdirectivesfilters

strats.components=
strats.directives=

strats.filters = function mergeAssets(
    parentVal, childVal, vm, key
) {    
    var res = Object.create(parentVal || null);    
    if (childVal) { 
        for (var key in childVal) {
            res[key] = childVal[key];
        }   
    } 
    return res
}

疊加型主要是通過原型鏈進行層層的疊加

小結:

  • 替換型策略有propsmethodsinjectcomputed,就是將新的同名參數替代舊的參數
  • 合併型策略是data, 通過set方法進行合併和重新賦值
  • 隊列型策略有生命周期函數和watch,原理是將函數存入一個數組,然後正序遍歷依次執行
  • 疊加型有componentdirectivesfilters,通過原型鏈進行層層的疊加

參考文獻

  • https://zhuanlan.zhihu.com/p/31018570
  • https://juejin.cn/post/6844904015495446536#heading-1
  • https://juejin.cn/post/6844903846775357453
  • https://vue3js.cn/docs/zh

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Android 修改系統息屏時間. 本篇文章主要記錄下android 如何修改手機息屏時間. 目前手機屏幕超時的時間範圍一般是: 15秒 30秒 1分鐘 2分鐘 5分鐘 10分鐘 30分鐘 那如何設置超過30分鐘呢? 代碼很簡單,如下: private void changeScreenOffTim ...
  • 兩個常用的組件:Material和Scaffold修飾App和H5一樣很固定。 1.Container 2.Text 3.picture import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( home: S ...
  • 本文基於Glide 4.11.0 Glide載入過程有一個解碼過程,比如將url載入為inputStream後,要將inputStream解碼為Bitmap。 從Glide源碼解析一我們大致知道了Glide載入的過程,所以我們可以直接從這裡看起,在這個過程中我們以從文件中載入bitmap為例: De ...
  • 首發原創flutter3+bitsdojo_window+getx客戶端仿微信exe聊天Flutter-WinChat。 flutter3-dart3-winchat 基於flutter3+dart3+getx+bitsdojo_window+file_picker+media_kit等技術開發桌面 ...
  • 序言 開年的第一篇文章,今天分享的是SwiftUI,SwiftUI出來好幾年,之前一直沒學習,所以現在才開始;如果大家還留在 iOS 開發,這們語言也是一個趨勢; 目前待業中.... 不得不說已逝的2023年,大家開始都抱著一解封,經濟都會向上轉好,可是現實不是我們想象那樣;目前我也在學習 Swif ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、Keep-alive 是什麼 keep-alive是vue中的內置組件,能在組件切換過程中將狀態保留在記憶體中,防止重覆渲染DOM keep-alive 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們 keep-alive可以設 ...
  • 寫在前面 按照國際慣例,要先聊下生活,吐槽一番,今天是2月14日,也是下午聽老媽說,我才知道! 現在真的是對日期節日已經毫無概念可言,只知道星期幾。 現在已經覺得寫博客也好,學習文章也罷,和寫日記一樣,已經融入到我的生活中,或者更確切的說,變成生活的一部分了。 飯後和老媽閑聊了幾句後,我發現現在真的 ...
  • 概念 RCE(Remote code execution)遠程代碼執行漏洞,RCE又分命令執行和代碼執行。 RCE-遠程代碼執行:遠程執行PHP代碼 RCE-遠程命令執行:遠程執行Linux或者Windows等系統命令。 常見函數有: PHP:eval(),assert(),preg_replace ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...