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

vue 中Virtual Dom被創(chuàng)建的方法

 更新時(shí)間:2019年04月15日 10:11:05   投稿:mrr  
本文將通過(guò)解讀render函數(shù)的源碼,來(lái)分析vue中的vNode是如何創(chuàng)建的,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

本文將通過(guò)解讀render函數(shù)的源碼,來(lái)分析vue中的vNode是如何創(chuàng)建的。在vue2.x的版本中,無(wú)論是直接書寫render函數(shù),還是使用template或el屬性,或是使用.vue單文件的形式,最終都需要編譯成render函數(shù)進(jìn)行vnode的創(chuàng)建,最終再渲染成真實(shí)的DOM。 如果對(duì)vue源碼的目錄還不是很了解,推薦先閱讀下 深入vue -- 源碼目錄和編譯過(guò)程。

01  render函數(shù)

render方法定義在文件 src/core/instance/render.js 中

Vue.prototype._render = function (): VNode {
 const vm: Component = this
 const { render, _parentVnode } = vm.$options
 // ... 
 // set parent vnode. this allows render functions to have access
 // to the data on the placeholder node.
 vm.$vnode = _parentVnode
 // render self
 let vnode
 try {
  vnode = render.call(vm._renderProxy, vm.$createElement)
 } catch (e) {
  handleError(e, vm, `render`)
  // return error render result,
  // or previous vnode to prevent render error causing blank component
  /* istanbul ignore else */
  if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
  try {
   vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
  } catch (e) {
   handleError(e, vm, `renderError`)
   vnode = vm._vnode
  }
  } else {
  vnode = vm._vnode
  }
 }
 // if the returned array contains only a single node, allow it
 if (Array.isArray(vnode) && vnode.length === 1) {
  vnode = vnode[0]
 }
 // return empty vnode in case the render function errored out
 if (!(vnode instanceof VNode)) {
  if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
  warn(
   'Multiple root nodes returned from render function. Render function ' +
   'should return a single root node.',
   vm
  )
  }
  vnode = createEmptyVNode()
 }
 // set parent
 vnode.parent = _parentVnode
 return vnode
 }

_render定義在vue的原型上,會(huì)返回vnode,vnode通過(guò)代碼render.call(vm._renderProxy, vm.$createElement)進(jìn)行創(chuàng)建。

在創(chuàng)建vnode過(guò)程中,如果出現(xiàn)錯(cuò)誤,就會(huì)執(zhí)行catch中代碼做降級(jí)處理。

_render中最核心的代碼就是:

vnode = render.call(vm._renderProxy, vm.$createElement)

接下來(lái),分析下這里的render,vm._renderProxy,vm.$createElement分別是什么。

render函數(shù)

const { render, _parentVnode } = vm.$options

render方法是從$options中提取的。render方法有兩種途徑得來(lái):

在組件中開發(fā)者直接手寫的render函數(shù)

通過(guò)編譯template屬性生成

參數(shù) vm._renderProxy

vm._renderProxy定義在 src/core/instance/init.js 中,是call的第一個(gè)參數(shù),指定render函數(shù)執(zhí)行的上下文。

/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
 initProxy(vm)
} else {
 vm._renderProxy = vm
}

生產(chǎn)環(huán)境:

vm._renderProxy = vm,也就是說(shuō),在生產(chǎn)環(huán)境,render函數(shù)執(zhí)行的上下文就是當(dāng)前vue實(shí)例,即當(dāng)前組件的this。

開發(fā)環(huán)境:

開發(fā)環(huán)境會(huì)執(zhí)行initProxy(vm),initProxy定義在文件 src/core/instance/proxy.js 中。

let initProxy
// ...
initProxy = function initProxy (vm) {
 if (hasProxy) {
 // determine which proxy handler to use
 const options = vm.$options
 const handlers = options.render && options.render._withStripped
  ? getHandler
  : hasHandler
 vm._renderProxy = new Proxy(vm, handlers)
 } else {
 vm._renderProxy = vm
 }
}

hasProxy的定義如下

const hasProxy =
 typeof Proxy !== 'undefined' && isNative(Proxy)

用來(lái)判斷瀏覽器是否支持es6的Proxy。

Proxy作用是在訪問(wèn)一個(gè)對(duì)象時(shí),對(duì)其進(jìn)行攔截,new Proxy的第一個(gè)參數(shù)表示所要攔截的對(duì)象,第二個(gè)參數(shù)是用來(lái)定制攔截行為的對(duì)象。

開發(fā)環(huán)境,如果支持Proxy就會(huì)對(duì)vm實(shí)例進(jìn)行攔截,否則和生產(chǎn)環(huán)境相同,直接將vm賦值給vm._renderProxy。具體的攔截行為通過(guò)handlers對(duì)象指定。

當(dāng)手寫render函數(shù)時(shí),handlers = hasHandler,通過(guò)template生成的render函數(shù),handlers = getHandler。 hasHandler代碼:

const hasHandler = {
 has (target, key) {
 const has = key in target
 const isAllowed = allowedGlobals(key) ||
  (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data))
 if (!has && !isAllowed) {
  if (key in target.$data) warnReservedPrefix(target, key)
  else warnNonPresent(target, key)
 }
 return has || !isAllowed
 }
}

getHandler代碼

const getHandler = {
 get (target, key) {
 if (typeof key === 'string' && !(key in target)) {
  if (key in target.$data) warnReservedPrefix(target, key)
  else warnNonPresent(target, key)
 }
 return target[key]
 }
}

hasHandler,getHandler分別是對(duì)vm對(duì)象的屬性的讀取和propKey in proxy的操作進(jìn)行攔截,并對(duì)vm的參數(shù)進(jìn)行校驗(yàn),再調(diào)用 warnNonPresent 和 warnReservedPrefix 進(jìn)行Warn警告。

可見,initProxy方法的主要作用就是在開發(fā)時(shí),對(duì)vm實(shí)例進(jìn)行攔截發(fā)現(xiàn)問(wèn)題并拋出錯(cuò)誤,方便開發(fā)者及時(shí)修改問(wèn)題。
參數(shù) vm.$createElement

vm.$createElement就是手寫render函數(shù)時(shí)傳入的createElement函數(shù),它定義在initRender方法中,initRender在new Vue初始化時(shí)執(zhí)行,參數(shù)是實(shí)例vm。

export function initRender (vm: Component) {
 // ...
 // bind the createElement fn to this instance
 // so that we get proper render context inside it.
 // args order: tag, data, children, normalizationType, alwaysNormalize
 // internal version is used by render functions compiled from templates
 vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
 // normalization is always applied for the public version, used in
 // user-written render functions.
 vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
 // ...
}

從代碼的注釋可以看出: vm.$createElement是為開發(fā)者手寫render函數(shù)提供的方法,vm._c是為通過(guò)編譯template生成的render函數(shù)使用的方法。它們都會(huì)調(diào)用createElement方法。

02  createElement方法

createElement方法定義在 src/core/vdom/create-element.js 文件中

const SIMPLE_NORMALIZE = 1
const ALWAYS_NORMALIZE = 2
// wrapper function for providing a more flexible interface
// without getting yelled at by flow
export function createElement (
 context: Component,
 tag: any,
 data: any,
 children: any,
 normalizationType: any,
 alwaysNormalize: boolean
): VNode | Array<VNode> {
 if (Array.isArray(data) || isPrimitive(data)) {
 normalizationType = children
 children = data
 data = undefined
 }
 if (isTrue(alwaysNormalize)) {
 normalizationType = ALWAYS_NORMALIZE
 }
 return _createElement(context, tag, data, children, normalizationType)
}

createElement方法主要是對(duì)參數(shù)做一些處理,再調(diào)用_createElement方法創(chuàng)建vnode。

下面看一下vue文檔中createElement能接收的參數(shù)。

// @returns {VNode}
createElement(
 // {String | Object | Function}
 // 一個(gè) HTML 標(biāo)簽字符串,組件選項(xiàng)對(duì)象,或者
 // 解析上述任何一種的一個(gè) async 異步函數(shù)。必需參數(shù)。
 'div',

 // {Object}
 // 一個(gè)包含模板相關(guān)屬性的數(shù)據(jù)對(duì)象
 // 你可以在 template 中使用這些特性。可選參數(shù)。
 {
 },

 // {String | Array}
 // 子虛擬節(jié)點(diǎn) (VNodes),由 `createElement()` 構(gòu)建而成,
 // 也可以使用字符串來(lái)生成“文本虛擬節(jié)點(diǎn)”??蛇x參數(shù)。
 [
 '先寫一些文字',
 createElement('h1', '一則頭條'),
 createElement(MyComponent, {
  props: {
  someProp: 'foobar'
  }
 })
 ]
)

文檔中除了第一個(gè)參數(shù)是必選參數(shù),其他都是可選參數(shù)。也就是說(shuō)使用createElement方法的時(shí)候,可以不傳第二個(gè)參數(shù),只傳第一個(gè)參數(shù)和第三個(gè)參數(shù)。剛剛說(shuō)的參數(shù)處理就是對(duì)這種情況做處理。

if (Array.isArray(data) || isPrimitive(data)) {
 normalizationType = children
 children = data
 data = undefined
}

通過(guò)判斷data是否是數(shù)組或者是基礎(chǔ)類型,如果滿足這個(gè)條件,說(shuō)明這個(gè)位置傳的參數(shù)是children,然后對(duì)參數(shù)依次重新賦值。這種方式被稱為重載。

重載:函數(shù)名相同,函數(shù)的參數(shù)列表不同(包括參數(shù)個(gè)數(shù)和參數(shù)類型),至于返回類型可同可不同。

處理好參數(shù)后調(diào)用_createElement方法創(chuàng)建vnode。下面是_createElement方法的核心代碼。

export function _createElement (
 context: Component,
 tag?: string | Class<Component> | Function | Object,
 data?: VNodeData,
 children?: any,
 normalizationType?: number
): VNode | Array<VNode> {
 // ...
 if (normalizationType === ALWAYS_NORMALIZE) {
  children = normalizeChildren(children)
 } else if (normalizationType === SIMPLE_NORMALIZE) {
  children = simpleNormalizeChildren(children)
 }
 let vnode, ns
 if (typeof tag === 'string') {
  let Ctor
  // ...
  if (config.isReservedTag(tag)) {
   // platform built-in elements
   vnode = new VNode(
    config.parsePlatformTagName(tag), data, children,
    undefined, undefined, context
   )
  } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
   // component
   vnode = createComponent(Ctor, data, context, children, tag)
  } else {
   // unknown or unlisted namespaced elements
   // check at runtime because it may get assigned a namespace when its
   // parent normalizes children
   vnode = new VNode(
    tag, data, children,
    undefined, undefined, context
   )
  }
 } else {
  // direct component options / constructor
  vnode = createComponent(tag, data, context, children)
 }
 if (Array.isArray(vnode)) {
  return vnode
 } else if (isDef(vnode)) {
  if (isDef(ns)) applyNS(vnode, ns)
  if (isDef(data)) registerDeepBindings(data)
  return vnode
 } else {
  return createEmptyVNode()
 }
}

方法開始會(huì)做判斷,如果data是響應(yīng)式的數(shù)據(jù),component的is屬性不是真值的時(shí)候,都會(huì)去調(diào)用createEmptyVNode方法,創(chuàng)建一個(gè)空的vnode。 接下來(lái),根據(jù)normalizationType的值,調(diào)用normalizeChildren或simpleNormalizeChildren方法對(duì)參數(shù)children進(jìn)行處理。這兩個(gè)方法定義在 src/core/vdom/helpers/normalize-children.js 文件下。

// 1. When the children contains components - because a functional component
// may return an Array instead of a single root. In this case, just a simple
// normalization is needed - if any child is an Array, we flatten the whole
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
// because functional components already normalize their own children.
export function simpleNormalizeChildren (children: any) {
 for (let i = 0; i < children.length; i++) {
  if (Array.isArray(children[i])) {
   return Array.prototype.concat.apply([], children)
  }
 }
 return children
}

// 2. When the children contains constructs that always generated nested Arrays,
// e.g. <template>, <slot>, v-for, or when the children is provided by user
// with hand-written render functions / JSX. In such cases a full normalization
// is needed to cater to all possible types of children values.
export function normalizeChildren (children: any): ?Array<VNode> {
 return isPrimitive(children)
  ? [createTextVNode(children)]
  : Array.isArray(children)
   ? normalizeArrayChildren(children)
   : undefined
}

normalizeChildren和simpleNormalizeChildren的目的都是將children數(shù)組扁平化處理,最終返回一個(gè)vnode的一維數(shù)組。
simpleNormalizeChildren是針對(duì)函數(shù)式組件做處理,所以只需要考慮children是二維數(shù)組的情況。 normalizeChildren方法會(huì)考慮children是多層嵌套的數(shù)組的情況。normalizeChildren開始會(huì)判斷children的類型,如果children是基礎(chǔ)類型,直接創(chuàng)建文本vnode,如果是數(shù)組,調(diào)用normalizeArrayChildren方法,并在normalizeArrayChildren方法里面進(jìn)行遞歸調(diào)用,最終將children轉(zhuǎn)成一維數(shù)組。

接下來(lái),繼續(xù)看_createElement方法,如果tag參數(shù)的類型不是String類型,是組件的話,調(diào)用createComponent創(chuàng)建vnode。如果tag是String類型,再去判斷tag是否是html的保留標(biāo)簽,是否是不認(rèn)識(shí)的節(jié)點(diǎn),通過(guò)調(diào)用new VNode(),傳入不同的參數(shù)來(lái)創(chuàng)建vnode實(shí)例。

無(wú)論是哪種情況,最終都是通過(guò)VNode這個(gè)class來(lái)創(chuàng)建vnode,下面是類VNode的源碼,在文件 src/core/vdom/vnode.js 中定義

export default class VNode {
 tag: string | void;
 data: VNodeData | void;
 children: ?Array<VNode>;
 text: string | void;
 elm: Node | void;
 ns: string | void;
 context: Component | void; // rendered in this component's scope
 key: string | number | void;
 componentOptions: VNodeComponentOptions | void;
 componentInstance: Component | void; // component instance
 parent: VNode | void; // component placeholder node

 // strictly internal
 raw: boolean; // contains raw HTML? (server only)
 isStatic: boolean; // hoisted static node
 isRootInsert: boolean; // necessary for enter transition check
 isComment: boolean; // empty comment placeholder?
 isCloned: boolean; // is a cloned node?
 isOnce: boolean; // is a v-once node?
 asyncFactory: Function | void; // async component factory function
 asyncMeta: Object | void;
 isAsyncPlaceholder: boolean;
 ssrContext: Object | void;
 fnContext: Component | void; // real context vm for functional nodes
 fnOptions: ?ComponentOptions; // for SSR caching
 devtoolsMeta: ?Object; // used to store functional render context for devtools
 fnScopeId: ?string; // functional scope id support

 constructor (
  tag?: string,
  data?: VNodeData,
  children?: ?Array<VNode>,
  text?: string,
  elm?: Node,
  context?: Component,
  componentOptions?: VNodeComponentOptions,
  asyncFactory?: Function
) {
  this.tag = tag // 標(biāo)簽名
  this.data = data // 當(dāng)前節(jié)點(diǎn)數(shù)據(jù)
  this.children = children // 子節(jié)點(diǎn)
  this.text = text // 文本
  this.elm = elm // 對(duì)應(yīng)的真實(shí)DOM節(jié)點(diǎn)
  this.ns = undefined // 命名空間
  this.context = context // 當(dāng)前節(jié)點(diǎn)上下文
  this.fnContext = undefined // 函數(shù)化組件上下文
  this.fnOptions = undefined // 函數(shù)化組件配置參數(shù)
  this.fnScopeId = undefined // 函數(shù)化組件ScopeId
  this.key = data && data.key // 子節(jié)點(diǎn)key屬性
  this.componentOptions = componentOptions // 組件配置項(xiàng) 
  this.componentInstance = undefined // 組件實(shí)例
  this.parent = undefined // 父節(jié)點(diǎn)
  this.raw = false // 是否是原生的HTML片段或只是普通文本
  this.isStatic = false // 靜態(tài)節(jié)點(diǎn)標(biāo)記
  this.isRootInsert = true // 是否作為根節(jié)點(diǎn)插入
  this.isComment = false // 是否為注釋節(jié)點(diǎn)
  this.isCloned = false // 是否為克隆節(jié)點(diǎn)
  this.isOnce = false // 是否有v-once指令
  this.asyncFactory = asyncFactory // 異步工廠方法 
  this.asyncMeta = undefined // 異步Meta
  this.isAsyncPlaceholder = false // 是否異步占位
 }

 // DEPRECATED: alias for componentInstance for backwards compat.
 /* istanbul ignore next */
 get child (): Component | void {
  return this.componentInstance
 }
}

VNode類定義的數(shù)據(jù),都是用來(lái)描述VNode的。

至此,render函數(shù)創(chuàng)建vdom的源碼就分析完了,我們簡(jiǎn)單的總結(jié)梳理一下。

_render 定義在 Vue.prototype 上,_render函數(shù)執(zhí)行會(huì)調(diào)用方法render,在開發(fā)環(huán)境下,會(huì)對(duì)vm實(shí)例進(jìn)行代理,校驗(yàn)vm實(shí)例數(shù)據(jù)正確性。render函數(shù)內(nèi),會(huì)執(zhí)行render的參數(shù)createElement方法,createElement會(huì)對(duì)參數(shù)進(jìn)行處理,處理參數(shù)后調(diào)用_createElement, _createElement方法內(nèi)部最終會(huì)直接或間接調(diào)用new VNode(), 創(chuàng)建vnode實(shí)例。

03   vnode && vdom

createElement 返回的vnode并不是真正的dom元素,VNode的全稱叫做“虛擬節(jié)點(diǎn) (Virtual Node)”,它所包含的信息會(huì)告訴 Vue 頁(yè)面上需要渲染什么樣的節(jié)點(diǎn),及其子節(jié)點(diǎn)。我們常說(shuō)的“虛擬 DOM(Virtual Dom)”是對(duì)由 Vue 組件樹建立起來(lái)的整個(gè) VNode 樹的稱呼。

04  心得

讀源碼切忌只看源碼,一定要結(jié)合具體的使用一起分析,這樣才能更清楚的了解某段代碼的意圖。就像本文render函數(shù),如果從來(lái)沒有使用過(guò)render函數(shù),直接就閱讀這塊源碼可能會(huì)比較吃力,不妨先看看文檔,寫個(gè)demo,看看具體的使用,再對(duì)照使用來(lái)分析源碼,這樣很多比較困惑的問(wèn)題就迎刃而解了。

總結(jié)

以上所述是小編給大家介紹的vue 中Virtual Dom被創(chuàng)建的方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!

相關(guān)文章

  • Flutter部件內(nèi)部狀態(tài)管理小結(jié)之實(shí)現(xiàn)Vue的v-model功能

    Flutter部件內(nèi)部狀態(tài)管理小結(jié)之實(shí)現(xiàn)Vue的v-model功能

    本文是 Flutter 部件內(nèi)部狀態(tài)管理的小結(jié),從部件的基礎(chǔ)開始,到部件的狀態(tài)管理,并且在過(guò)程中實(shí)現(xiàn)一個(gè)類似 Vue 的 v-model 的功能,感興趣的朋友跟隨小編一起看看吧
    2019-06-06
  • vue3.0中使用element的完整步驟

    vue3.0中使用element的完整步驟

    這篇文章主要給大家介紹了關(guān)于vue3.0中使用element的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • vue+iview寫個(gè)彈框的示例代碼

    vue+iview寫個(gè)彈框的示例代碼

    本篇文章主要介紹了vue+iview寫個(gè)彈框的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • VUE項(xiàng)目中封裝Echart折線圖的方法

    VUE項(xiàng)目中封裝Echart折線圖的方法

    這篇文章主要為大家詳細(xì)介紹了VUE項(xiàng)目中封裝Echart折線圖的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Vue中動(dòng)態(tài)添加ref的方法詳解

    Vue中動(dòng)態(tài)添加ref的方法詳解

    在Vue.js項(xiàng)目中,ref是一個(gè)非常有用的功能,它可以用來(lái)獲取DOM元素或子組件的實(shí)例引用,通過(guò)ref,我們可以在父組件中直接操作子組件的方法和屬性,或者對(duì)DOM元素進(jìn)行直接操作,本文將詳細(xì)介紹如何在Vue中動(dòng)態(tài)添加ref,并通過(guò)多個(gè)具體的代碼示例來(lái)幫助讀者理解其實(shí)現(xiàn)過(guò)程
    2024-10-10
  • Element中el-input密碼輸入框?yàn)g覽器自動(dòng)填充賬號(hào)密碼問(wèn)題的解決方法

    Element中el-input密碼輸入框?yàn)g覽器自動(dòng)填充賬號(hào)密碼問(wèn)題的解決方法

    自己寫了一個(gè)管理系統(tǒng),登錄成功之后,瀏覽器提示我保存賬號(hào)密碼,每次登錄時(shí)就會(huì)自動(dòng)回填記住的賬號(hào)密碼,方便用戶快速登錄,下面這篇文章主要給大家介紹了關(guān)于Element中el-input密碼輸入框?yàn)g覽器自動(dòng)填充賬號(hào)密碼問(wèn)題的解決方法,需要的朋友可以參考下
    2022-09-09
  • vue項(xiàng)目中常見的三種文件類型在線預(yù)覽實(shí)現(xiàn)(pdf/word/excel表格)

    vue項(xiàng)目中常見的三種文件類型在線預(yù)覽實(shí)現(xiàn)(pdf/word/excel表格)

    最近在項(xiàng)目中要做一個(gè)pdf在線預(yù)覽的功能,索性給大家整理個(gè)全面的,這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中常見的三種文件類型在線預(yù)覽實(shí)現(xiàn)的相關(guān)資料,文件類型分別是pdf/word文件/excel表格,需要的朋友可以參考下
    2022-05-05
  • Vue中的Token過(guò)期驗(yàn)證與動(dòng)態(tài)路由重定向詳解

    Vue中的Token過(guò)期驗(yàn)證與動(dòng)態(tài)路由重定向詳解

    這篇文章主要為大家詳細(xì)介紹了如何在 Vue 項(xiàng)目中實(shí)現(xiàn) Token 過(guò)期驗(yàn)證,并根據(jù) Token 的有效期動(dòng)態(tài)重定向用戶到首頁(yè)或登錄頁(yè),感興趣的小伙伴可以了解下
    2025-03-03
  • vue實(shí)現(xiàn)移動(dòng)端圖片上傳功能

    vue實(shí)現(xiàn)移動(dòng)端圖片上傳功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)移動(dòng)端圖片上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • vue項(xiàng)目下載文件重命名監(jiān)測(cè)進(jìn)度demo

    vue項(xiàng)目下載文件重命名監(jiān)測(cè)進(jìn)度demo

    這篇文章主要為大家介紹了vue項(xiàng)目下載文件重命名監(jiān)測(cè)進(jìn)度demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評(píng)論

云梦县| 长白| 定西市| 永平县| 松溪县| 莒南县| 溆浦县| 呼玛县| 元氏县| 瑞安市| 运城市| 凤庆县| 景东| 嘉峪关市| 石渠县| 高青县| 绥棱县| 子洲县| 祁阳县| 五原县| 安康市| 无为县| 红河县| 丹江口市| 兴隆县| 罗山县| 根河市| 湖南省| 申扎县| 滦南县| 苏州市| 彭州市| 同心县| 金秀| 尚志市| 平潭县| 广河县| 峡江县| 新营市| 东至县| 巢湖市|