一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Vue3設(shè)計(jì)思想及響應(yīng)式源碼剖析

京東云 ? 來(lái)源:京東物流 喬盼盼 ? 作者:京東物流 喬盼盼 ? 2024-12-20 10:24 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

作者:京東物流 喬盼盼

一、Vue3結(jié)構(gòu)分析

1、Vue2與Vue3的對(duì)比

?對(duì)TypeScript支持不友好(所有屬性都放在了this對(duì)象上,難以推倒組件的數(shù)據(jù)類型)

?大量的API掛載在Vue對(duì)象的原型上,難以實(shí)現(xiàn)TreeShaking。

?架構(gòu)層面對(duì)跨平臺(tái)dom渲染開(kāi)發(fā)支持不友好,vue3允許自定義渲染器,擴(kuò)展能力強(qiáng)。

?CompositionAPI。受ReactHook啟發(fā)

?對(duì)虛擬DOM進(jìn)行了重寫(xiě)、對(duì)模板的編譯進(jìn)行了優(yōu)化操作...

2、Vue3設(shè)計(jì)思想

?Vue3.0更注重模塊上的拆分,在2.0中無(wú)法單獨(dú)使用部分模塊。需要引入完整的Vuejs(例如只想使用使用響應(yīng)式部分,但是需要引入完整的Vuejs), Vue3中的模塊之間耦合度低,模塊可以獨(dú)立使用。拆分模塊

?Vue2中很多方法掛載到了實(shí)例中導(dǎo)致沒(méi)有使用也會(huì)被打包(還有很多組件也是一樣)。通過(guò)構(gòu)建工具Tree-shaking機(jī)制實(shí)現(xiàn)按需引入,減少用戶打包后體積。重寫(xiě)API

?Vue3允許自定義渲染器,擴(kuò)展能力強(qiáng)。不會(huì)發(fā)生以前的事情,改寫(xiě)Vue源碼改造渲染方式。擴(kuò)展更方便

??

依然保留了Vue2的特點(diǎn):

依舊是聲明式框架,底層渲染邏輯不關(guān)心(命令式比較關(guān)注過(guò)程,可以控制怎么寫(xiě)最優(yōu)?編寫(xiě)過(guò)程不同),如for和reduce

采用虛擬DOM

區(qū)分編譯時(shí)和運(yùn)行時(shí)

內(nèi)部區(qū)分了編譯時(shí)(模板?編程成js代碼,一般在構(gòu)建工具中使用)和運(yùn)行時(shí)

簡(jiǎn)單來(lái)說(shuō),Vue3 框架更小,擴(kuò)展更加方便

3、monorepo管理項(xiàng)目

Monorepo 是管理項(xiàng)目代碼的一個(gè)方式,指在一個(gè)項(xiàng)目倉(cāng)庫(kù)(repo)中管理多個(gè)模塊/包(package)。也就是說(shuō)是一種將多個(gè)package放在一個(gè)repo中的代碼管理模式。Vue3內(nèi)部實(shí)現(xiàn)了一個(gè)模塊的拆分, Vue3源碼采用 Monorepo 方式進(jìn)行管理,將模塊拆分到package目錄中。

?一個(gè)倉(cāng)庫(kù)可維護(hù)多個(gè)模塊,不用到處找倉(cāng)庫(kù)

?方便版本管理和依賴管理,模塊之間的引用,調(diào)用都非常方便

?每個(gè)包可以獨(dú)立發(fā)布

早期使用yarn workspace + lerna來(lái)管理項(xiàng)目,后面是pnpm

pnpm介紹

快速,節(jié)省磁盤空間的包管理器,主要采用符號(hào)鏈接的方式管理模塊

1.快速

2.高效利用磁盤空間

pnpm 內(nèi)部使用基于內(nèi)容尋址的文件系統(tǒng)來(lái)存儲(chǔ)磁盤上所有的文件,這個(gè)文件系統(tǒng)出色的地方在于:

?不會(huì)重復(fù)安裝同一個(gè)包。用 npm/yarn 的時(shí)候,如果 100 個(gè)項(xiàng)目都依賴 lodash,那么 lodash 很可能就被安裝了 100 次,磁盤中就有 100 個(gè)地方寫(xiě)入了這部分代碼。但在使用 pnpm 只會(huì)安裝一次,磁盤中只有一個(gè)地方寫(xiě)入,后面再次使用都會(huì)直接使用hardlink(硬鏈接)

?即使一個(gè)包的不同版本,pnpm 也會(huì)極大程度地復(fù)用之前版本的代碼。比如 lodash 有 100 個(gè)文件,更新版本之后多了一個(gè)文件,那么磁盤當(dāng)中并不會(huì)重新寫(xiě)入 101 個(gè)文件,而是保留原來(lái)的 100 個(gè)文件的hardlink,僅僅寫(xiě)入那一個(gè)新增的文件。

1.支持Monorepo

pnpm 與 npm/yarn 一個(gè)很大的不同就是支持了 monorepo

1.安全性高

之前在使用 npm/yarn 的時(shí)候,由于 node_module 的扁平結(jié)構(gòu),如果 A 依賴 B, B 依賴 C,那么 A 當(dāng)中是可以直接使用 C 的,但問(wèn)題是 A 當(dāng)中并沒(méi)有聲明 C 這個(gè)依賴。因此會(huì)出現(xiàn)這種非法訪問(wèn)的情況。但 pnpm自創(chuàng)了一套依賴管理方式,很好地解決了這個(gè)問(wèn)題,保證了安全性

默認(rèn)情況下,pnpm 則是通過(guò)使用符號(hào)鏈接的方式僅將項(xiàng)目的直接依賴項(xiàng)添加到node_modules的根目錄下。

安裝和初始化

?全局安裝(node版本>16)

npm install pnpm -g

?初始化

pnpm init

配置workspace

根目錄創(chuàng)建pnpm-workspace.yaml

packages:
  - 'packages/*'

將packages下所有的目錄都作為包進(jìn)行管理。這樣我們的Monorepo就搭建好了。確實(shí)比lerna + yarn workspace更快捷

4、項(xiàng)目結(jié)構(gòu)

packages

?reactivity:響應(yīng)式系統(tǒng)

?runtime-core:與平臺(tái)無(wú)關(guān)的運(yùn)行時(shí)核心 (可以創(chuàng)建針對(duì)特定平臺(tái)的運(yùn)行時(shí) - 自定義渲染器)

?runtime-dom: 針對(duì)瀏覽器的運(yùn)行時(shí)。包括DOM API,屬性,事件處理等

?runtime-test:用于測(cè)試

?server-renderer:用于服務(wù)器端渲染

?compiler-core:與平臺(tái)無(wú)關(guān)的編譯器核心

?compiler-dom: 針對(duì)瀏覽器的編譯模塊

?compiler-ssr: 針對(duì)服務(wù)端渲染的編譯模塊

?template-explorer:用于調(diào)試編譯器輸出的開(kāi)發(fā)工具

?shared:多個(gè)包之間共享的內(nèi)容

?vue:完整版本,包括運(yùn)行時(shí)和編譯器

                                    +---------------------+
                                    |                     |
                                    |  @vue/compiler-sfc  |
                                    |                     |
                                    +-----+--------+------+
                                          |        |
                                          v        v
                      +---------------------+    +----------------------+
                      |                     |    |                      |
        +------------>|  @vue/compiler-dom  +--->|  @vue/compiler-core  |
        |             |                     |    |                      |
   +----+----+        +---------------------+    +----------------------+
   |         |
   |   vue   |
   |         |
   +----+----+        +---------------------+    +----------------------+    +-------------------+
        |             |                     |    |                      |    |                   |
        +------------>|  @vue/runtime-dom   +--->|  @vue/runtime-core   +--->|  @vue/reactivity  |
                      |                     |    |                      |    |                   |
                      +---------------------+    +----------------------+    +-------------------+

scripts

Vue3在開(kāi)發(fā)環(huán)境使用esbuild打包,生產(chǎn)環(huán)境采用rollup打包

包的相互依賴

安裝

把packages/shared安裝到packages/reactivity

pnpm install @vue/shared@workspace --filter @vue/reactivity

使用

在reactivity/src/computed.ts中引入shared中相關(guān)方法

import { isFunction, NOOP } from '@vue/shared' // ts引入會(huì)報(bào)錯(cuò)

const onlyGetter = isFunction(getterOrOptions)
  if (onlyGetter) {
    ...
  } else {
    ...
  }
...

tips:@vue/shared引入會(huì)報(bào)錯(cuò),需要在tsconfig.json中配置

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@vue/compat": ["packages/vue-compat/src"],
      "@vue/*": ["packages/*/src"],
      "vue": ["packages/vue/src"]
    }
  },
}

5、打包

所有包的入口均為src/index.ts這樣可以實(shí)現(xiàn)統(tǒng)一打包.

?reactivity/package.json

{
  "name": "@vue/reactivity",
  "version": "3.2.45",
  "main": "index.js",
  "module":"dist/reactivity.esm-bundler.js",
  "unpkg": "dist/reactivity.global.js",
  "buildOptions": {
    "name": "VueReactivity",
    "formats": [
      "esm-bundler",
      "cjs",
      "global"
    ]
  }
}

?shared/package.json

{
    "name": "@vue/shared",
    "version": "3.2.45",
    "main": "index.js",
    "module": "dist/shared.esm-bundler.js",
    "buildOptions": {
        "formats": [
            "esm-bundler",
            "cjs"
        ]
    }
}

formats為自定義的打包格式,有esm-bundler在構(gòu)建工具中使用的格式、esm-browser在瀏覽器中使用的格式、cjs在node中使用的格式、global立即執(zhí)行函數(shù)的格式

開(kāi)發(fā)環(huán)境esbuild打包

開(kāi)發(fā)時(shí) 執(zhí)行腳本, 參數(shù)為要打包的模塊

"scripts": {
    "dev": "node scripts/dev.js reactivity -f global"
}
// Using esbuild for faster dev builds.
// We are still using Rollup for production builds because it generates
// smaller files w/ better tree-shaking.

// @ts-check
const { build } = require('esbuild')
const nodePolyfills = require('@esbuild-plugins/node-modules-polyfill')
const { resolve, relative } = require('path')
const args = require('minimist')(process.argv.slice(2))

const target = args._[0] || 'vue'
const format = args.f || 'global'
const inlineDeps = args.i || args.inline
const pkg = require(resolve(__dirname, `../packages/${target}/package.json`))

// resolve output
const outputFormat = format.startsWith('global')
  ? 'iife'
  : format === 'cjs'
  ? 'cjs'
  : 'esm'

const postfix = format.endsWith('-runtime')
  ? `runtime.${format.replace(/-runtime$/, '')}`
  : format

const outfile = resolve(
  __dirname,
  `../packages/${target}/dist/${
    target === 'vue-compat' ? `vue` : target
  }.${postfix}.js`
)
const relativeOutfile = relative(process.cwd(), outfile)

// resolve externals
// TODO this logic is largely duplicated from rollup.config.js
let external = []
if (!inlineDeps) {
  // cjs & esm-bundler: external all deps
  if (format === 'cjs' || format.includes('esm-bundler')) {
    external = [
      ...external,
      ...Object.keys(pkg.dependencies || {}),
      ...Object.keys(pkg.peerDependencies || {}),
      // for @vue/compiler-sfc / server-renderer
      'path',
      'url',
      'stream'
    ]
  }

  if (target === 'compiler-sfc') {
    const consolidateDeps = require.resolve('@vue/consolidate/package.json', {
      paths: [resolve(__dirname, `../packages/${target}/`)]
    })
    external = [
      ...external,
      ...Object.keys(require(consolidateDeps).devDependencies),
      'fs',
      'vm',
      'crypto',
      'react-dom/server',
      'teacup/lib/express',
      'arc-templates/dist/es5',
      'then-pug',
      'then-jade'
    ]
  }
}

build({
  entryPoints: [resolve(__dirname, `../packages/${target}/src/index.ts`)],
  outfile,
  bundle: true,
  external,
  sourcemap: true,
  format: outputFormat,
  globalName: pkg.buildOptions?.name,
  platform: format === 'cjs' ? 'node' : 'browser',
  plugins:
    format === 'cjs' || pkg.buildOptions?.enableNonBrowserBranches
      ? [nodePolyfills.default()]
      : undefined,
  define: {
    __COMMIT__: `"dev"`,
    __VERSION__: `"${pkg.version}"`,
    __DEV__: `true`,
    __TEST__: `false`,
    __BROWSER__: String(
      format !== 'cjs' && !pkg.buildOptions?.enableNonBrowserBranches
    ),
    __GLOBAL__: String(format === 'global'),
    __ESM_BUNDLER__: String(format.includes('esm-bundler')),
    __ESM_BROWSER__: String(format.includes('esm-browser')),
    __NODE_JS__: String(format === 'cjs'),
    __SSR__: String(format === 'cjs' || format.includes('esm-bundler')),
    __COMPAT__: String(target === 'vue-compat'),
    __FEATURE_SUSPENSE__: `true`,
    __FEATURE_OPTIONS_API__: `true`,
    __FEATURE_PROD_DEVTOOLS__: `false`
  },
  watch: {
    onRebuild(error) {
      if (!error) console.log(`rebuilt: ${relativeOutfile}`)
    }
  }
}).then(() => {
  console.log(`watching: ${relativeOutfile}`)
})

生產(chǎn)環(huán)境rollup打包

具體代碼參考rollup.config.mjs

build.js

二、Vue3中Reactivity模塊

1、vue3對(duì)比vue2的響應(yīng)式變化

?在Vue2的時(shí)候使用defineProperty來(lái)進(jìn)行數(shù)據(jù)的劫持, 需要對(duì)屬性進(jìn)行重寫(xiě)添加getter及setter性能差。

?當(dāng)新增屬性和刪除屬性時(shí)無(wú)法監(jiān)控變化。需要通過(guò)$set、$delete實(shí)現(xiàn)

?數(shù)組不采用defineProperty來(lái)進(jìn)行劫持 (浪費(fèi)性能,對(duì)所有索引進(jìn)行劫持會(huì)造成性能浪費(fèi))需要對(duì)數(shù)組單獨(dú)進(jìn)行處理

Vue3中使用Proxy來(lái)實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)變化。從而解決了上述問(wèn)題

2、CompositionAPI

?在Vue2中采用的是OptionsAPI, 用戶提供的data,props,methods,computed,watch等屬性 (用戶編寫(xiě)復(fù)雜業(yè)務(wù)邏輯會(huì)出現(xiàn)反復(fù)橫跳問(wèn)題)

?Vue2中所有的屬性都是通過(guò)this訪問(wèn),this存在指向明確問(wèn)題

?Vue2中很多未使用方法或?qū)傩砸琅f會(huì)被打包,并且所有全局API都在Vue對(duì)象上公開(kāi)。Composition API對(duì) tree-shaking 更加友好,代碼也更容易壓縮。

?組件邏輯共享問(wèn)題, Vue2 采用mixins 實(shí)現(xiàn)組件之間的邏輯共享; 但是會(huì)有數(shù)據(jù)來(lái)源不明確,命名沖突等問(wèn)題。 Vue3采用CompositionAPI 提取公共邏輯非常方便

簡(jiǎn)單的組件仍然可以采用OptionsAPI進(jìn)行編寫(xiě),compositionAPI在復(fù)雜的邏輯中有著明顯的優(yōu)勢(shì)~。reactivity模塊中就包含了很多我們經(jīng)常使用到的API例如:computed、reactive、ref、effect等

3、基本使用

const { effect, reactive } = VueReactivity
// console.log(effect, reactive);
const state = reactive({name: 'qpp', age:18, address: {city: '南京'}})
console.log(state.address);
effect(()=>{
    console.log(state.name)
})

4、reactive實(shí)現(xiàn)

import { mutableHandlers } from'./baseHandlers'; 
// 代理相關(guān)邏輯import{ isObject }from'./util';// 工具方法
export function reactive(target: object) {
  // if trying to observe a readonly proxy, return the readonly version.
  if (isReadonly(target)) {
    return target
  }
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}
function createReactiveObject(target, baseHandler){
    if(!isObject(target)){
        return target;
    }
    ...
    const observed =new Proxy(target, baseHandler);
    return observed
}

baseHandlers

import { isObject, hasOwn, hasChanged } from"@vue/shared";
import { reactive } from"./reactive";
const get = createGetter();
const set = createSetter();
function createGetter(){
    return function get(target, key, receiver){
        // 對(duì)獲取的值進(jìn)行放射
        const res = Reflect.get(target, key, receiver);
        console.log('屬性獲取',key)
        if(isObject(res)){// 如果獲取的值是對(duì)象類型,則返回當(dāng)前對(duì)象的代理對(duì)象
            return reactive(res);
        }
        return res;
    }
}
function createSetter(){
    return function set(target, key, value, receiver){
        const oldValue = target[key];
        const hadKey =hasOwn(target, key);
        const result = Reflect.set(target, key, value, receiver);
        if(!hadKey){
            console.log('屬性新增',key,value)
        }else if(hasChanged(value, oldValue)){
            console.log('屬性值被修改',key,value)
        }
        return result;
    }
}
export const mutableHandlers ={
    get,// 當(dāng)獲取屬性時(shí)調(diào)用此方法
    set// 當(dāng)修改屬性時(shí)調(diào)用此方法
}

這里我只選了對(duì)最常用到的get和set方法的代碼,還應(yīng)該有has、deleteProperty、ownKeys。這里為了快速掌握核心流程就先暫且跳過(guò)這些代碼

5、effect實(shí)現(xiàn)

我們?cè)賮?lái)看effect的代碼,默認(rèn)effect會(huì)立即執(zhí)行,當(dāng)依賴的值發(fā)生變化時(shí)effect會(huì)重新執(zhí)行

export let activeEffect = undefined;
// 依賴收集的原理是 借助js是單線程的特點(diǎn), 默認(rèn)調(diào)用effect的時(shí)候會(huì)去調(diào)用proxy的get,此時(shí)讓屬性記住
// 依賴的effect,同理也讓effect記住對(duì)應(yīng)的屬性
// 靠的是數(shù)據(jù)結(jié)構(gòu) weakMap : {map:{key:new Set()}}
// 稍后數(shù)據(jù)變化的時(shí)候 找到對(duì)應(yīng)的map 通過(guò)屬性出發(fā)set中effect
function cleanEffect(effect) {
    // 需要清理effect中存入屬性中的set中的effect 
    // 每次執(zhí)行前都需要將effect只對(duì)應(yīng)屬性的set集合都清理掉
    // 屬性中的set 依然存放effect
    let deps = effect.deps
    for (let i = 0; i < deps.length; i++) {
        deps[i].delete(effect)
    }
    effect.deps.length = 0;

}

// 創(chuàng)建effect時(shí)可以傳遞參數(shù),computed也是基于effect來(lái)實(shí)現(xiàn)的,只是增加了一些參數(shù)條件而已
export function effect(
    fn: () => T,
    options?: ReactiveEffectOptions    
){
    // 將用戶傳遞的函數(shù)編程響應(yīng)式的effect
    const _effect = new ReactiveEffect(fn,options.scheduler);
    // 更改runner中的this
    _effect.run()
    const runner = _effect.run.bind(_effect);
    runner.effect = _effect; // 暴露effect的實(shí)例
    return runner// 用戶可以手動(dòng)調(diào)用runner重新執(zhí)行
}
export class ReactiveEffect {
    public active = true;
    public parent = null;
    public deps = []; // effect中用了哪些屬性,后續(xù)清理的時(shí)候要使用
    constructor(public fn,public scheduler?) { } // 你傳遞的fn我會(huì)幫你放到this上
    // effectScope 可以來(lái)實(shí)現(xiàn)讓所有的effect停止
    run() {
        // 依賴收集  讓熟悉和effect 產(chǎn)生關(guān)聯(lián)
        if (!this.active) {
            return this.fn();
        } else {
            try {
                this.parent = activeEffect
                activeEffect = this;
                cleanEffect(this); // vue2 和 vue3中都是要清理的 
                return this.fn(); // 去proxy對(duì)象上取值, 取之的時(shí)候 我要讓這個(gè)熟悉 和當(dāng)前的effect函數(shù)關(guān)聯(lián)起來(lái),稍后數(shù)據(jù)變化了 ,可以重新執(zhí)行effect函數(shù)
            } finally {
                // 取消當(dāng)前正在運(yùn)行的effect
                activeEffect = this.parent;
                this.parent = null;
            }
        }
    }
    stop() {
        if (this.active) {
            this.active = false;
            cleanEffect(this);
        }
    }
}

在effect方法調(diào)用時(shí)會(huì)對(duì)屬性進(jìn)行取值,此時(shí)可以進(jìn)行依賴收集。

effect(()=>{
    console.log(state.name)
    // 執(zhí)行用戶傳入的fn函數(shù),會(huì)取到state.name,state.age... 會(huì)觸發(fā)reactive中的getter
    app.innerHTML = 'name:' + state.name + 'age:' + state.age + 'address' + state.address.city
    
})

6、依賴收集

核心代碼

// 收集屬性對(duì)應(yīng)的effect
export function track(target, type, key){}// 觸發(fā)屬性對(duì)應(yīng)effect執(zhí)行
export function trigger(target, type, key){}

function createGetter(){
    return function get(target, key, receiver){
        const res = Reflect.get(target, key, receiver);
        // 取值時(shí)依賴收集
        track(target, TrackOpTypes.GET, key);
        if(isObject(res)){
            return reactive(res);
        }
        return res;
    }
}
function createSetter(){
    return function set(target, key, value, receiver){
        const oldValue = target[key];
        const hadKey =hasOwn(target, key);
        const result = Reflect.set(target, key, value, receiver);
        if(!hadKey){
            // 設(shè)置值時(shí)觸發(fā)更新 - ADD
            trigger(target, TriggerOpTypes.ADD, key);
        }else if(hasChanged(value, oldValue)){
             // 設(shè)置值時(shí)觸發(fā)更新 - SET
            trigger(target, TriggerOpTypes.SET, key, value, oldValue);
        }
        return result;
    }
}

track的實(shí)現(xiàn)

const targetMap = new WeakMap();
export function track(target: object, type: TrackOpTypes, key: unknown){
    if (shouldTrack && activeEffect) { // 上下文 shouldTrack = true
        let depsMap = targetMap.get(target);
        if(!depsMap){// 如果沒(méi)有map,增加map
            targetMap.set(target,(depsMap =newMap()));
        }
        let dep = depsMap.get(key);// 取對(duì)應(yīng)屬性的依賴表
        if(!dep){// 如果沒(méi)有則構(gòu)建set
            depsMap.set(key,(dep =newSet()));
        }
    
        trackEffects(dep, eventInfo)
    }
}

export function trackEffects(
  dep: Dep,
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
  //let shouldTrack = false
  //if (effectTrackDepth <= maxMarkerBits) {
   // if (!newTracked(dep)) {
     // dep.n |= trackOpBit // set newly tracked
     // shouldTrack = !wasTracked(dep)
    //}
  //} else {
    // Full cleanup mode.
  //  shouldTrack = !dep.has(activeEffect!)
  } 

  if (!dep.has(activeEffect!) {
    dep.add(activeEffect!)
    activeEffect!.deps.push(dep)
    //if (__DEV__ && activeEffect!.onTrack) {
    //  activeEffect!.onTrack({
    //    effect: activeEffect!,
    //    ...debuggerEventExtraInfo!
    //  })
   // }
  }
}

trigger實(shí)現(xiàn)

export function trigger(target, type, key){
    const depsMap = targetMap.get(target);
    if(!depsMap){
        return;
    }
    const run=(effects)=>{
        if(effects){ effects.forEach(effect=>effect()); }
    }
    // 有key 就找到對(duì)應(yīng)的key的依賴執(zhí)行
    if(key !==void0){
        run(depsMap.get(key));
    }
    // 數(shù)組新增屬性
    if(type == TriggerOpTypes.ADD){
        run(depsMap.get(isArray(target)?'length':'');
    }}

依賴關(guān)系

??審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1613

    瀏覽量

    64018
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    671

    瀏覽量

    30323
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Redux設(shè)計(jì)思想源碼解析

    Redux源碼剖析及應(yīng)用
    發(fā)表于 08-02 08:19

    基于TypeScript實(shí)現(xiàn)Vue3.0指令組件拖拽

    最近在用vue3重構(gòu)后臺(tái)的一個(gè)功能。一個(gè)彈窗組件,彈出一個(gè)表單。然后點(diǎn)擊提交。早上運(yùn)維突然跑過(guò)來(lái)問(wèn)我,為啥彈窗擋住了下邊的表格的數(shù)據(jù),我添加的時(shí)候,都沒(méi)法對(duì)照表格來(lái)看了。你必須給我解決一下。我參考了
    發(fā)表于 11-04 06:58

    vue-cli-----vue實(shí)例中template:'<App/>是什么意思?

    哪位大神知道vue-cli-----vue實(shí)例中template:'是什么意思嗎?
    發(fā)表于 11-05 07:02

    Vue框架的教程資料免費(fèi)下載

    Vue是一套用于構(gòu)建用戶界面的漸進(jìn)JavaScript框架。與其它大型框架不同的是,Vue 被設(shè)計(jì)為可以自底向上逐層應(yīng)用。Vue 的核心庫(kù)只關(guān)注視圖層,方便與第三方庫(kù)或既有項(xiàng)目整合。
    發(fā)表于 03-18 08:00 ?0次下載
    <b class='flag-5'>Vue</b>框架的教程資料免費(fèi)下載

    STL源碼剖析的PDF電子書(shū)免費(fèi)下載

    學(xué)習(xí)編程的人都知道,閱讀、剖析名家代碼乃是提高水平的捷徑。源碼之前,了無(wú)秘密。大師們的縝密思維、經(jīng)驗(yàn)結(jié)晶、技術(shù)思路、獨(dú)到風(fēng)格,都原原本本體現(xiàn)在源碼之中。
    發(fā)表于 06-29 08:00 ?0次下載
    STL<b class='flag-5'>源碼</b><b class='flag-5'>剖析</b>的PDF電子書(shū)免費(fèi)下載

    關(guān)于vue如何去水印的解決方法的介紹

    vue軟件,點(diǎn)擊屏幕右下方的標(biāo)識(shí)。2:在彈出的窗口中選擇設(shè)置。的步驟即可,大家一起來(lái)看看小編整理的關(guān)于vue怎么去水印的解決方法: 1:打開(kāi)vue軟件,點(diǎn)擊屏幕右下方的標(biāo)識(shí)。 2:在彈出的窗口中選擇設(shè)置。
    發(fā)表于 03-24 17:33 ?3538次閱讀

    Java編程思想練習(xí)題源碼

    Java編程思想練習(xí)題源碼,配合《Java編程思想》進(jìn)行學(xué)習(xí)。
    發(fā)表于 09-26 14:24 ?0次下載

    關(guān)于React和Vue產(chǎn)生一定的認(rèn)知

    Vue2 相較 Vue3 版本而言牢牢占據(jù)著大部分 Vue 開(kāi)發(fā)者的視野,但是因?yàn)?Vue 官方已經(jīng)把 Vue3 作為默認(rèn)的版本,所以在此同
    的頭像 發(fā)表于 11-02 13:18 ?1058次閱讀

    Vue入門之Vue定義

    Vue (讀音 /vju?/,類似于 view) 是一套用于構(gòu)建用戶界面的漸進(jìn)JavaScript框架。 Vue 的核心庫(kù)只關(guān)注視圖層,也就是只處理頁(yè)面。 Vue提供的一套J
    的頭像 發(fā)表于 02-06 16:41 ?1333次閱讀
    <b class='flag-5'>Vue</b>入門之<b class='flag-5'>Vue</b>定義

    如何使用springboot+vue搭建個(gè)人網(wǎng)站3

    Vue.js(讀音 /vju?/, 類似于 view)是一個(gè)構(gòu)建數(shù)據(jù)驅(qū)動(dòng)的 web 界面的漸進(jìn)框架。Vue現(xiàn)在這么火,大家都懂。接下來(lái)讓我們來(lái)認(rèn)識(shí)一下她的魅力吧~
    的頭像 發(fā)表于 02-14 16:05 ?1607次閱讀
    如何使用springboot+<b class='flag-5'>vue</b>搭建個(gè)人網(wǎng)站<b class='flag-5'>3</b>

    什么是ArcoWork

    Arco Work采用了時(shí)下流行的技術(shù)框架:Vue3、Vite2、Typescript當(dāng)然還有就是 Arco Design了
    的頭像 發(fā)表于 03-01 10:17 ?3979次閱讀
    什么是ArcoWork

    簡(jiǎn)單介紹一下Vue中的響應(yīng)原理

    自從 Vue 發(fā)布以來(lái),就受到了廣大開(kāi)發(fā)人員的青睞,提到 Vue,我們首先想到的就是 Vue響應(yīng)系統(tǒng),那
    的頭像 發(fā)表于 03-13 10:11 ?1000次閱讀

    使用Vue3時(shí)遇到的一些問(wèn)題

    Vue3 目前已經(jīng)趨于穩(wěn)定,不少代碼庫(kù)都已經(jīng)開(kāi)始使用它,很多項(xiàng)目未來(lái)也必然要遷移至 Vue3。本文記錄我在使用 Vue3 時(shí)遇到的一些問(wèn)題,希望能為其他開(kāi)發(fā)者提供幫助。
    的頭像 發(fā)表于 09-13 10:16 ?1337次閱讀
    使用<b class='flag-5'>Vue3</b>時(shí)遇到的一些問(wèn)題

    一文看懂Vue3響應(yīng)系統(tǒng)原理

    Vue3 中,響應(yīng)系統(tǒng)的實(shí)現(xiàn)基于 ES6 的 Proxy 對(duì)象。Proxy 可以直接監(jiān)聽(tīng)對(duì)象和數(shù)組的變化,而無(wú)需對(duì)每個(gè)屬性進(jìn)行監(jiān)聽(tīng),從而大大提高性能。同時(shí),Proxy 也可以解決 Object.defineProperty
    的頭像 發(fā)表于 12-07 10:55 ?2279次閱讀
    一文看懂<b class='flag-5'>Vue3</b><b class='flag-5'>響應(yīng)</b><b class='flag-5'>式</b>系統(tǒng)原理

    bootstrap框架和vue框架的區(qū)別

    響應(yīng)移動(dòng)優(yōu)先的網(wǎng)頁(yè)。Bootstrap的核心設(shè)計(jì)理念是“移動(dòng)優(yōu)先”,即優(yōu)先考慮移動(dòng)設(shè)備的顯示效果,然后通過(guò)媒體查詢等技術(shù)實(shí)現(xiàn)對(duì)不同設(shè)備的適配。Bootstrap提供了一套豐富的CSS和JavaScript組件,可以快速實(shí)現(xiàn)各種常見(jiàn)的網(wǎng)頁(yè)布局和交互效果。
    的頭像 發(fā)表于 07-11 09:55 ?1461次閱讀