2023-12-18 13:12:25 +08:00
/ * !
2024-01-16 21:26:16 +08:00
* Vue . js v2 . 7.16
* ( c ) 2014 - 2023 Evan You
2023-12-18 13:12:25 +08:00
* Released under the MIT License .
* /
'use strict' ;
2024-01-16 21:26:16 +08:00
const emptyObject = Object . freeze ( { } ) ;
const isArray = Array . isArray ;
2023-12-18 13:12:25 +08:00
// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.
2024-01-16 21:26:16 +08:00
function isUndef ( v ) {
return v === undefined || v === null ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isDef ( v ) {
return v !== undefined && v !== null ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isTrue ( v ) {
return v === true ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isFalse ( v ) {
return v === false ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if value is primitive .
* /
2024-01-16 21:26:16 +08:00
function isPrimitive ( value ) {
return ( typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean' ) ;
}
function isFunction ( value ) {
return typeof value === 'function' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Quick object check - this is primarily used to tell
2024-01-16 21:26:16 +08:00
* objects from primitive values when we know the value
2023-12-18 13:12:25 +08:00
* is a JSON - compliant type .
* /
2024-01-16 21:26:16 +08:00
function isObject ( obj ) {
return obj !== null && typeof obj === 'object' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Get the raw type string of a value , e . g . , [ object Object ] .
* /
2024-01-16 21:26:16 +08:00
const _toString = Object . prototype . toString ;
function toRawType ( value ) {
return _toString . call ( value ) . slice ( 8 , - 1 ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Strict object type check . Only returns true
* for plain JavaScript objects .
* /
2024-01-16 21:26:16 +08:00
function isPlainObject ( obj ) {
return _toString . call ( obj ) === '[object Object]' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isRegExp ( v ) {
return _toString . call ( v ) === '[object RegExp]' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if val is a valid array index .
* /
2024-01-16 21:26:16 +08:00
function isValidArrayIndex ( val ) {
const n = parseFloat ( String ( val ) ) ;
return n >= 0 && Math . floor ( n ) === n && isFinite ( val ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isPromise ( val ) {
return ( isDef ( val ) &&
typeof val . then === 'function' &&
typeof val . catch === 'function' ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Convert a value to a string that is actually rendered .
* /
2024-01-16 21:26:16 +08:00
function toString ( val ) {
return val == null
? ''
: Array . isArray ( val ) || ( isPlainObject ( val ) && val . toString === _toString )
? JSON . stringify ( val , replacer , 2 )
: String ( val ) ;
}
function replacer ( _key , val ) {
// avoid circular deps from v3
if ( val && val . _ _v _isRef ) {
return val . value ;
}
return val ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Convert an input value to a number for persistence .
* If the conversion fails , return original string .
* /
2024-01-16 21:26:16 +08:00
function toNumber ( val ) {
const n = parseFloat ( val ) ;
return isNaN ( n ) ? val : n ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Make a map and return a function for checking if a key
* is in that map .
* /
2024-01-16 21:26:16 +08:00
function makeMap ( str , expectsLowerCase ) {
const map = Object . create ( null ) ;
const list = str . split ( ',' ) ;
for ( let i = 0 ; i < list . length ; i ++ ) {
map [ list [ i ] ] = true ;
}
return expectsLowerCase ? val => map [ val . toLowerCase ( ) ] : val => map [ val ] ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if a tag is a built - in tag .
* /
2024-01-16 21:26:16 +08:00
const isBuiltInTag = makeMap ( 'slot,component' , true ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Check if an attribute is a reserved attribute .
* /
2024-01-16 21:26:16 +08:00
const isReservedAttribute = makeMap ( 'key,ref,slot,slot-scope,is' ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Remove an item from an array .
* /
2024-01-16 21:26:16 +08:00
function remove$2 ( arr , item ) {
const len = arr . length ;
if ( len ) {
// fast path for the only / last item
if ( item === arr [ len - 1 ] ) {
arr . length = len - 1 ;
return ;
}
const index = arr . indexOf ( item ) ;
if ( index > - 1 ) {
return arr . splice ( index , 1 ) ;
}
2023-12-18 13:12:25 +08:00
}
}
/ * *
* Check whether an object has the property .
* /
2024-01-16 21:26:16 +08:00
const hasOwnProperty = Object . prototype . hasOwnProperty ;
function hasOwn ( obj , key ) {
return hasOwnProperty . call ( obj , key ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Create a cached version of a pure function .
* /
2024-01-16 21:26:16 +08:00
function cached ( fn ) {
const cache = Object . create ( null ) ;
return function cachedFn ( str ) {
const hit = cache [ str ] ;
return hit || ( cache [ str ] = fn ( str ) ) ;
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Camelize a hyphen - delimited string .
* /
2024-01-16 21:26:16 +08:00
const camelizeRE = /-(\w)/g ;
const camelize = cached ( ( str ) => {
return str . replace ( camelizeRE , ( _ , c ) => ( c ? c . toUpperCase ( ) : '' ) ) ;
2023-12-18 13:12:25 +08:00
} ) ;
/ * *
* Capitalize a string .
* /
2024-01-16 21:26:16 +08:00
const capitalize = cached ( ( str ) => {
return str . charAt ( 0 ) . toUpperCase ( ) + str . slice ( 1 ) ;
2023-12-18 13:12:25 +08:00
} ) ;
/ * *
* Hyphenate a camelCase string .
* /
2024-01-16 21:26:16 +08:00
const hyphenateRE = /\B([A-Z])/g ;
const hyphenate = cached ( ( str ) => {
return str . replace ( hyphenateRE , '-$1' ) . toLowerCase ( ) ;
2023-12-18 13:12:25 +08:00
} ) ;
/ * *
* Simple bind polyfill for environments that do not support it ,
* e . g . , PhantomJS 1. x . Technically , we don ' t need this anymore
* since native bind is now performant enough in most browsers .
* But removing it would mean breaking code that was able to run in
* PhantomJS 1. x , so this must be kept for backward compatibility .
* /
/* istanbul ignore next */
2024-01-16 21:26:16 +08:00
function polyfillBind ( fn , ctx ) {
function boundFn ( a ) {
const l = arguments . length ;
return l
? l > 1
? fn . apply ( ctx , arguments )
: fn . call ( ctx , a )
: fn . call ( ctx ) ;
}
boundFn . _length = fn . length ;
return boundFn ;
}
function nativeBind ( fn , ctx ) {
return fn . bind ( ctx ) ;
}
// @ts-expect-error bind cannot be `undefined`
const bind = Function . prototype . bind ? nativeBind : polyfillBind ;
2023-12-18 13:12:25 +08:00
/ * *
* Convert an Array - like object to a real Array .
* /
2024-01-16 21:26:16 +08:00
function toArray ( list , start ) {
start = start || 0 ;
let i = list . length - start ;
const ret = new Array ( i ) ;
while ( i -- ) {
ret [ i ] = list [ i + start ] ;
}
return ret ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Mix properties into target object .
* /
2024-01-16 21:26:16 +08:00
function extend ( to , _from ) {
for ( const key in _from ) {
to [ key ] = _from [ key ] ;
}
return to ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Merge an Array of Objects into a single Object .
* /
2024-01-16 21:26:16 +08:00
function toObject ( arr ) {
const res = { } ;
for ( let i = 0 ; i < arr . length ; i ++ ) {
if ( arr [ i ] ) {
extend ( res , arr [ i ] ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return res ;
2023-12-18 13:12:25 +08:00
}
/* eslint-disable no-unused-vars */
/ * *
* Perform no operation .
* Stubbing args to make Flow happy without leaving useless transpiled code
* with ... rest ( https : //flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).
* /
2024-01-16 21:26:16 +08:00
function noop ( a , b , c ) { }
2023-12-18 13:12:25 +08:00
/ * *
* Always return false .
* /
2024-01-16 21:26:16 +08:00
const no = ( a , b , c ) => false ;
2023-12-18 13:12:25 +08:00
/* eslint-enable no-unused-vars */
/ * *
* Return the same value .
* /
2024-01-16 21:26:16 +08:00
const identity = ( _ ) => _ ;
2023-12-18 13:12:25 +08:00
/ * *
* Check if two values are loosely equal - that is ,
* if they are plain objects , do they have the same shape ?
* /
2024-01-16 21:26:16 +08:00
function looseEqual ( a , b ) {
if ( a === b )
return true ;
const isObjectA = isObject ( a ) ;
const isObjectB = isObject ( b ) ;
if ( isObjectA && isObjectB ) {
try {
const isArrayA = Array . isArray ( a ) ;
const isArrayB = Array . isArray ( b ) ;
if ( isArrayA && isArrayB ) {
return ( a . length === b . length &&
a . every ( ( e , i ) => {
return looseEqual ( e , b [ i ] ) ;
} ) ) ;
}
else if ( a instanceof Date && b instanceof Date ) {
return a . getTime ( ) === b . getTime ( ) ;
}
else if ( ! isArrayA && ! isArrayB ) {
const keysA = Object . keys ( a ) ;
const keysB = Object . keys ( b ) ;
return ( keysA . length === keysB . length &&
keysA . every ( key => {
return looseEqual ( a [ key ] , b [ key ] ) ;
} ) ) ;
}
else {
/* istanbul ignore next */
return false ;
}
}
catch ( e ) {
/* istanbul ignore next */
return false ;
}
}
else if ( ! isObjectA && ! isObjectB ) {
return String ( a ) === String ( b ) ;
}
else {
return false ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Return the first index at which a loosely equal value can be
* found in the array ( if value is a plain object , the array must
* contain an object of the same shape ) , or - 1 if it is not present .
* /
2024-01-16 21:26:16 +08:00
function looseIndexOf ( arr , val ) {
for ( let i = 0 ; i < arr . length ; i ++ ) {
if ( looseEqual ( arr [ i ] , val ) )
return i ;
}
return - 1 ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Ensure a function is called only once .
* /
2024-01-16 21:26:16 +08:00
function once ( fn ) {
let called = false ;
return function ( ) {
if ( ! called ) {
called = true ;
fn . apply ( this , arguments ) ;
}
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill
function hasChanged ( x , y ) {
if ( x === y ) {
return x === 0 && 1 / x !== 1 / y ;
}
else {
return x === x || y === y ;
}
}
const SSR _ATTR = 'data-server-rendered' ;
const ASSET _TYPES = [ 'component' , 'directive' , 'filter' ] ;
const LIFECYCLE _HOOKS = [
'beforeCreate' ,
'created' ,
'beforeMount' ,
'mounted' ,
'beforeUpdate' ,
'updated' ,
'beforeDestroy' ,
'destroyed' ,
'activated' ,
'deactivated' ,
'errorCaptured' ,
'serverPrefetch' ,
'renderTracked' ,
'renderTriggered'
2023-12-18 13:12:25 +08:00
] ;
2024-01-16 21:26:16 +08:00
var config = {
/ * *
* Option merge strategies ( used in core / util / options )
* /
// $flow-disable-line
optionMergeStrategies : Object . create ( null ) ,
/ * *
* Whether to suppress warnings .
* /
silent : false ,
/ * *
* Show production mode tip message on boot ?
* /
productionTip : true ,
/ * *
* Whether to enable devtools
* /
devtools : true ,
/ * *
* Whether to record perf
* /
performance : false ,
/ * *
* Error handler for watcher errors
* /
errorHandler : null ,
/ * *
* Warn handler for watcher warns
* /
warnHandler : null ,
/ * *
* Ignore certain custom elements
* /
ignoredElements : [ ] ,
/ * *
* Custom user key aliases for v - on
* /
// $flow-disable-line
keyCodes : Object . create ( null ) ,
/ * *
* Check if a tag is reserved so that it cannot be registered as a
* component . This is platform - dependent and may be overwritten .
* /
isReservedTag : no ,
/ * *
* Check if an attribute is reserved so that it cannot be used as a component
* prop . This is platform - dependent and may be overwritten .
* /
isReservedAttr : no ,
/ * *
* Check if a tag is an unknown element .
* Platform - dependent .
* /
isUnknownElement : no ,
/ * *
* Get the namespace of an element
* /
getTagNamespace : noop ,
/ * *
* Parse the real tag name for the specific platform .
* /
parsePlatformTagName : identity ,
/ * *
* Check if an attribute must be bound using property , e . g . value
* Platform - dependent .
* /
mustUseProp : no ,
/ * *
* Perform updates asynchronously . Intended to be used by Vue Test Utils
* This will significantly reduce performance if set to false .
* /
async : true ,
/ * *
* Exposed for legacy reasons
* /
_lifecycleHooks : LIFECYCLE _HOOKS
} ;
2023-12-18 13:12:25 +08:00
/ * *
* unicode letters used for parsing html tags , component names and property paths .
* using https : //www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname
* skipping \u10000 - \uEFFFF due to it freezing up PhantomJS
* /
2024-01-16 21:26:16 +08:00
const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/ ;
2023-12-18 13:12:25 +08:00
/ * *
* Check if a string starts with $ or _
* /
2024-01-16 21:26:16 +08:00
function isReserved ( str ) {
const c = ( str + '' ) . charCodeAt ( 0 ) ;
return c === 0x24 || c === 0x5f ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Define a property .
* /
2024-01-16 21:26:16 +08:00
function def ( obj , key , val , enumerable ) {
Object . defineProperty ( obj , key , {
value : val ,
enumerable : ! ! enumerable ,
writable : true ,
configurable : true
} ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Parse simple path .
* /
2024-01-16 21:26:16 +08:00
const bailRE = new RegExp ( ` [^ ${ unicodeRegExp . source } . $ _ \\ d] ` ) ;
function parsePath ( path ) {
if ( bailRE . test ( path ) ) {
return ;
}
const segments = path . split ( '.' ) ;
return function ( obj ) {
for ( let i = 0 ; i < segments . length ; i ++ ) {
if ( ! obj )
return ;
obj = obj [ segments [ i ] ] ;
}
return obj ;
} ;
2023-12-18 13:12:25 +08:00
}
// can we use __proto__?
2024-01-16 21:26:16 +08:00
const hasProto = '__proto__' in { } ;
2023-12-18 13:12:25 +08:00
// Browser environment sniffing
2024-01-16 21:26:16 +08:00
const inBrowser = typeof window !== 'undefined' ;
const UA = inBrowser && window . navigator . userAgent . toLowerCase ( ) ;
const isIE = UA && /msie|trident/ . test ( UA ) ;
const isIE9 = UA && UA . indexOf ( 'msie 9.0' ) > 0 ;
const isEdge = UA && UA . indexOf ( 'edge/' ) > 0 ;
UA && UA . indexOf ( 'android' ) > 0 ;
const isIOS = UA && /iphone|ipad|ipod|ios/ . test ( UA ) ;
UA && /chrome\/\d+/ . test ( UA ) && ! isEdge ;
UA && /phantomjs/ . test ( UA ) ;
const isFF = UA && UA . match ( /firefox\/(\d+)/ ) ;
2023-12-18 13:12:25 +08:00
// Firefox has a "watch" function on Object.prototype...
2024-01-16 21:26:16 +08:00
// @ts-expect-error firebox support
const nativeWatch = { } . watch ;
let supportsPassive = false ;
2023-12-18 13:12:25 +08:00
if ( inBrowser ) {
2024-01-16 21:26:16 +08:00
try {
const opts = { } ;
Object . defineProperty ( opts , 'passive' , {
get ( ) {
/* istanbul ignore next */
supportsPassive = true ;
}
} ) ; // https://github.com/facebook/flow/issues/285
window . addEventListener ( 'test-passive' , null , opts ) ;
}
catch ( e ) { }
2023-12-18 13:12:25 +08:00
}
// this needs to be lazy-evaled because vue may be required before
// vue-server-renderer can set VUE_ENV
2024-01-16 21:26:16 +08:00
let _isServer ;
const isServerRendering = ( ) => {
if ( _isServer === undefined ) {
/* istanbul ignore if */
if ( ! inBrowser && typeof global !== 'undefined' ) {
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
_isServer =
global [ 'process' ] && global [ 'process' ] . env . VUE _ENV === 'server' ;
}
else {
_isServer = false ;
}
}
return _isServer ;
2023-12-18 13:12:25 +08:00
} ;
// detect devtools
2024-01-16 21:26:16 +08:00
const devtools = inBrowser && window . _ _VUE _DEVTOOLS _GLOBAL _HOOK _ _ ;
2023-12-18 13:12:25 +08:00
/* istanbul ignore next */
2024-01-16 21:26:16 +08:00
function isNative ( Ctor ) {
return typeof Ctor === 'function' && /native code/ . test ( Ctor . toString ( ) ) ;
}
const hasSymbol = typeof Symbol !== 'undefined' &&
isNative ( Symbol ) &&
typeof Reflect !== 'undefined' &&
isNative ( Reflect . ownKeys ) ;
let _Set ; // $flow-disable-line
/* istanbul ignore if */ if ( typeof Set !== 'undefined' && isNative ( Set ) ) {
// use native Set when available.
_Set = Set ;
}
else {
// a non-standard Set polyfill that only works with primitive keys.
_Set = class Set {
constructor ( ) {
this . set = Object . create ( null ) ;
}
has ( key ) {
return this . set [ key ] === true ;
}
add ( key ) {
this . set [ key ] = true ;
}
clear ( ) {
this . set = Object . create ( null ) ;
}
2023-12-18 13:12:25 +08:00
} ;
}
2024-01-16 21:26:16 +08:00
let currentInstance = null ;
/ * *
* This is exposed for compatibility with v3 ( e . g . some functions in VueUse
* relies on it ) . Do not use this internally , just use ` currentInstance ` .
*
* @ internal this function needs manual type declaration because it relies
* on previously manually authored types from Vue 2
* /
function getCurrentInstance ( ) {
return currentInstance && { proxy : currentInstance } ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* @ internal
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function setCurrentInstance ( vm = null ) {
if ( ! vm )
currentInstance && currentInstance . _scope . off ( ) ;
currentInstance = vm ;
vm && vm . _scope . on ( ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* @ internal
* /
class VNode {
constructor ( tag , data , children , text , elm , context , componentOptions , asyncFactory ) {
this . tag = tag ;
this . data = data ;
this . children = children ;
this . text = text ;
this . elm = elm ;
this . ns = undefined ;
this . context = context ;
this . fnContext = undefined ;
this . fnOptions = undefined ;
this . fnScopeId = undefined ;
this . key = data && data . key ;
this . componentOptions = componentOptions ;
this . componentInstance = undefined ;
this . parent = undefined ;
this . raw = false ;
this . isStatic = false ;
this . isRootInsert = true ;
this . isComment = false ;
this . isCloned = false ;
this . isOnce = false ;
this . asyncFactory = asyncFactory ;
this . asyncMeta = undefined ;
this . isAsyncPlaceholder = false ;
}
// DEPRECATED: alias for componentInstance for backwards compat.
/* istanbul ignore next */
get child ( ) {
return this . componentInstance ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const createEmptyVNode = ( text = '' ) => {
const node = new VNode ( ) ;
node . text = text ;
node . isComment = true ;
return node ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function createTextVNode ( val ) {
return new VNode ( undefined , undefined , undefined , String ( val ) ) ;
2023-12-18 13:12:25 +08:00
}
// optimized shallow clone
// used for static nodes and slot nodes because they may be reused across
// multiple renders, cloning them avoids errors when DOM manipulations rely
// on their elm reference.
2024-01-16 21:26:16 +08:00
function cloneVNode ( vnode ) {
const cloned = new VNode ( vnode . tag , vnode . data ,
2023-12-18 13:12:25 +08:00
// #7975
// clone children array to avoid mutating original in case of cloning
// a child.
2024-01-16 21:26:16 +08:00
vnode . children && vnode . children . slice ( ) , vnode . text , vnode . elm , vnode . context , vnode . componentOptions , vnode . asyncFactory ) ;
cloned . ns = vnode . ns ;
cloned . isStatic = vnode . isStatic ;
cloned . key = vnode . key ;
cloned . isComment = vnode . isComment ;
cloned . fnContext = vnode . fnContext ;
cloned . fnOptions = vnode . fnOptions ;
cloned . fnScopeId = vnode . fnScopeId ;
cloned . asyncMeta = vnode . asyncMeta ;
cloned . isCloned = true ;
return cloned ;
}
let uid$2 = 0 ;
const pendingCleanupDeps = [ ] ;
const cleanupDeps = ( ) => {
for ( let i = 0 ; i < pendingCleanupDeps . length ; i ++ ) {
const dep = pendingCleanupDeps [ i ] ;
dep . subs = dep . subs . filter ( s => s ) ;
dep . _pending = false ;
}
pendingCleanupDeps . length = 0 ;
} ;
/ * *
* A dep is an observable that can have multiple
* directives subscribing to it .
* @ internal
* /
class Dep {
constructor ( ) {
// pending subs cleanup
this . _pending = false ;
this . id = uid$2 ++ ;
this . subs = [ ] ;
}
addSub ( sub ) {
this . subs . push ( sub ) ;
}
removeSub ( sub ) {
// #12696 deps with massive amount of subscribers are extremely slow to
// clean up in Chromium
// to workaround this, we unset the sub for now, and clear them on
// next scheduler flush.
this . subs [ this . subs . indexOf ( sub ) ] = null ;
if ( ! this . _pending ) {
this . _pending = true ;
pendingCleanupDeps . push ( this ) ;
}
}
depend ( info ) {
if ( Dep . target ) {
Dep . target . addDep ( this ) ;
if ( info && Dep . target . onTrack ) {
Dep . target . onTrack ( Object . assign ( { effect : Dep . target } , info ) ) ;
}
}
}
notify ( info ) {
// stabilize the subscriber list first
const subs = this . subs . filter ( s => s ) ;
if ( ! config . async ) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs . sort ( ( a , b ) => a . id - b . id ) ;
}
for ( let i = 0 , l = subs . length ; i < l ; i ++ ) {
const sub = subs [ i ] ;
if ( info ) {
sub . onTrigger &&
sub . onTrigger ( Object . assign ( { effect : subs [ i ] } , info ) ) ;
}
sub . update ( ) ;
}
}
}
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep . target = null ;
const targetStack = [ ] ;
function pushTarget ( target ) {
targetStack . push ( target ) ;
Dep . target = target ;
}
function popTarget ( ) {
targetStack . pop ( ) ;
Dep . target = targetStack [ targetStack . length - 1 ] ;
2023-12-18 13:12:25 +08:00
}
/ *
* not type checking this file because flow doesn ' t play well with
* dynamically accessing methods on Array prototype
* /
2024-01-16 21:26:16 +08:00
const arrayProto = Array . prototype ;
const arrayMethods = Object . create ( arrayProto ) ;
const methodsToPatch = [
'push' ,
'pop' ,
'shift' ,
'unshift' ,
'splice' ,
'sort' ,
'reverse'
2023-12-18 13:12:25 +08:00
] ;
/ * *
* Intercept mutating methods and emit events
* /
methodsToPatch . forEach ( function ( method ) {
2024-01-16 21:26:16 +08:00
// cache original method
const original = arrayProto [ method ] ;
def ( arrayMethods , method , function mutator ( ... args ) {
const result = original . apply ( this , args ) ;
const ob = this . _ _ob _ _ ;
let inserted ;
switch ( method ) {
case 'push' :
case 'unshift' :
inserted = args ;
break ;
case 'splice' :
inserted = args . slice ( 2 ) ;
break ;
}
if ( inserted )
ob . observeArray ( inserted ) ;
// notify change
{
ob . dep . notify ( {
type : "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */ ,
target : this ,
key : method
} ) ;
}
return result ;
} ) ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
const arrayKeys = Object . getOwnPropertyNames ( arrayMethods ) ;
const NO _INITIAL _VALUE = { } ;
2023-12-18 13:12:25 +08:00
/ * *
* In some cases we may want to disable observation inside a component ' s
* update computation .
* /
2024-01-16 21:26:16 +08:00
let shouldObserve = true ;
function toggleObserving ( value ) {
shouldObserve = value ;
}
// ssr mock dep
const mockDep = {
notify : noop ,
depend : noop ,
addSub : noop ,
removeSub : noop
} ;
2023-12-18 13:12:25 +08:00
/ * *
* Observer class that is attached to each observed
* object . Once attached , the observer converts the target
* object ' s property keys into getter / setters that
* collect dependencies and dispatch updates .
* /
2024-01-16 21:26:16 +08:00
class Observer {
constructor ( value , shallow = false , mock = false ) {
this . value = value ;
this . shallow = shallow ;
this . mock = mock ;
// this.value = value
this . dep = mock ? mockDep : new Dep ( ) ;
this . vmCount = 0 ;
def ( value , '__ob__' , this ) ;
if ( isArray ( value ) ) {
if ( ! mock ) {
if ( hasProto ) {
value . _ _proto _ _ = arrayMethods ;
/* eslint-enable no-proto */
}
else {
for ( let i = 0 , l = arrayKeys . length ; i < l ; i ++ ) {
const key = arrayKeys [ i ] ;
def ( value , key , arrayMethods [ key ] ) ;
}
}
}
if ( ! shallow ) {
this . observeArray ( value ) ;
}
}
else {
/ * *
* Walk through all properties and convert them into
* getter / setters . This method should only be called when
* value type is Object .
* /
const keys = Object . keys ( value ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const key = keys [ i ] ;
defineReactive ( value , key , NO _INITIAL _VALUE , undefined , shallow , mock ) ;
}
}
}
/ * *
* Observe a list of Array items .
* /
observeArray ( value ) {
for ( let i = 0 , l = value . length ; i < l ; i ++ ) {
observe ( value [ i ] , false , this . mock ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// helpers
2023-12-18 13:12:25 +08:00
/ * *
* Attempt to create an observer instance for a value ,
* returns the new observer if successfully observed ,
* or the existing observer if the value already has one .
* /
2024-01-16 21:26:16 +08:00
function observe ( value , shallow , ssrMockReactivity ) {
if ( value && hasOwn ( value , '__ob__' ) && value . _ _ob _ _ instanceof Observer ) {
return value . _ _ob _ _ ;
}
if ( shouldObserve &&
( ssrMockReactivity || ! isServerRendering ( ) ) &&
( isArray ( value ) || isPlainObject ( value ) ) &&
Object . isExtensible ( value ) &&
! value . _ _v _skip /* ReactiveFlags.SKIP */ &&
! isRef ( value ) &&
! ( value instanceof VNode ) ) {
return new Observer ( value , shallow , ssrMockReactivity ) ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Define a reactive property on an Object .
* /
2024-01-16 21:26:16 +08:00
function defineReactive ( obj , key , val , customSetter , shallow , mock , observeEvenIfShallow = false ) {
const dep = new Dep ( ) ;
const property = Object . getOwnPropertyDescriptor ( obj , key ) ;
if ( property && property . configurable === false ) {
return ;
}
// cater for pre-defined getter/setters
const getter = property && property . get ;
const setter = property && property . set ;
if ( ( ! getter || setter ) &&
( val === NO _INITIAL _VALUE || arguments . length === 2 ) ) {
val = obj [ key ] ;
}
let childOb = shallow ? val && val . _ _ob _ _ : observe ( val , false , mock ) ;
Object . defineProperty ( obj , key , {
enumerable : true ,
configurable : true ,
get : function reactiveGetter ( ) {
const value = getter ? getter . call ( obj ) : val ;
if ( Dep . target ) {
{
dep . depend ( {
target : obj ,
type : "get" /* TrackOpTypes.GET */ ,
key
} ) ;
}
if ( childOb ) {
childOb . dep . depend ( ) ;
if ( isArray ( value ) ) {
dependArray ( value ) ;
}
}
}
return isRef ( value ) && ! shallow ? value . value : value ;
} ,
set : function reactiveSetter ( newVal ) {
const value = getter ? getter . call ( obj ) : val ;
if ( ! hasChanged ( value , newVal ) ) {
return ;
}
if ( customSetter ) {
customSetter ( ) ;
}
if ( setter ) {
setter . call ( obj , newVal ) ;
}
else if ( getter ) {
// #7981: for accessor properties without setter
return ;
}
else if ( ! shallow && isRef ( value ) && ! isRef ( newVal ) ) {
value . value = newVal ;
return ;
}
else {
val = newVal ;
}
childOb = shallow ? newVal && newVal . _ _ob _ _ : observe ( newVal , false , mock ) ;
{
dep . notify ( {
type : "set" /* TriggerOpTypes.SET */ ,
target : obj ,
key ,
newValue : newVal ,
oldValue : value
} ) ;
}
}
} ) ;
return dep ;
}
function set ( target , key , val ) {
if ( ( isUndef ( target ) || isPrimitive ( target ) ) ) {
warn ( ` Cannot set reactive property on undefined, null, or primitive value: ${ target } ` ) ;
}
if ( isReadonly ( target ) ) {
warn ( ` Set operation on key " ${ key } " failed: target is readonly. ` ) ;
return ;
}
const ob = target . _ _ob _ _ ;
if ( isArray ( target ) && isValidArrayIndex ( key ) ) {
target . length = Math . max ( target . length , key ) ;
target . splice ( key , 1 , val ) ;
// when mocking for SSR, array methods are not hijacked
if ( ob && ! ob . shallow && ob . mock ) {
observe ( val , false , true ) ;
}
return val ;
}
if ( key in target && ! ( key in Object . prototype ) ) {
target [ key ] = val ;
return val ;
}
if ( target . _isVue || ( ob && ob . vmCount ) ) {
warn ( 'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.' ) ;
return val ;
}
if ( ! ob ) {
target [ key ] = val ;
return val ;
}
defineReactive ( ob . value , key , val , undefined , ob . shallow , ob . mock ) ;
{
ob . dep . notify ( {
type : "add" /* TriggerOpTypes.ADD */ ,
target : target ,
key ,
newValue : val ,
oldValue : undefined
} ) ;
}
return val ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function del ( target , key ) {
if ( ( isUndef ( target ) || isPrimitive ( target ) ) ) {
warn ( ` Cannot delete reactive property on undefined, null, or primitive value: ${ target } ` ) ;
}
if ( isArray ( target ) && isValidArrayIndex ( key ) ) {
target . splice ( key , 1 ) ;
return ;
}
const ob = target . _ _ob _ _ ;
if ( target . _isVue || ( ob && ob . vmCount ) ) {
warn ( 'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.' ) ;
return ;
}
if ( isReadonly ( target ) ) {
warn ( ` Delete operation on key " ${ key } " failed: target is readonly. ` ) ;
return ;
}
if ( ! hasOwn ( target , key ) ) {
return ;
}
delete target [ key ] ;
if ( ! ob ) {
return ;
}
{
ob . dep . notify ( {
type : "delete" /* TriggerOpTypes.DELETE */ ,
target : target ,
key
} ) ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Collect dependencies on array elements when the array is touched , since
* we cannot intercept array element access like property getters .
* /
2024-01-16 21:26:16 +08:00
function dependArray ( value ) {
for ( let e , i = 0 , l = value . length ; i < l ; i ++ ) {
e = value [ i ] ;
if ( e && e . _ _ob _ _ ) {
e . _ _ob _ _ . dep . depend ( ) ;
}
if ( isArray ( e ) ) {
dependArray ( e ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function reactive ( target ) {
makeReactive ( target , false ) ;
return target ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Return a shallowly - reactive copy of the original object , where only the root
* level properties are reactive . It also does not auto - unwrap refs ( even at the
* root level ) .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function shallowReactive ( target ) {
makeReactive ( target , true ) ;
def ( target , "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */ , true ) ;
return target ;
}
function makeReactive ( target , shallow ) {
// if trying to observe a readonly proxy, return the readonly version.
if ( ! isReadonly ( target ) ) {
{
if ( isArray ( target ) ) {
warn ( ` Avoid using Array as root value for ${ shallow ? ` shallowReactive() ` : ` reactive() ` } as it cannot be tracked in watch() or watchEffect(). Use ${ shallow ? ` shallowRef() ` : ` ref() ` } instead. This is a Vue-2-only limitation. ` ) ;
}
const existingOb = target && target . _ _ob _ _ ;
if ( existingOb && existingOb . shallow !== shallow ) {
warn ( ` Target is already a ${ existingOb . shallow ? ` ` : ` non- ` } shallow reactive object, and cannot be converted to ${ shallow ? ` ` : ` non- ` } shallow. ` ) ;
}
}
const ob = observe ( target , shallow , isServerRendering ( ) /* ssr mock reactivity */ ) ;
if ( ! ob ) {
if ( target == null || isPrimitive ( target ) ) {
warn ( ` value cannot be made reactive: ${ String ( target ) } ` ) ;
}
if ( isCollectionType ( target ) ) {
warn ( ` Vue 2 does not support reactive collection types such as Map or Set. ` ) ;
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function isReactive ( value ) {
if ( isReadonly ( value ) ) {
return isReactive ( value [ "__v_raw" /* ReactiveFlags.RAW */ ] ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return ! ! ( value && value . _ _ob _ _ ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isShallow ( value ) {
return ! ! ( value && value . _ _v _isShallow ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isReadonly ( value ) {
return ! ! ( value && value . _ _v _isReadonly ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isProxy ( value ) {
return isReactive ( value ) || isReadonly ( value ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function toRaw ( observed ) {
const raw = observed && observed [ "__v_raw" /* ReactiveFlags.RAW */ ] ;
return raw ? toRaw ( raw ) : observed ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function markRaw ( value ) {
// non-extensible objects won't be observed anyway
if ( Object . isExtensible ( value ) ) {
def ( value , "__v_skip" /* ReactiveFlags.SKIP */ , true ) ;
}
return value ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* @ internal
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function isCollectionType ( value ) {
const type = toRawType ( value ) ;
return ( type === 'Map' || type === 'WeakMap' || type === 'Set' || type === 'WeakSet' ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* @ internal
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
const RefFlag = ` __v_isRef ` ;
function isRef ( r ) {
return ! ! ( r && r . _ _v _isRef === true ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function ref$1 ( value ) {
return createRef ( value , false ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function shallowRef ( value ) {
return createRef ( value , true ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createRef ( rawValue , shallow ) {
if ( isRef ( rawValue ) ) {
return rawValue ;
}
const ref = { } ;
def ( ref , RefFlag , true ) ;
def ( ref , "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */ , shallow ) ;
def ( ref , 'dep' , defineReactive ( ref , 'value' , rawValue , null , shallow , isServerRendering ( ) ) ) ;
return ref ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function triggerRef ( ref ) {
if ( ! ref . dep ) {
warn ( ` received object is not a triggerable ref. ` ) ;
}
{
ref . dep &&
ref . dep . notify ( {
type : "set" /* TriggerOpTypes.SET */ ,
target : ref ,
key : 'value'
} ) ;
}
}
function unref ( ref ) {
return isRef ( ref ) ? ref . value : ref ;
}
function proxyRefs ( objectWithRefs ) {
if ( isReactive ( objectWithRefs ) ) {
return objectWithRefs ;
}
const proxy = { } ;
const keys = Object . keys ( objectWithRefs ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
proxyWithRefUnwrap ( proxy , objectWithRefs , keys [ i ] ) ;
}
return proxy ;
}
function proxyWithRefUnwrap ( target , source , key ) {
Object . defineProperty ( target , key , {
enumerable : true ,
configurable : true ,
get : ( ) => {
const val = source [ key ] ;
if ( isRef ( val ) ) {
return val . value ;
}
else {
const ob = val && val . _ _ob _ _ ;
if ( ob )
ob . dep . depend ( ) ;
return val ;
}
} ,
set : value => {
const oldValue = source [ key ] ;
if ( isRef ( oldValue ) && ! isRef ( value ) ) {
oldValue . value = value ;
}
else {
source [ key ] = value ;
}
}
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function customRef ( factory ) {
const dep = new Dep ( ) ;
const { get , set } = factory ( ( ) => {
{
dep . depend ( {
target : ref ,
type : "get" /* TrackOpTypes.GET */ ,
key : 'value'
} ) ;
}
} , ( ) => {
{
dep . notify ( {
target : ref ,
type : "set" /* TriggerOpTypes.SET */ ,
key : 'value'
} ) ;
}
} ) ;
const ref = {
get value ( ) {
return get ( ) ;
} ,
set value ( newVal ) {
set ( newVal ) ;
}
} ;
def ( ref , RefFlag , true ) ;
return ref ;
}
function toRefs ( object ) {
if ( ! isReactive ( object ) ) {
warn ( ` toRefs() expects a reactive object but received a plain one. ` ) ;
}
const ret = isArray ( object ) ? new Array ( object . length ) : { } ;
for ( const key in object ) {
ret [ key ] = toRef ( object , key ) ;
}
return ret ;
}
function toRef ( object , key , defaultValue ) {
const val = object [ key ] ;
if ( isRef ( val ) ) {
return val ;
}
const ref = {
get value ( ) {
const val = object [ key ] ;
return val === undefined ? defaultValue : val ;
} ,
set value ( newVal ) {
object [ key ] = newVal ;
}
} ;
def ( ref , RefFlag , true ) ;
return ref ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const rawToReadonlyFlag = ` __v_rawToReadonly ` ;
const rawToShallowReadonlyFlag = ` __v_rawToShallowReadonly ` ;
function readonly ( target ) {
return createReadonly ( target , false ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createReadonly ( target , shallow ) {
if ( ! isPlainObject ( target ) ) {
{
if ( isArray ( target ) ) {
warn ( ` Vue 2 does not support readonly arrays. ` ) ;
}
else if ( isCollectionType ( target ) ) {
warn ( ` Vue 2 does not support readonly collection types such as Map or Set. ` ) ;
}
else {
warn ( ` value cannot be made readonly: ${ typeof target } ` ) ;
}
}
return target ;
}
if ( ! Object . isExtensible ( target ) ) {
warn ( ` Vue 2 does not support creating readonly proxy for non-extensible object. ` ) ;
}
// already a readonly object
if ( isReadonly ( target ) ) {
return target ;
}
// already has a readonly proxy
const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag ;
const existingProxy = target [ existingFlag ] ;
if ( existingProxy ) {
return existingProxy ;
}
const proxy = Object . create ( Object . getPrototypeOf ( target ) ) ;
def ( target , existingFlag , proxy ) ;
def ( proxy , "__v_isReadonly" /* ReactiveFlags.IS_READONLY */ , true ) ;
def ( proxy , "__v_raw" /* ReactiveFlags.RAW */ , target ) ;
if ( isRef ( target ) ) {
def ( proxy , RefFlag , true ) ;
}
if ( shallow || isShallow ( target ) ) {
def ( proxy , "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */ , true ) ;
}
const keys = Object . keys ( target ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
defineReadonlyProperty ( proxy , target , keys [ i ] , shallow ) ;
}
return proxy ;
}
function defineReadonlyProperty ( proxy , target , key , shallow ) {
Object . defineProperty ( proxy , key , {
enumerable : true ,
configurable : true ,
get ( ) {
const val = target [ key ] ;
return shallow || ! isPlainObject ( val ) ? val : readonly ( val ) ;
} ,
set ( ) {
warn ( ` Set operation on key " ${ key } " failed: target is readonly. ` ) ;
}
} ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Returns a reactive - copy of the original object , where only the root level
* properties are readonly , and does NOT unwrap refs nor recursively convert
* returned properties .
* This is used for creating the props proxy object for stateful components .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function shallowReadonly ( target ) {
return createReadonly ( target , true ) ;
}
function computed ( getterOrOptions , debugOptions ) {
let getter ;
let setter ;
const onlyGetter = isFunction ( getterOrOptions ) ;
if ( onlyGetter ) {
getter = getterOrOptions ;
setter = ( ) => {
warn ( 'Write operation failed: computed value is readonly' ) ;
}
;
}
else {
getter = getterOrOptions . get ;
setter = getterOrOptions . set ;
}
const watcher = isServerRendering ( )
? null
: new Watcher ( currentInstance , getter , noop , { lazy : true } ) ;
if ( watcher && debugOptions ) {
watcher . onTrack = debugOptions . onTrack ;
watcher . onTrigger = debugOptions . onTrigger ;
}
const ref = {
// some libs rely on the presence effect for checking computed refs
// from normal refs, but the implementation doesn't matter
effect : watcher ,
get value ( ) {
if ( watcher ) {
if ( watcher . dirty ) {
watcher . evaluate ( ) ;
}
if ( Dep . target ) {
if ( Dep . target . onTrack ) {
Dep . target . onTrack ( {
effect : Dep . target ,
target : ref ,
type : "get" /* TrackOpTypes.GET */ ,
key : 'value'
} ) ;
}
watcher . depend ( ) ;
}
return watcher . value ;
}
else {
return getter ( ) ;
}
} ,
set value ( newVal ) {
setter ( newVal ) ;
}
} ;
def ( ref , RefFlag , true ) ;
def ( ref , "__v_isReadonly" /* ReactiveFlags.IS_READONLY */ , onlyGetter ) ;
return ref ;
}
const WATCHER = ` watcher ` ;
const WATCHER _CB = ` ${ WATCHER } callback ` ;
const WATCHER _GETTER = ` ${ WATCHER } getter ` ;
const WATCHER _CLEANUP = ` ${ WATCHER } cleanup ` ;
// Simple effect.
function watchEffect ( effect , options ) {
return doWatch ( effect , null , options ) ;
}
function watchPostEffect ( effect , options ) {
return doWatch ( effect , null , ( Object . assign ( Object . assign ( { } , options ) , { flush : 'post' } ) ) ) ;
}
function watchSyncEffect ( effect , options ) {
return doWatch ( effect , null , ( Object . assign ( Object . assign ( { } , options ) , { flush : 'sync' } ) ) ) ;
}
// initial value for watchers to trigger on undefined initial values
const INITIAL _WATCHER _VALUE = { } ;
// implementation
function watch ( source , cb , options ) {
if ( typeof cb !== 'function' ) {
warn ( ` \` watch(fn, options?) \` signature has been moved to a separate API. ` +
` Use \` watchEffect(fn, options?) \` instead. \` watch \` now only ` +
` supports \` watch(source, cb, options?) signature. ` ) ;
}
return doWatch ( source , cb , options ) ;
}
function doWatch ( source , cb , { immediate , deep , flush = 'pre' , onTrack , onTrigger } = emptyObject ) {
if ( ! cb ) {
if ( immediate !== undefined ) {
warn ( ` watch() "immediate" option is only respected when using the ` +
` watch(source, callback, options?) signature. ` ) ;
}
if ( deep !== undefined ) {
warn ( ` watch() "deep" option is only respected when using the ` +
` watch(source, callback, options?) signature. ` ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const warnInvalidSource = ( s ) => {
warn ( ` Invalid watch source: ${ s } . A watch source can only be a getter/effect ` +
` function, a ref, a reactive object, or an array of these types. ` ) ;
} ;
const instance = currentInstance ;
const call = ( fn , type , args = null ) => {
const res = invokeWithErrorHandling ( fn , null , args , instance , type ) ;
if ( deep && res && res . _ _ob _ _ )
res . _ _ob _ _ . dep . depend ( ) ;
return res ;
} ;
let getter ;
let forceTrigger = false ;
let isMultiSource = false ;
if ( isRef ( source ) ) {
getter = ( ) => source . value ;
forceTrigger = isShallow ( source ) ;
}
else if ( isReactive ( source ) ) {
getter = ( ) => {
source . _ _ob _ _ . dep . depend ( ) ;
return source ;
} ;
deep = true ;
}
else if ( isArray ( source ) ) {
isMultiSource = true ;
forceTrigger = source . some ( s => isReactive ( s ) || isShallow ( s ) ) ;
getter = ( ) => source . map ( s => {
if ( isRef ( s ) ) {
return s . value ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( isReactive ( s ) ) {
s . _ _ob _ _ . dep . depend ( ) ;
return traverse ( s ) ;
}
else if ( isFunction ( s ) ) {
return call ( s , WATCHER _GETTER ) ;
}
else {
warnInvalidSource ( s ) ;
}
} ) ;
}
else if ( isFunction ( source ) ) {
if ( cb ) {
// getter with cb
getter = ( ) => call ( source , WATCHER _GETTER ) ;
}
else {
// no cb -> simple effect
getter = ( ) => {
if ( instance && instance . _isDestroyed ) {
return ;
}
if ( cleanup ) {
cleanup ( ) ;
}
return call ( source , WATCHER , [ onCleanup ] ) ;
} ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
else {
getter = noop ;
warnInvalidSource ( source ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( cb && deep ) {
const baseGetter = getter ;
getter = ( ) => traverse ( baseGetter ( ) ) ;
}
let cleanup ;
let onCleanup = ( fn ) => {
cleanup = watcher . onStop = ( ) => {
call ( fn , WATCHER _CLEANUP ) ;
} ;
} ;
// in SSR there is no need to setup an actual effect, and it should be noop
// unless it's eager
if ( isServerRendering ( ) ) {
// we will also not call the invalidate callback (+ runner is not set up)
onCleanup = noop ;
if ( ! cb ) {
getter ( ) ;
}
else if ( immediate ) {
call ( cb , WATCHER _CB , [
getter ( ) ,
isMultiSource ? [ ] : undefined ,
onCleanup
] ) ;
}
return noop ;
}
const watcher = new Watcher ( currentInstance , getter , noop , {
lazy : true
} ) ;
watcher . noRecurse = ! cb ;
let oldValue = isMultiSource ? [ ] : INITIAL _WATCHER _VALUE ;
// overwrite default run
watcher . run = ( ) => {
if ( ! watcher . active ) {
return ;
}
if ( cb ) {
// watch(source, cb)
const newValue = watcher . get ( ) ;
if ( deep ||
forceTrigger ||
( isMultiSource
? newValue . some ( ( v , i ) => hasChanged ( v , oldValue [ i ] ) )
: hasChanged ( newValue , oldValue ) ) ) {
// cleanup before running cb again
if ( cleanup ) {
cleanup ( ) ;
}
call ( cb , WATCHER _CB , [
newValue ,
// pass undefined as the old value when it's changed for the first time
oldValue === INITIAL _WATCHER _VALUE ? undefined : oldValue ,
onCleanup
] ) ;
oldValue = newValue ;
}
}
else {
// watchEffect
watcher . get ( ) ;
}
} ;
if ( flush === 'sync' ) {
watcher . update = watcher . run ;
}
else if ( flush === 'post' ) {
watcher . post = true ;
watcher . update = ( ) => queueWatcher ( watcher ) ;
}
else {
// pre
watcher . update = ( ) => {
if ( instance && instance === currentInstance && ! instance . _isMounted ) {
// pre-watcher triggered before
const buffer = instance . _preWatchers || ( instance . _preWatchers = [ ] ) ;
if ( buffer . indexOf ( watcher ) < 0 )
buffer . push ( watcher ) ;
}
else {
queueWatcher ( watcher ) ;
}
} ;
}
{
watcher . onTrack = onTrack ;
watcher . onTrigger = onTrigger ;
}
// initial run
2023-12-18 13:12:25 +08:00
if ( cb ) {
2024-01-16 21:26:16 +08:00
if ( immediate ) {
watcher . run ( ) ;
}
else {
oldValue = watcher . get ( ) ;
}
}
else if ( flush === 'post' && instance ) {
instance . $once ( 'hook:mounted' , ( ) => watcher . get ( ) ) ;
}
else {
watcher . get ( ) ;
}
return ( ) => {
watcher . teardown ( ) ;
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
let activeEffectScope ;
class EffectScope {
constructor ( detached = false ) {
this . detached = detached ;
/ * *
* @ internal
* /
this . active = true ;
/ * *
* @ internal
* /
this . effects = [ ] ;
/ * *
* @ internal
* /
this . cleanups = [ ] ;
this . parent = activeEffectScope ;
if ( ! detached && activeEffectScope ) {
this . index =
( activeEffectScope . scopes || ( activeEffectScope . scopes = [ ] ) ) . push ( this ) - 1 ;
}
}
run ( fn ) {
if ( this . active ) {
const currentEffectScope = activeEffectScope ;
try {
activeEffectScope = this ;
return fn ( ) ;
}
finally {
activeEffectScope = currentEffectScope ;
}
}
else {
warn ( ` cannot run an inactive effect scope. ` ) ;
}
}
/ * *
* This should only be called on non - detached scopes
* @ internal
* /
on ( ) {
activeEffectScope = this ;
}
/ * *
* This should only be called on non - detached scopes
* @ internal
* /
off ( ) {
activeEffectScope = this . parent ;
}
stop ( fromParent ) {
if ( this . active ) {
let i , l ;
for ( i = 0 , l = this . effects . length ; i < l ; i ++ ) {
this . effects [ i ] . teardown ( ) ;
}
for ( i = 0 , l = this . cleanups . length ; i < l ; i ++ ) {
this . cleanups [ i ] ( ) ;
}
if ( this . scopes ) {
for ( i = 0 , l = this . scopes . length ; i < l ; i ++ ) {
this . scopes [ i ] . stop ( true ) ;
}
}
// nested scope, dereference from parent to avoid memory leaks
if ( ! this . detached && this . parent && ! fromParent ) {
// optimized O(1) removal
const last = this . parent . scopes . pop ( ) ;
if ( last && last !== this ) {
this . parent . scopes [ this . index ] = last ;
last . index = this . index ;
}
}
this . parent = undefined ;
this . active = false ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function effectScope ( detached ) {
return new EffectScope ( detached ) ;
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* @ internal
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function recordEffectScope ( effect , scope = activeEffectScope ) {
if ( scope && scope . active ) {
scope . effects . push ( effect ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getCurrentScope ( ) {
return activeEffectScope ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function onScopeDispose ( fn ) {
if ( activeEffectScope ) {
activeEffectScope . cleanups . push ( fn ) ;
}
else {
warn ( ` onScopeDispose() is called when there is no active effect scope ` +
` to be associated with. ` ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function provide ( key , value ) {
if ( ! currentInstance ) {
{
warn ( ` provide() can only be used inside setup(). ` ) ;
}
}
else {
// TS doesn't allow symbol as index type
resolveProvided ( currentInstance ) [ key ] = value ;
}
}
function resolveProvided ( vm ) {
// by default an instance inherits its parent's provides object
// but when it needs to provide values of its own, it creates its
// own provides object using parent provides object as prototype.
// this way in `inject` we can simply look up injections from direct
// parent and let the prototype chain do the work.
const existing = vm . _provided ;
const parentProvides = vm . $parent && vm . $parent . _provided ;
if ( parentProvides === existing ) {
return ( vm . _provided = Object . create ( parentProvides ) ) ;
}
else {
return existing ;
}
}
function inject ( key , defaultValue , treatDefaultAsFactory = false ) {
// fallback to `currentRenderingInstance` so that this can be called in
// a functional component
const instance = currentInstance ;
if ( instance ) {
// #2400
// to support `app.use` plugins,
// fallback to appContext's `provides` if the instance is at root
const provides = instance . $parent && instance . $parent . _provided ;
if ( provides && key in provides ) {
// TS doesn't allow symbol as index type
return provides [ key ] ;
}
else if ( arguments . length > 1 ) {
return treatDefaultAsFactory && isFunction ( defaultValue )
? defaultValue . call ( instance )
: defaultValue ;
}
else {
warn ( ` injection " ${ String ( key ) } " not found. ` ) ;
}
}
else {
warn ( ` inject() can only be used inside setup() or functional components. ` ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const normalizeEvent = cached ( ( name ) => {
const passive = name . charAt ( 0 ) === '&' ;
name = passive ? name . slice ( 1 ) : name ;
const once = name . charAt ( 0 ) === '~' ; // Prefixed last, checked first
name = once ? name . slice ( 1 ) : name ;
const capture = name . charAt ( 0 ) === '!' ;
name = capture ? name . slice ( 1 ) : name ;
return {
name ,
once ,
capture ,
passive
} ;
} ) ;
function createFnInvoker ( fns , vm ) {
function invoker ( ) {
const fns = invoker . fns ;
if ( isArray ( fns ) ) {
const cloned = fns . slice ( ) ;
for ( let i = 0 ; i < cloned . length ; i ++ ) {
invokeWithErrorHandling ( cloned [ i ] , null , arguments , vm , ` v-on handler ` ) ;
}
}
else {
// return handler return value for single handlers
return invokeWithErrorHandling ( fns , null , arguments , vm , ` v-on handler ` ) ;
}
}
invoker . fns = fns ;
return invoker ;
}
function updateListeners ( on , oldOn , add , remove , createOnceHandler , vm ) {
let name , cur , old , event ;
for ( name in on ) {
cur = on [ name ] ;
old = oldOn [ name ] ;
event = normalizeEvent ( name ) ;
if ( isUndef ( cur ) ) {
warn ( ` Invalid handler for event " ${ event . name } ": got ` + String ( cur ) , vm ) ;
}
else if ( isUndef ( old ) ) {
if ( isUndef ( cur . fns ) ) {
cur = on [ name ] = createFnInvoker ( cur , vm ) ;
}
if ( isTrue ( event . once ) ) {
cur = on [ name ] = createOnceHandler ( event . name , cur , event . capture ) ;
}
add ( event . name , cur , event . capture , event . passive , event . params ) ;
}
else if ( cur !== old ) {
old . fns = cur ;
on [ name ] = old ;
}
}
for ( name in oldOn ) {
if ( isUndef ( on [ name ] ) ) {
event = normalizeEvent ( name ) ;
remove ( event . name , oldOn [ name ] , event . capture ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function mergeVNodeHook ( def , hookKey , hook ) {
if ( def instanceof VNode ) {
def = def . data . hook || ( def . data . hook = { } ) ;
}
let invoker ;
const oldHook = def [ hookKey ] ;
function wrappedHook ( ) {
hook . apply ( this , arguments ) ;
// important: remove merged hook to ensure it's called only once
// and prevent memory leak
remove$2 ( invoker . fns , wrappedHook ) ;
}
if ( isUndef ( oldHook ) ) {
// no existing hook
invoker = createFnInvoker ( [ wrappedHook ] ) ;
}
else {
/* istanbul ignore if */
if ( isDef ( oldHook . fns ) && isTrue ( oldHook . merged ) ) {
// already a merged invoker
invoker = oldHook ;
invoker . fns . push ( wrappedHook ) ;
}
else {
// existing plain hook
invoker = createFnInvoker ( [ oldHook , wrappedHook ] ) ;
}
}
invoker . merged = true ;
def [ hookKey ] = invoker ;
}
function extractPropsFromVNodeData ( data , Ctor , tag ) {
// we are only extracting raw values here.
// validation and default values are handled in the child
// component itself.
const propOptions = Ctor . options . props ;
if ( isUndef ( propOptions ) ) {
return ;
}
const res = { } ;
const { attrs , props } = data ;
if ( isDef ( attrs ) || isDef ( props ) ) {
for ( const key in propOptions ) {
const altKey = hyphenate ( key ) ;
{
const keyInLowerCase = key . toLowerCase ( ) ;
if ( key !== keyInLowerCase && attrs && hasOwn ( attrs , keyInLowerCase ) ) {
tip ( ` Prop " ${ keyInLowerCase } " is passed to component ` +
` ${ formatComponentName (
// @ts-expect-error tag is string
tag || Ctor ) } , but the declared prop name is ` +
` " ${ key } ". ` +
` Note that HTML attributes are case-insensitive and camelCased ` +
` props need to use their kebab-case equivalents when using in-DOM ` +
` templates. You should probably use " ${ altKey } " instead of " ${ key } ". ` ) ;
}
}
checkProp ( res , props , key , altKey , true ) ||
checkProp ( res , attrs , key , altKey , false ) ;
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkProp ( res , hash , key , altKey , preserve ) {
if ( isDef ( hash ) ) {
if ( hasOwn ( hash , key ) ) {
res [ key ] = hash [ key ] ;
if ( ! preserve ) {
delete hash [ key ] ;
}
return true ;
}
else if ( hasOwn ( hash , altKey ) ) {
res [ key ] = hash [ altKey ] ;
if ( ! preserve ) {
delete hash [ altKey ] ;
}
return true ;
}
}
return false ;
2023-12-18 13:12:25 +08:00
}
// The template compiler attempts to minimize the need for normalization by
// statically analyzing the template at compile time.
//
// For plain HTML markup, normalization can be completely skipped because the
// generated render function is guaranteed to return Array<VNode>. There are
// two cases where extra normalization is needed:
// 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.
2024-01-16 21:26:16 +08:00
function simpleNormalizeChildren ( children ) {
for ( let i = 0 ; i < children . length ; i ++ ) {
if ( isArray ( children [ i ] ) ) {
return Array . prototype . concat . apply ( [ ] , children ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return children ;
2023-12-18 13:12:25 +08:00
}
// 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.
2024-01-16 21:26:16 +08:00
function normalizeChildren ( children ) {
return isPrimitive ( children )
? [ createTextVNode ( children ) ]
: isArray ( children )
? normalizeArrayChildren ( children )
: undefined ;
}
function isTextNode ( node ) {
return isDef ( node ) && isDef ( node . text ) && isFalse ( node . isComment ) ;
}
function normalizeArrayChildren ( children , nestedIndex ) {
const res = [ ] ;
let i , c , lastIndex , last ;
for ( i = 0 ; i < children . length ; i ++ ) {
c = children [ i ] ;
if ( isUndef ( c ) || typeof c === 'boolean' )
continue ;
lastIndex = res . length - 1 ;
last = res [ lastIndex ] ;
// nested
if ( isArray ( c ) ) {
if ( c . length > 0 ) {
c = normalizeArrayChildren ( c , ` ${ nestedIndex || '' } _ ${ i } ` ) ;
// merge adjacent text nodes
if ( isTextNode ( c [ 0 ] ) && isTextNode ( last ) ) {
res [ lastIndex ] = createTextVNode ( last . text + c [ 0 ] . text ) ;
c . shift ( ) ;
}
res . push . apply ( res , c ) ;
}
}
else if ( isPrimitive ( c ) ) {
if ( isTextNode ( last ) ) {
// merge adjacent text nodes
// this is necessary for SSR hydration because text nodes are
// essentially merged when rendered to HTML strings
res [ lastIndex ] = createTextVNode ( last . text + c ) ;
}
else if ( c !== '' ) {
// convert primitive to vnode
res . push ( createTextVNode ( c ) ) ;
}
}
else {
if ( isTextNode ( c ) && isTextNode ( last ) ) {
// merge adjacent text nodes
res [ lastIndex ] = createTextVNode ( last . text + c . text ) ;
}
else {
// default key for nested array children (likely generated by v-for)
if ( isTrue ( children . _isVList ) &&
isDef ( c . tag ) &&
isUndef ( c . key ) &&
isDef ( nestedIndex ) ) {
c . key = ` __vlist ${ nestedIndex } _ ${ i } __ ` ;
}
res . push ( c ) ;
}
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for rendering v - for lists .
* /
2024-01-16 21:26:16 +08:00
function renderList ( val , render ) {
let ret = null , i , l , keys , key ;
if ( isArray ( val ) || typeof val === 'string' ) {
ret = new Array ( val . length ) ;
for ( i = 0 , l = val . length ; i < l ; i ++ ) {
ret [ i ] = render ( val [ i ] , i ) ;
}
}
else if ( typeof val === 'number' ) {
ret = new Array ( val ) ;
for ( i = 0 ; i < val ; i ++ ) {
ret [ i ] = render ( i + 1 , i ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( isObject ( val ) ) {
if ( hasSymbol && val [ Symbol . iterator ] ) {
ret = [ ] ;
const iterator = val [ Symbol . iterator ] ( ) ;
let result = iterator . next ( ) ;
while ( ! result . done ) {
ret . push ( render ( result . value , ret . length ) ) ;
result = iterator . next ( ) ;
}
}
else {
keys = Object . keys ( val ) ;
ret = new Array ( keys . length ) ;
for ( i = 0 , l = keys . length ; i < l ; i ++ ) {
key = keys [ i ] ;
ret [ i ] = render ( val [ key ] , key , i ) ;
}
}
}
if ( ! isDef ( ret ) ) {
ret = [ ] ;
}
ret . _isVList = true ;
return ret ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for rendering < slot >
* /
2024-01-16 21:26:16 +08:00
function renderSlot ( name , fallbackRender , props , bindObject ) {
const scopedSlotFn = this . $scopedSlots [ name ] ;
let nodes ;
if ( scopedSlotFn ) {
// scoped slot
props = props || { } ;
if ( bindObject ) {
if ( ! isObject ( bindObject ) ) {
warn ( 'slot v-bind without argument expects an Object' , this ) ;
}
props = extend ( extend ( { } , bindObject ) , props ) ;
}
nodes =
scopedSlotFn ( props ) ||
( isFunction ( fallbackRender ) ? fallbackRender ( ) : fallbackRender ) ;
}
else {
nodes =
this . $slots [ name ] ||
( isFunction ( fallbackRender ) ? fallbackRender ( ) : fallbackRender ) ;
}
const target = props && props . slot ;
if ( target ) {
return this . $createElement ( 'template' , { slot : target } , nodes ) ;
}
else {
return nodes ;
2023-12-18 13:12:25 +08:00
}
}
/ * *
* Runtime helper for resolving filters
* /
2024-01-16 21:26:16 +08:00
function resolveFilter ( id ) {
return resolveAsset ( this . $options , 'filters' , id , true ) || identity ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isKeyNotMatch ( expect , actual ) {
if ( isArray ( expect ) ) {
return expect . indexOf ( actual ) === - 1 ;
}
else {
return expect !== actual ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for checking keyCodes from config .
* exposed as Vue . prototype . _k
* passing in eventKeyName as last argument separately for backwards compat
* /
2024-01-16 21:26:16 +08:00
function checkKeyCodes ( eventKeyCode , key , builtInKeyCode , eventKeyName , builtInKeyName ) {
const mappedKeyCode = config . keyCodes [ key ] || builtInKeyCode ;
if ( builtInKeyName && eventKeyName && ! config . keyCodes [ key ] ) {
return isKeyNotMatch ( builtInKeyName , eventKeyName ) ;
}
else if ( mappedKeyCode ) {
return isKeyNotMatch ( mappedKeyCode , eventKeyCode ) ;
}
else if ( eventKeyName ) {
return hyphenate ( eventKeyName ) !== key ;
}
return eventKeyCode === undefined ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for merging v - bind = "object" into a VNode ' s data .
* /
2024-01-16 21:26:16 +08:00
function bindObjectProps ( data , tag , value , asProp , isSync ) {
if ( value ) {
if ( ! isObject ( value ) ) {
warn ( 'v-bind without argument expects an Object or Array value' , this ) ;
}
else {
if ( isArray ( value ) ) {
value = toObject ( value ) ;
}
let hash ;
for ( const key in value ) {
if ( key === 'class' || key === 'style' || isReservedAttribute ( key ) ) {
hash = data ;
}
else {
const type = data . attrs && data . attrs . type ;
hash =
asProp || config . mustUseProp ( tag , type , key )
? data . domProps || ( data . domProps = { } )
: data . attrs || ( data . attrs = { } ) ;
}
const camelizedKey = camelize ( key ) ;
const hyphenatedKey = hyphenate ( key ) ;
if ( ! ( camelizedKey in hash ) && ! ( hyphenatedKey in hash ) ) {
hash [ key ] = value [ key ] ;
if ( isSync ) {
const on = data . on || ( data . on = { } ) ;
on [ ` update: ${ key } ` ] = function ( $event ) {
value [ key ] = $event ;
} ;
}
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
return data ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for rendering static trees .
* /
2024-01-16 21:26:16 +08:00
function renderStatic ( index , isInFor ) {
const cached = this . _staticTrees || ( this . _staticTrees = [ ] ) ;
let tree = cached [ index ] ;
// if has already-rendered static tree and not inside v-for,
// we can reuse the same tree.
if ( tree && ! isInFor ) {
return tree ;
}
// otherwise, render a fresh tree.
tree = cached [ index ] = this . $options . staticRenderFns [ index ] . call ( this . _renderProxy , this . _c , this // for render fns generated for functional component templates
) ;
markStatic ( tree , ` __static__ ${ index } ` , false ) ;
return tree ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Runtime helper for v - once .
* Effectively it means marking the node as static with a unique key .
* /
2024-01-16 21:26:16 +08:00
function markOnce ( tree , index , key ) {
markStatic ( tree , ` __once__ ${ index } ${ key ? ` _ ${ key } ` : ` ` } ` , true ) ;
return tree ;
}
function markStatic ( tree , key , isOnce ) {
if ( isArray ( tree ) ) {
for ( let i = 0 ; i < tree . length ; i ++ ) {
if ( tree [ i ] && typeof tree [ i ] !== 'string' ) {
markStaticNode ( tree [ i ] , ` ${ key } _ ${ i } ` , isOnce ) ;
}
}
}
else {
markStaticNode ( tree , key , isOnce ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function markStaticNode ( node , key , isOnce ) {
node . isStatic = true ;
node . key = key ;
node . isOnce = isOnce ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function bindObjectListeners ( data , value ) {
if ( value ) {
if ( ! isPlainObject ( value ) ) {
warn ( 'v-on without argument expects an Object value' , this ) ;
}
else {
const on = ( data . on = data . on ? extend ( { } , data . on ) : { } ) ;
for ( const key in value ) {
const existing = on [ key ] ;
const ours = value [ key ] ;
on [ key ] = existing ? [ ] . concat ( existing , ours ) : ours ;
}
}
}
return data ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function resolveScopedSlots ( fns , res ,
// the following are added in 2.6
hasDynamicKeys , contentHashKey ) {
res = res || { $stable : ! hasDynamicKeys } ;
for ( let i = 0 ; i < fns . length ; i ++ ) {
const slot = fns [ i ] ;
if ( isArray ( slot ) ) {
resolveScopedSlots ( slot , res , hasDynamicKeys ) ;
}
else if ( slot ) {
// marker for reverse proxying v-slot without scope on this.$slots
// @ts-expect-error
if ( slot . proxy ) {
// @ts-expect-error
slot . fn . proxy = true ;
}
res [ slot . key ] = slot . fn ;
}
}
if ( contentHashKey ) {
res . $key = contentHashKey ;
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// helper to process dynamic keys for dynamic arguments in v-bind and v-on.
function bindDynamicKeys ( baseObj , values ) {
for ( let i = 0 ; i < values . length ; i += 2 ) {
const key = values [ i ] ;
if ( typeof key === 'string' && key ) {
baseObj [ values [ i ] ] = values [ i + 1 ] ;
}
else if ( key !== '' && key !== null ) {
// null is a special value for explicitly removing a binding
warn ( ` Invalid value for dynamic directive argument (expected string or null): ${ key } ` , this ) ;
}
}
return baseObj ;
2023-12-18 13:12:25 +08:00
}
// helper to dynamically append modifier runtime markers to event names.
// ensure only append when value is already string, otherwise it will be cast
// to string and cause the type check to miss.
2024-01-16 21:26:16 +08:00
function prependModifier ( value , symbol ) {
return typeof value === 'string' ? symbol + value : value ;
}
function installRenderHelpers ( target ) {
target . _o = markOnce ;
target . _n = toNumber ;
target . _s = toString ;
target . _l = renderList ;
target . _t = renderSlot ;
target . _q = looseEqual ;
target . _i = looseIndexOf ;
target . _m = renderStatic ;
target . _f = resolveFilter ;
target . _k = checkKeyCodes ;
target . _b = bindObjectProps ;
target . _v = createTextVNode ;
target . _e = createEmptyVNode ;
target . _u = resolveScopedSlots ;
target . _g = bindObjectListeners ;
target . _d = bindDynamicKeys ;
target . _p = prependModifier ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* Runtime helper for resolving raw children VNodes into a slot object .
* /
function resolveSlots ( children , context ) {
if ( ! children || ! children . length ) {
return { } ;
}
const slots = { } ;
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
const child = children [ i ] ;
const data = child . data ;
// remove slot attribute if the node is resolved as a Vue slot node
if ( data && data . attrs && data . attrs . slot ) {
delete data . attrs . slot ;
}
// named slots should only be respected if the vnode was rendered in the
// same context.
if ( ( child . context === context || child . fnContext === context ) &&
data &&
data . slot != null ) {
const name = data . slot ;
const slot = slots [ name ] || ( slots [ name ] = [ ] ) ;
if ( child . tag === 'template' ) {
slot . push . apply ( slot , child . children || [ ] ) ;
}
else {
slot . push ( child ) ;
}
}
else {
( slots . default || ( slots . default = [ ] ) ) . push ( child ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// ignore slots that contains only whitespace
for ( const name in slots ) {
if ( slots [ name ] . every ( isWhitespace ) ) {
delete slots [ name ] ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return slots ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isWhitespace ( node ) {
return ( node . isComment && ! node . asyncFactory ) || node . text === ' ' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isAsyncPlaceholder ( node ) {
// @ts-expect-error not really boolean type
return node . isComment && node . asyncFactory ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function normalizeScopedSlots ( ownerVm , scopedSlots , normalSlots , prevScopedSlots ) {
let res ;
const hasNormalSlots = Object . keys ( normalSlots ) . length > 0 ;
const isStable = scopedSlots ? ! ! scopedSlots . $stable : ! hasNormalSlots ;
const key = scopedSlots && scopedSlots . $key ;
if ( ! scopedSlots ) {
res = { } ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( scopedSlots . _normalized ) {
// fast path 1: child component re-render only, parent did not change
return scopedSlots . _normalized ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( isStable &&
prevScopedSlots &&
prevScopedSlots !== emptyObject &&
key === prevScopedSlots . $key &&
! hasNormalSlots &&
! prevScopedSlots . $hasNormal ) {
// fast path 2: stable scoped slots w/ no normal slots to proxy,
// only need to normalize once
return prevScopedSlots ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
res = { } ;
for ( const key in scopedSlots ) {
if ( scopedSlots [ key ] && key [ 0 ] !== '$' ) {
res [ key ] = normalizeScopedSlot ( ownerVm , normalSlots , key , scopedSlots [ key ] ) ;
}
}
}
// expose normal slots on scopedSlots
for ( const key in normalSlots ) {
if ( ! ( key in res ) ) {
res [ key ] = proxyNormalSlot ( normalSlots , key ) ;
}
}
// avoriaz seems to mock a non-extensible $scopedSlots object
// and when that is passed down this would cause an error
if ( scopedSlots && Object . isExtensible ( scopedSlots ) ) {
scopedSlots . _normalized = res ;
}
def ( res , '$stable' , isStable ) ;
def ( res , '$key' , key ) ;
def ( res , '$hasNormal' , hasNormalSlots ) ;
return res ;
}
function normalizeScopedSlot ( vm , normalSlots , key , fn ) {
const normalized = function ( ) {
const cur = currentInstance ;
setCurrentInstance ( vm ) ;
let res = arguments . length ? fn . apply ( null , arguments ) : fn ( { } ) ;
res =
res && typeof res === 'object' && ! isArray ( res )
? [ res ] // single vnode
: normalizeChildren ( res ) ;
const vnode = res && res [ 0 ] ;
setCurrentInstance ( cur ) ;
return res &&
( ! vnode ||
( res . length === 1 && vnode . isComment && ! isAsyncPlaceholder ( vnode ) ) ) // #9658, #10391
? undefined
: res ;
} ;
// this is a slot using the new v-slot syntax without scope. although it is
// compiled as a scoped slot, render fn users would expect it to be present
// on this.$slots because the usage is semantically a normal slot.
if ( fn . proxy ) {
Object . defineProperty ( normalSlots , key , {
get : normalized ,
enumerable : true ,
configurable : true
} ) ;
}
return normalized ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function proxyNormalSlot ( slots , key ) {
return ( ) => slots [ key ] ;
}
function initSetup ( vm ) {
const options = vm . $options ;
const setup = options . setup ;
if ( setup ) {
const ctx = ( vm . _setupContext = createSetupContext ( vm ) ) ;
setCurrentInstance ( vm ) ;
pushTarget ( ) ;
const setupResult = invokeWithErrorHandling ( setup , null , [ vm . _props || shallowReactive ( { } ) , ctx ] , vm , ` setup ` ) ;
popTarget ( ) ;
setCurrentInstance ( ) ;
if ( isFunction ( setupResult ) ) {
// render function
// @ts-ignore
options . render = setupResult ;
}
else if ( isObject ( setupResult ) ) {
// bindings
if ( setupResult instanceof VNode ) {
warn ( ` setup() should not return VNodes directly - ` +
` return a render function instead. ` ) ;
}
vm . _setupState = setupResult ;
// __sfc indicates compiled bindings from <script setup>
if ( ! setupResult . _ _sfc ) {
for ( const key in setupResult ) {
if ( ! isReserved ( key ) ) {
proxyWithRefUnwrap ( vm , setupResult , key ) ;
}
else {
warn ( ` Avoid using variables that start with _ or $ in setup(). ` ) ;
}
}
}
else {
// exposed for compiled render fn
const proxy = ( vm . _setupProxy = { } ) ;
for ( const key in setupResult ) {
if ( key !== '__sfc' ) {
proxyWithRefUnwrap ( proxy , setupResult , key ) ;
}
}
}
}
else if ( setupResult !== undefined ) {
warn ( ` setup() should return an object. Received: ${ setupResult === null ? 'null' : typeof setupResult } ` ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createSetupContext ( vm ) {
let exposeCalled = false ;
return {
get attrs ( ) {
if ( ! vm . _attrsProxy ) {
const proxy = ( vm . _attrsProxy = { } ) ;
def ( proxy , '_v_attr_proxy' , true ) ;
syncSetupProxy ( proxy , vm . $attrs , emptyObject , vm , '$attrs' ) ;
}
return vm . _attrsProxy ;
} ,
get listeners ( ) {
if ( ! vm . _listenersProxy ) {
const proxy = ( vm . _listenersProxy = { } ) ;
syncSetupProxy ( proxy , vm . $listeners , emptyObject , vm , '$listeners' ) ;
}
return vm . _listenersProxy ;
} ,
get slots ( ) {
return initSlotsProxy ( vm ) ;
} ,
emit : bind ( vm . $emit , vm ) ,
expose ( exposed ) {
{
if ( exposeCalled ) {
warn ( ` expose() should be called only once per setup(). ` , vm ) ;
}
exposeCalled = true ;
}
if ( exposed ) {
Object . keys ( exposed ) . forEach ( key => proxyWithRefUnwrap ( vm , exposed , key ) ) ;
}
}
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function syncSetupProxy ( to , from , prev , instance , type ) {
let changed = false ;
for ( const key in from ) {
if ( ! ( key in to ) ) {
changed = true ;
defineProxyAttr ( to , key , instance , type ) ;
}
else if ( from [ key ] !== prev [ key ] ) {
changed = true ;
}
}
for ( const key in to ) {
if ( ! ( key in from ) ) {
changed = true ;
delete to [ key ] ;
}
}
return changed ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function defineProxyAttr ( proxy , key , instance , type ) {
Object . defineProperty ( proxy , key , {
enumerable : true ,
configurable : true ,
get ( ) {
return instance [ type ] [ key ] ;
}
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initSlotsProxy ( vm ) {
if ( ! vm . _slotsProxy ) {
syncSetupSlots ( ( vm . _slotsProxy = { } ) , vm . $scopedSlots ) ;
}
return vm . _slotsProxy ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function syncSetupSlots ( to , from ) {
for ( const key in from ) {
to [ key ] = from [ key ] ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
for ( const key in to ) {
if ( ! ( key in from ) ) {
delete to [ key ] ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
/ * *
* @ internal use manual type def because public setup context type relies on
* legacy VNode types
* /
function useSlots ( ) {
return getContext ( ) . slots ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* @ internal use manual type def because public setup context type relies on
* legacy VNode types
* /
function useAttrs ( ) {
return getContext ( ) . attrs ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* Vue 2 only
* @ internal use manual type def because public setup context type relies on
* legacy VNode types
* /
function useListeners ( ) {
return getContext ( ) . listeners ;
}
function getContext ( ) {
if ( ! currentInstance ) {
warn ( ` useContext() called without active instance. ` ) ;
}
const vm = currentInstance ;
return vm . _setupContext || ( vm . _setupContext = createSetupContext ( vm ) ) ;
}
/ * *
* Runtime helper for merging default declarations . Imported by compiled code
* only .
* @ internal
* /
function mergeDefaults ( raw , defaults ) {
const props = isArray ( raw )
? raw . reduce ( ( normalized , p ) => ( ( normalized [ p ] = { } ) , normalized ) , { } )
: raw ;
for ( const key in defaults ) {
const opt = props [ key ] ;
if ( opt ) {
if ( isArray ( opt ) || isFunction ( opt ) ) {
props [ key ] = { type : opt , default : defaults [ key ] } ;
}
else {
opt . default = defaults [ key ] ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( opt === null ) {
props [ key ] = { default : defaults [ key ] } ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
warn ( ` props default key " ${ key } " has no corresponding declaration. ` ) ;
}
}
return props ;
}
function initRender ( vm ) {
vm . _vnode = null ; // the root of the child tree
vm . _staticTrees = null ; // v-once cached trees
const options = vm . $options ;
const parentVnode = ( vm . $vnode = options . _parentVnode ) ; // the placeholder node in parent tree
const renderContext = parentVnode && parentVnode . context ;
vm . $slots = resolveSlots ( options . _renderChildren , renderContext ) ;
vm . $scopedSlots = parentVnode
? normalizeScopedSlots ( vm . $parent , parentVnode . data . scopedSlots , vm . $slots )
: emptyObject ;
// 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
// @ts-expect-error
vm . _c = ( a , b , c , d ) => createElement$1 ( vm , a , b , c , d , false ) ;
// normalization is always applied for the public version, used in
// user-written render functions.
// @ts-expect-error
vm . $createElement = ( a , b , c , d ) => createElement$1 ( vm , a , b , c , d , true ) ;
// $attrs & $listeners are exposed for easier HOC creation.
// they need to be reactive so that HOCs using them are always updated
const parentData = parentVnode && parentVnode . data ;
/* istanbul ignore else */
{
defineReactive ( vm , '$attrs' , ( parentData && parentData . attrs ) || emptyObject , ( ) => {
! isUpdatingChildComponent && warn ( ` $ attrs is readonly. ` , vm ) ;
} , true ) ;
defineReactive ( vm , '$listeners' , options . _parentListeners || emptyObject , ( ) => {
! isUpdatingChildComponent && warn ( ` $ listeners is readonly. ` , vm ) ;
} , true ) ;
}
}
let currentRenderingInstance = null ;
function renderMixin ( Vue ) {
// install runtime convenience helpers
installRenderHelpers ( Vue . prototype ) ;
Vue . prototype . $nextTick = function ( fn ) {
return nextTick ( fn , this ) ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
Vue . prototype . _render = function ( ) {
const vm = this ;
const { render , _parentVnode } = vm . $options ;
if ( _parentVnode && vm . _isMounted ) {
vm . $scopedSlots = normalizeScopedSlots ( vm . $parent , _parentVnode . data . scopedSlots , vm . $slots , vm . $scopedSlots ) ;
if ( vm . _slotsProxy ) {
syncSetupSlots ( vm . _slotsProxy , vm . $scopedSlots ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// set parent vnode. this allows render functions to have access
// to the data on the placeholder node.
vm . $vnode = _parentVnode ;
// render self
const prevInst = currentInstance ;
const prevRenderInst = currentRenderingInstance ;
let vnode ;
try {
setCurrentInstance ( vm ) ;
currentRenderingInstance = vm ;
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 ( 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 ;
}
}
finally {
currentRenderingInstance = prevRenderInst ;
setCurrentInstance ( prevInst ) ;
}
// if the returned array contains only a single node, allow it
if ( isArray ( vnode ) && vnode . length === 1 ) {
vnode = vnode [ 0 ] ;
}
// return empty vnode in case the render function errored out
if ( ! ( vnode instanceof VNode ) ) {
if ( isArray ( vnode ) ) {
warn ( 'Multiple root nodes returned from render function. Render function ' +
'should return a single root node.' , vm ) ;
}
vnode = createEmptyVNode ( ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// set parent
vnode . parent = _parentVnode ;
return vnode ;
} ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function ensureCtor ( comp , base ) {
if ( comp . _ _esModule || ( hasSymbol && comp [ Symbol . toStringTag ] === 'Module' ) ) {
comp = comp . default ;
}
return isObject ( comp ) ? base . extend ( comp ) : comp ;
}
function createAsyncPlaceholder ( factory , data , context , children , tag ) {
const node = createEmptyVNode ( ) ;
node . asyncFactory = factory ;
node . asyncMeta = { data , context , children , tag } ;
return node ;
}
function resolveAsyncComponent ( factory , baseCtor ) {
if ( isTrue ( factory . error ) && isDef ( factory . errorComp ) ) {
return factory . errorComp ;
}
if ( isDef ( factory . resolved ) ) {
return factory . resolved ;
}
const owner = currentRenderingInstance ;
if ( owner && isDef ( factory . owners ) && factory . owners . indexOf ( owner ) === - 1 ) {
// already pending
factory . owners . push ( owner ) ;
}
if ( isTrue ( factory . loading ) && isDef ( factory . loadingComp ) ) {
return factory . loadingComp ;
}
if ( owner && ! isDef ( factory . owners ) ) {
const owners = ( factory . owners = [ owner ] ) ;
let sync = true ;
let timerLoading = null ;
let timerTimeout = null ;
owner . $on ( 'hook:destroyed' , ( ) => remove$2 ( owners , owner ) ) ;
const forceRender = ( renderCompleted ) => {
for ( let i = 0 , l = owners . length ; i < l ; i ++ ) {
owners [ i ] . $forceUpdate ( ) ;
}
if ( renderCompleted ) {
owners . length = 0 ;
if ( timerLoading !== null ) {
clearTimeout ( timerLoading ) ;
timerLoading = null ;
}
if ( timerTimeout !== null ) {
clearTimeout ( timerTimeout ) ;
timerTimeout = null ;
}
}
} ;
const resolve = once ( ( res ) => {
// cache resolved
factory . resolved = ensureCtor ( res , baseCtor ) ;
// invoke callbacks only if this is not a synchronous resolve
// (async resolves are shimmed as synchronous during SSR)
if ( ! sync ) {
forceRender ( true ) ;
}
else {
owners . length = 0 ;
}
} ) ;
const reject = once ( reason => {
warn ( ` Failed to resolve async component: ${ String ( factory ) } ` +
( reason ? ` \n Reason: ${ reason } ` : '' ) ) ;
if ( isDef ( factory . errorComp ) ) {
factory . error = true ;
forceRender ( true ) ;
}
} ) ;
const res = factory ( resolve , reject ) ;
if ( isObject ( res ) ) {
if ( isPromise ( res ) ) {
// () => Promise
if ( isUndef ( factory . resolved ) ) {
res . then ( resolve , reject ) ;
}
}
else if ( isPromise ( res . component ) ) {
res . component . then ( resolve , reject ) ;
if ( isDef ( res . error ) ) {
factory . errorComp = ensureCtor ( res . error , baseCtor ) ;
}
if ( isDef ( res . loading ) ) {
factory . loadingComp = ensureCtor ( res . loading , baseCtor ) ;
if ( res . delay === 0 ) {
factory . loading = true ;
}
else {
// @ts-expect-error NodeJS timeout type
timerLoading = setTimeout ( ( ) => {
timerLoading = null ;
if ( isUndef ( factory . resolved ) && isUndef ( factory . error ) ) {
factory . loading = true ;
forceRender ( false ) ;
}
} , res . delay || 200 ) ;
}
}
if ( isDef ( res . timeout ) ) {
// @ts-expect-error NodeJS timeout type
timerTimeout = setTimeout ( ( ) => {
timerTimeout = null ;
if ( isUndef ( factory . resolved ) ) {
reject ( ` timeout ( ${ res . timeout } ms) ` ) ;
}
} , res . timeout ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
sync = false ;
// return in case resolved synchronously
return factory . loading ? factory . loadingComp : factory . resolved ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function getFirstComponentChild ( children ) {
if ( isArray ( children ) ) {
for ( let i = 0 ; i < children . length ; i ++ ) {
const c = children [ i ] ;
if ( isDef ( c ) && ( isDef ( c . componentOptions ) || isAsyncPlaceholder ( c ) ) ) {
return c ;
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const SIMPLE _NORMALIZE = 1 ;
const ALWAYS _NORMALIZE = 2 ;
// wrapper function for providing a more flexible interface
// without getting yelled at by flow
function createElement$1 ( context , tag , data , children , normalizationType , alwaysNormalize ) {
if ( isArray ( data ) || isPrimitive ( data ) ) {
normalizationType = children ;
children = data ;
data = undefined ;
}
if ( isTrue ( alwaysNormalize ) ) {
normalizationType = ALWAYS _NORMALIZE ;
}
return _createElement ( context , tag , data , children , normalizationType ) ;
}
function _createElement ( context , tag , data , children , normalizationType ) {
if ( isDef ( data ) && isDef ( data . _ _ob _ _ ) ) {
warn ( ` Avoid using observed data object as vnode data: ${ JSON . stringify ( data ) } \n ` + 'Always create fresh vnode data objects in each render!' , context ) ;
return createEmptyVNode ( ) ;
}
// object syntax in v-bind
if ( isDef ( data ) && isDef ( data . is ) ) {
tag = data . is ;
}
if ( ! tag ) {
// in case of component :is set to falsy value
return createEmptyVNode ( ) ;
}
// warn against non-primitive key
if ( isDef ( data ) && isDef ( data . key ) && ! isPrimitive ( data . key ) ) {
warn ( 'Avoid using non-primitive value as key, ' +
'use string/number value instead.' , context ) ;
}
// support single function children as default scoped slot
if ( isArray ( children ) && isFunction ( children [ 0 ] ) ) {
data = data || { } ;
data . scopedSlots = { default : children [ 0 ] } ;
children . length = 0 ;
}
if ( normalizationType === ALWAYS _NORMALIZE ) {
children = normalizeChildren ( children ) ;
}
else if ( normalizationType === SIMPLE _NORMALIZE ) {
children = simpleNormalizeChildren ( children ) ;
}
let vnode , ns ;
if ( typeof tag === 'string' ) {
let Ctor ;
ns = ( context . $vnode && context . $vnode . ns ) || config . getTagNamespace ( tag ) ;
if ( config . isReservedTag ( tag ) ) {
// platform built-in elements
if ( isDef ( data ) &&
isDef ( data . nativeOn ) &&
data . tag !== 'component' ) {
warn ( ` The .native modifier for v-on is only valid on components but it was used on < ${ tag } >. ` , context ) ;
}
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 ( isArray ( vnode ) ) {
return vnode ;
}
else if ( isDef ( vnode ) ) {
if ( isDef ( ns ) )
applyNS ( vnode , ns ) ;
if ( isDef ( data ) )
registerDeepBindings ( data ) ;
return vnode ;
}
else {
return createEmptyVNode ( ) ;
}
}
function applyNS ( vnode , ns , force ) {
vnode . ns = ns ;
if ( vnode . tag === 'foreignObject' ) {
// use default namespace inside foreignObject
ns = undefined ;
force = true ;
}
if ( isDef ( vnode . children ) ) {
for ( let i = 0 , l = vnode . children . length ; i < l ; i ++ ) {
const child = vnode . children [ i ] ;
if ( isDef ( child . tag ) &&
( isUndef ( child . ns ) || ( isTrue ( force ) && child . tag !== 'svg' ) ) ) {
applyNS ( child , ns , force ) ;
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
// ref #5318
// necessary to ensure parent re-render when deep bindings like :style and
// :class are used on slot nodes
function registerDeepBindings ( data ) {
if ( isObject ( data . style ) ) {
traverse ( data . style ) ;
}
if ( isObject ( data . class ) ) {
traverse ( data . class ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* @ internal this function needs manual public type declaration because it relies
* on previously manually authored types from Vue 2
* /
function h ( type , props , children ) {
if ( ! currentInstance ) {
warn ( ` globally imported h() can only be invoked when there is an active ` +
` component instance, e.g. synchronously in a component's render or setup function. ` ) ;
}
return createElement$1 ( currentInstance , type , props , children , 2 , true ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function handleError ( err , vm , info ) {
// Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
// See: https://github.com/vuejs/vuex/issues/1505
pushTarget ( ) ;
try {
if ( vm ) {
let cur = vm ;
while ( ( cur = cur . $parent ) ) {
const hooks = cur . $options . errorCaptured ;
if ( hooks ) {
for ( let i = 0 ; i < hooks . length ; i ++ ) {
try {
const capture = hooks [ i ] . call ( cur , err , vm , info ) === false ;
if ( capture )
return ;
}
catch ( e ) {
globalHandleError ( e , cur , 'errorCaptured hook' ) ;
}
}
}
}
}
globalHandleError ( err , vm , info ) ;
}
finally {
popTarget ( ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function invokeWithErrorHandling ( handler , context , args , vm , info ) {
let res ;
try {
res = args ? handler . apply ( context , args ) : handler . call ( context ) ;
if ( res && ! res . _isVue && isPromise ( res ) && ! res . _handled ) {
res . catch ( e => handleError ( e , vm , info + ` (Promise/async) ` ) ) ;
res . _handled = true ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
catch ( e ) {
handleError ( e , vm , info ) ;
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function globalHandleError ( err , vm , info ) {
if ( config . errorHandler ) {
try {
return config . errorHandler . call ( null , err , vm , info ) ;
}
catch ( e ) {
// if the user intentionally throws the original error in the handler,
// do not log it twice
if ( e !== err ) {
logError ( e , null , 'config.errorHandler' ) ;
}
}
}
logError ( err , vm , info ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function logError ( err , vm , info ) {
2023-12-18 13:12:25 +08:00
{
2024-01-16 21:26:16 +08:00
warn ( ` Error in ${ info } : " ${ err . toString ( ) } " ` , vm ) ;
}
/* istanbul ignore else */
if ( inBrowser && typeof console !== 'undefined' ) {
console . error ( err ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
throw err ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
/* globals MutationObserver */
let isUsingMicroTask = false ;
const callbacks = [ ] ;
let pending = false ;
function flushCallbacks ( ) {
pending = false ;
const copies = callbacks . slice ( 0 ) ;
callbacks . length = 0 ;
for ( let i = 0 ; i < copies . length ; i ++ ) {
copies [ i ] ( ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// Here we have async deferring wrappers using microtasks.
// In 2.5 we used (macro) tasks (in combination with microtasks).
// However, it has subtle problems when state is changed right before repaint
// (e.g. #6813, out-in transitions).
// Also, using (macro) tasks in event handler would cause some weird behaviors
// that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).
// So we now use microtasks everywhere, again.
// A major drawback of this tradeoff is that there are some scenarios
// where microtasks have too high a priority and fire in between supposedly
// sequential events (e.g. #4521, #6690, which have workarounds)
// or even between bubbling of the same event (#6566).
let timerFunc ;
// The nextTick behavior leverages the microtask queue, which can be accessed
// via either native Promise.then or MutationObserver.
// MutationObserver has wider support, however it is seriously bugged in
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
// completely stops working after triggering a few times... so, if native
// Promise is available, we will use it:
/* istanbul ignore next, $flow-disable-line */
if ( typeof Promise !== 'undefined' && isNative ( Promise ) ) {
const p = Promise . resolve ( ) ;
timerFunc = ( ) => {
p . then ( flushCallbacks ) ;
// In problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if ( isIOS )
setTimeout ( noop ) ;
} ;
isUsingMicroTask = true ;
}
else if ( ! isIE &&
typeof MutationObserver !== 'undefined' &&
( isNative ( MutationObserver ) ||
// PhantomJS and iOS 7.x
MutationObserver . toString ( ) === '[object MutationObserverConstructor]' ) ) {
// Use MutationObserver where native Promise is not available,
// e.g. PhantomJS, iOS7, Android 4.4
// (#6466 MutationObserver is unreliable in IE11)
let counter = 1 ;
const observer = new MutationObserver ( flushCallbacks ) ;
const textNode = document . createTextNode ( String ( counter ) ) ;
observer . observe ( textNode , {
characterData : true
} ) ;
timerFunc = ( ) => {
counter = ( counter + 1 ) % 2 ;
textNode . data = String ( counter ) ;
} ;
isUsingMicroTask = true ;
}
else if ( typeof setImmediate !== 'undefined' && isNative ( setImmediate ) ) {
// Fallback to setImmediate.
// Technically it leverages the (macro) task queue,
// but it is still a better choice than setTimeout.
timerFunc = ( ) => {
setImmediate ( flushCallbacks ) ;
} ;
}
else {
// Fallback to setTimeout.
timerFunc = ( ) => {
setTimeout ( flushCallbacks , 0 ) ;
} ;
}
/ * *
* @ internal
* /
function nextTick ( cb , ctx ) {
let _resolve ;
callbacks . push ( ( ) => {
if ( cb ) {
try {
cb . call ( ctx ) ;
}
catch ( e ) {
handleError ( e , ctx , 'nextTick' ) ;
}
}
else if ( _resolve ) {
_resolve ( ctx ) ;
}
} ) ;
if ( ! pending ) {
pending = true ;
timerFunc ( ) ;
}
// $flow-disable-line
if ( ! cb && typeof Promise !== 'undefined' ) {
return new Promise ( resolve => {
_resolve = resolve ;
} ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function useCssModule ( name = '$style' ) {
/* istanbul ignore else */
{
if ( ! currentInstance ) {
warn ( ` useCssModule must be called inside setup() ` ) ;
return emptyObject ;
}
const mod = currentInstance [ name ] ;
if ( ! mod ) {
warn ( ` Current instance does not have CSS module named " ${ name } ". ` ) ;
return emptyObject ;
}
return mod ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/ * *
* Runtime helper for SFC ' s CSS variable injection feature .
* @ private
* /
function useCssVars ( getter ) {
if ( ! inBrowser && ! false )
return ;
const instance = currentInstance ;
if ( ! instance ) {
warn ( ` useCssVars is called without current active component instance. ` ) ;
return ;
}
watchPostEffect ( ( ) => {
const el = instance . $el ;
const vars = getter ( instance , instance . _setupProxy ) ;
if ( el && el . nodeType === 1 ) {
const style = el . style ;
for ( const key in vars ) {
style . setProperty ( ` -- ${ key } ` , vars [ key ] ) ;
}
}
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* v3 - compatible async component API .
* @ internal the type is manually declared in < root > / t y p e s / v 3 - d e f i n e - a s y n c - c o m p o n e n t . d . t s
* because it relies on existing manual types
* /
function defineAsyncComponent ( source ) {
if ( isFunction ( source ) ) {
source = { loader : source } ;
}
const { loader , loadingComponent , errorComponent , delay = 200 , timeout , // undefined = never times out
suspensible = false , // in Vue 3 default is true
onError : userOnError } = source ;
if ( suspensible ) {
warn ( ` The suspensible option for async components is not supported in Vue2. It is ignored. ` ) ;
}
let pendingRequest = null ;
let retries = 0 ;
const retry = ( ) => {
retries ++ ;
pendingRequest = null ;
return load ( ) ;
} ;
const load = ( ) => {
let thisRequest ;
return ( pendingRequest ||
( thisRequest = pendingRequest =
loader ( )
. catch ( err => {
err = err instanceof Error ? err : new Error ( String ( err ) ) ;
if ( userOnError ) {
return new Promise ( ( resolve , reject ) => {
const userRetry = ( ) => resolve ( retry ( ) ) ;
const userFail = ( ) => reject ( err ) ;
userOnError ( err , userRetry , userFail , retries + 1 ) ;
} ) ;
}
else {
throw err ;
}
} )
. then ( ( comp ) => {
if ( thisRequest !== pendingRequest && pendingRequest ) {
return pendingRequest ;
}
if ( ! comp ) {
warn ( ` Async component loader resolved to undefined. ` +
` If you are using retry(), make sure to return its return value. ` ) ;
}
// interop module default
if ( comp &&
( comp . _ _esModule || comp [ Symbol . toStringTag ] === 'Module' ) ) {
comp = comp . default ;
}
if ( comp && ! isObject ( comp ) && ! isFunction ( comp ) ) {
throw new Error ( ` Invalid async component load result: ${ comp } ` ) ;
}
return comp ;
} ) ) ) ;
} ;
return ( ) => {
const component = load ( ) ;
return {
component ,
delay ,
timeout ,
error : errorComponent ,
loading : loadingComponent
} ;
} ;
}
function createLifeCycle ( hookName ) {
return ( fn , target = currentInstance ) => {
if ( ! target ) {
warn ( ` ${ formatName ( hookName ) } is called when there is no active component instance to be ` +
` associated with. ` +
` Lifecycle injection APIs can only be used during execution of setup(). ` ) ;
return ;
}
return injectHook ( target , hookName , fn ) ;
} ;
}
function formatName ( name ) {
if ( name === 'beforeDestroy' ) {
name = 'beforeUnmount' ;
}
else if ( name === 'destroyed' ) {
name = 'unmounted' ;
}
return ` on ${ name [ 0 ] . toUpperCase ( ) + name . slice ( 1 ) } ` ;
}
function injectHook ( instance , hookName , fn ) {
const options = instance . $options ;
options [ hookName ] = mergeLifecycleHook ( options [ hookName ] , fn ) ;
}
const onBeforeMount = createLifeCycle ( 'beforeMount' ) ;
const onMounted = createLifeCycle ( 'mounted' ) ;
const onBeforeUpdate = createLifeCycle ( 'beforeUpdate' ) ;
const onUpdated = createLifeCycle ( 'updated' ) ;
const onBeforeUnmount = createLifeCycle ( 'beforeDestroy' ) ;
const onUnmounted = createLifeCycle ( 'destroyed' ) ;
const onActivated = createLifeCycle ( 'activated' ) ;
const onDeactivated = createLifeCycle ( 'deactivated' ) ;
const onServerPrefetch = createLifeCycle ( 'serverPrefetch' ) ;
const onRenderTracked = createLifeCycle ( 'renderTracked' ) ;
const onRenderTriggered = createLifeCycle ( 'renderTriggered' ) ;
const injectErrorCapturedHook = createLifeCycle ( 'errorCaptured' ) ;
function onErrorCaptured ( hook , target = currentInstance ) {
injectErrorCapturedHook ( hook , target ) ;
}
/ * *
* Note : also update dist / vue . runtime . mjs when adding new exports to this file .
* /
const version = '2.7.16' ;
/ * *
* @ internal type is manually declared in < root > / t y p e s / v 3 - d e f i n e - c o m p o n e n t . d . t s
* /
function defineComponent ( options ) {
return options ;
}
var vca = /*#__PURE__*/ Object . freeze ( {
_ _proto _ _ : null ,
version : version ,
defineComponent : defineComponent ,
ref : ref$1 ,
shallowRef : shallowRef ,
isRef : isRef ,
toRef : toRef ,
toRefs : toRefs ,
unref : unref ,
proxyRefs : proxyRefs ,
customRef : customRef ,
triggerRef : triggerRef ,
reactive : reactive ,
isReactive : isReactive ,
isReadonly : isReadonly ,
isShallow : isShallow ,
isProxy : isProxy ,
shallowReactive : shallowReactive ,
markRaw : markRaw ,
toRaw : toRaw ,
readonly : readonly ,
shallowReadonly : shallowReadonly ,
computed : computed ,
watch : watch ,
watchEffect : watchEffect ,
watchPostEffect : watchPostEffect ,
watchSyncEffect : watchSyncEffect ,
EffectScope : EffectScope ,
effectScope : effectScope ,
onScopeDispose : onScopeDispose ,
getCurrentScope : getCurrentScope ,
provide : provide ,
inject : inject ,
h : h ,
getCurrentInstance : getCurrentInstance ,
useSlots : useSlots ,
useAttrs : useAttrs ,
useListeners : useListeners ,
mergeDefaults : mergeDefaults ,
nextTick : nextTick ,
set : set ,
del : del ,
useCssModule : useCssModule ,
useCssVars : useCssVars ,
defineAsyncComponent : defineAsyncComponent ,
onBeforeMount : onBeforeMount ,
onMounted : onMounted ,
onBeforeUpdate : onBeforeUpdate ,
onUpdated : onUpdated ,
onBeforeUnmount : onBeforeUnmount ,
onUnmounted : onUnmounted ,
onActivated : onActivated ,
onDeactivated : onDeactivated ,
onServerPrefetch : onServerPrefetch ,
onRenderTracked : onRenderTracked ,
onRenderTriggered : onRenderTriggered ,
onErrorCaptured : onErrorCaptured
} ) ;
const seenObjects = new _Set ( ) ;
/ * *
* Recursively traverse an object to evoke all converted
* getters , so that every nested property inside the object
* is collected as a "deep" dependency .
* /
function traverse ( val ) {
_traverse ( val , seenObjects ) ;
seenObjects . clear ( ) ;
return val ;
}
function _traverse ( val , seen ) {
let i , keys ;
const isA = isArray ( val ) ;
if ( ( ! isA && ! isObject ( val ) ) ||
val . _ _v _skip /* ReactiveFlags.SKIP */ ||
Object . isFrozen ( val ) ||
val instanceof VNode ) {
return ;
}
if ( val . _ _ob _ _ ) {
const depId = val . _ _ob _ _ . dep . id ;
if ( seen . has ( depId ) ) {
return ;
}
seen . add ( depId ) ;
}
if ( isA ) {
i = val . length ;
while ( i -- )
_traverse ( val [ i ] , seen ) ;
}
else if ( isRef ( val ) ) {
_traverse ( val . value , seen ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
keys = Object . keys ( val ) ;
i = keys . length ;
while ( i -- )
_traverse ( val [ keys [ i ] ] , seen ) ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let uid$1 = 0 ;
/ * *
* A watcher parses an expression , collects dependencies ,
* and fires callback when the expression value changes .
* This is used for both the $watch ( ) api and directives .
* @ internal
* /
class Watcher {
constructor ( vm , expOrFn , cb , options , isRenderWatcher ) {
recordEffectScope ( this ,
// if the active effect scope is manually created (not a component scope),
// prioritize it
activeEffectScope && ! activeEffectScope . _vm
? activeEffectScope
: vm
? vm . _scope
: undefined ) ;
if ( ( this . vm = vm ) && isRenderWatcher ) {
vm . _watcher = this ;
}
// options
if ( options ) {
this . deep = ! ! options . deep ;
this . user = ! ! options . user ;
this . lazy = ! ! options . lazy ;
this . sync = ! ! options . sync ;
this . before = options . before ;
{
this . onTrack = options . onTrack ;
this . onTrigger = options . onTrigger ;
}
}
else {
this . deep = this . user = this . lazy = this . sync = false ;
}
this . cb = cb ;
this . id = ++ uid$1 ; // uid for batching
this . active = true ;
this . post = false ;
this . dirty = this . lazy ; // for lazy watchers
this . deps = [ ] ;
this . newDeps = [ ] ;
this . depIds = new _Set ( ) ;
this . newDepIds = new _Set ( ) ;
this . expression = expOrFn . toString ( ) ;
// parse expression for getter
if ( isFunction ( expOrFn ) ) {
this . getter = expOrFn ;
}
else {
this . getter = parsePath ( expOrFn ) ;
if ( ! this . getter ) {
this . getter = noop ;
warn ( ` Failed watching path: " ${ expOrFn } " ` +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.' , vm ) ;
}
}
this . value = this . lazy ? undefined : this . get ( ) ;
}
/ * *
* Evaluate the getter , and re - collect dependencies .
* /
get ( ) {
pushTarget ( this ) ;
let value ;
const vm = this . vm ;
try {
value = this . getter . call ( vm , vm ) ;
}
catch ( e ) {
if ( this . user ) {
handleError ( e , vm , ` getter for watcher " ${ this . expression } " ` ) ;
}
else {
throw e ;
}
}
finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if ( this . deep ) {
traverse ( value ) ;
}
popTarget ( ) ;
this . cleanupDeps ( ) ;
}
return value ;
}
/ * *
* Add a dependency to this directive .
* /
addDep ( dep ) {
const id = dep . id ;
if ( ! this . newDepIds . has ( id ) ) {
this . newDepIds . add ( id ) ;
this . newDeps . push ( dep ) ;
if ( ! this . depIds . has ( id ) ) {
dep . addSub ( this ) ;
}
}
}
/ * *
* Clean up for dependency collection .
* /
cleanupDeps ( ) {
let i = this . deps . length ;
while ( i -- ) {
const dep = this . deps [ i ] ;
if ( ! this . newDepIds . has ( dep . id ) ) {
dep . removeSub ( this ) ;
}
}
let tmp = this . depIds ;
this . depIds = this . newDepIds ;
this . newDepIds = tmp ;
this . newDepIds . clear ( ) ;
tmp = this . deps ;
this . deps = this . newDeps ;
this . newDeps = tmp ;
this . newDeps . length = 0 ;
}
/ * *
* Subscriber interface .
* Will be called when a dependency changes .
* /
update ( ) {
/* istanbul ignore else */
if ( this . lazy ) {
this . dirty = true ;
}
else if ( this . sync ) {
this . run ( ) ;
}
else {
queueWatcher ( this ) ;
}
}
/ * *
* Scheduler job interface .
* Will be called by the scheduler .
* /
run ( ) {
if ( this . active ) {
const value = this . get ( ) ;
if ( value !== this . value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
isObject ( value ) ||
this . deep ) {
// set new value
const oldValue = this . value ;
this . value = value ;
if ( this . user ) {
const info = ` callback for watcher " ${ this . expression } " ` ;
invokeWithErrorHandling ( this . cb , this . vm , [ value , oldValue ] , this . vm , info ) ;
}
else {
this . cb . call ( this . vm , value , oldValue ) ;
}
}
}
}
/ * *
* Evaluate the value of the watcher .
* This only gets called for lazy watchers .
* /
evaluate ( ) {
this . value = this . get ( ) ;
this . dirty = false ;
}
/ * *
* Depend on all deps collected by this watcher .
* /
depend ( ) {
let i = this . deps . length ;
while ( i -- ) {
this . deps [ i ] . depend ( ) ;
}
}
/ * *
* Remove self from all dependencies ' subscriber list .
* /
teardown ( ) {
if ( this . vm && ! this . vm . _isBeingDestroyed ) {
remove$2 ( this . vm . _scope . effects , this ) ;
}
if ( this . active ) {
let i = this . deps . length ;
while ( i -- ) {
this . deps [ i ] . removeSub ( this ) ;
}
this . active = false ;
if ( this . onStop ) {
this . onStop ( ) ;
}
}
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let mark ;
let measure ;
{
const perf = inBrowser && window . performance ;
/* istanbul ignore if */
if ( perf &&
// @ts-ignore
perf . mark &&
// @ts-ignore
perf . measure &&
// @ts-ignore
perf . clearMarks &&
// @ts-ignore
perf . clearMeasures ) {
mark = tag => perf . mark ( tag ) ;
measure = ( name , startTag , endTag ) => {
perf . measure ( name , startTag , endTag ) ;
perf . clearMarks ( startTag ) ;
perf . clearMarks ( endTag ) ;
// perf.clearMeasures(name)
} ;
}
}
function initEvents ( vm ) {
vm . _events = Object . create ( null ) ;
vm . _hasHookEvent = false ;
// init parent attached events
const listeners = vm . $options . _parentListeners ;
if ( listeners ) {
updateComponentListeners ( vm , listeners ) ;
}
}
let target$1 ;
function add$1 ( event , fn ) {
target$1 . $on ( event , fn ) ;
}
function remove$1 ( event , fn ) {
target$1 . $off ( event , fn ) ;
}
function createOnceHandler$1 ( event , fn ) {
const _target = target$1 ;
return function onceHandler ( ) {
const res = fn . apply ( null , arguments ) ;
if ( res !== null ) {
_target . $off ( event , onceHandler ) ;
}
} ;
}
function updateComponentListeners ( vm , listeners , oldListeners ) {
target$1 = vm ;
updateListeners ( listeners , oldListeners || { } , add$1 , remove$1 , createOnceHandler$1 , vm ) ;
target$1 = undefined ;
}
function eventsMixin ( Vue ) {
const hookRE = /^hook:/ ;
Vue . prototype . $on = function ( event , fn ) {
const vm = this ;
if ( isArray ( event ) ) {
for ( let i = 0 , l = event . length ; i < l ; i ++ ) {
vm . $on ( event [ i ] , fn ) ;
}
}
else {
( vm . _events [ event ] || ( vm . _events [ event ] = [ ] ) ) . push ( fn ) ;
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
if ( hookRE . test ( event ) ) {
vm . _hasHookEvent = true ;
}
}
return vm ;
} ;
Vue . prototype . $once = function ( event , fn ) {
const vm = this ;
function on ( ) {
vm . $off ( event , on ) ;
fn . apply ( vm , arguments ) ;
}
on . fn = fn ;
vm . $on ( event , on ) ;
return vm ;
} ;
Vue . prototype . $off = function ( event , fn ) {
const vm = this ;
// all
if ( ! arguments . length ) {
vm . _events = Object . create ( null ) ;
return vm ;
}
// array of events
if ( isArray ( event ) ) {
for ( let i = 0 , l = event . length ; i < l ; i ++ ) {
vm . $off ( event [ i ] , fn ) ;
}
return vm ;
}
// specific event
const cbs = vm . _events [ event ] ;
if ( ! cbs ) {
return vm ;
}
if ( ! fn ) {
vm . _events [ event ] = null ;
return vm ;
}
// specific handler
let cb ;
let i = cbs . length ;
while ( i -- ) {
cb = cbs [ i ] ;
if ( cb === fn || cb . fn === fn ) {
cbs . splice ( i , 1 ) ;
break ;
}
}
return vm ;
} ;
Vue . prototype . $emit = function ( event ) {
const vm = this ;
{
const lowerCaseEvent = event . toLowerCase ( ) ;
if ( lowerCaseEvent !== event && vm . _events [ lowerCaseEvent ] ) {
tip ( ` Event " ${ lowerCaseEvent } " is emitted in component ` +
` ${ formatComponentName ( vm ) } but the handler is registered for " ${ event } ". ` +
` Note that HTML attributes are case-insensitive and you cannot use ` +
` v-on to listen to camelCase events when using in-DOM templates. ` +
` You should probably use " ${ hyphenate ( event ) } " instead of " ${ event } ". ` ) ;
}
}
let cbs = vm . _events [ event ] ;
if ( cbs ) {
cbs = cbs . length > 1 ? toArray ( cbs ) : cbs ;
const args = toArray ( arguments , 1 ) ;
const info = ` event handler for " ${ event } " ` ;
for ( let i = 0 , l = cbs . length ; i < l ; i ++ ) {
invokeWithErrorHandling ( cbs [ i ] , vm , args , vm , info ) ;
}
}
return vm ;
} ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let activeInstance = null ;
let isUpdatingChildComponent = false ;
function setActiveInstance ( vm ) {
const prevActiveInstance = activeInstance ;
activeInstance = vm ;
return ( ) => {
activeInstance = prevActiveInstance ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
}
function initLifecycle ( vm ) {
const options = vm . $options ;
// locate first non-abstract parent
let parent = options . parent ;
if ( parent && ! options . abstract ) {
while ( parent . $options . abstract && parent . $parent ) {
parent = parent . $parent ;
}
parent . $children . push ( vm ) ;
}
vm . $parent = parent ;
vm . $root = parent ? parent . $root : vm ;
vm . $children = [ ] ;
vm . $refs = { } ;
vm . _provided = parent ? parent . _provided : Object . create ( null ) ;
vm . _watcher = null ;
vm . _inactive = null ;
vm . _directInactive = false ;
vm . _isMounted = false ;
vm . _isDestroyed = false ;
vm . _isBeingDestroyed = false ;
}
function lifecycleMixin ( Vue ) {
Vue . prototype . _update = function ( vnode , hydrating ) {
const vm = this ;
const prevEl = vm . $el ;
const prevVnode = vm . _vnode ;
const restoreActiveInstance = setActiveInstance ( vm ) ;
vm . _vnode = vnode ;
// Vue.prototype.__patch__ is injected in entry points
// based on the rendering backend used.
if ( ! prevVnode ) {
// initial render
vm . $el = vm . _ _patch _ _ ( vm . $el , vnode , hydrating , false /* removeOnly */ ) ;
}
else {
// updates
vm . $el = vm . _ _patch _ _ ( prevVnode , vnode ) ;
}
restoreActiveInstance ( ) ;
// update __vue__ reference
if ( prevEl ) {
prevEl . _ _vue _ _ = null ;
}
if ( vm . $el ) {
vm . $el . _ _vue _ _ = vm ;
}
// if parent is an HOC, update its $el as well
let wrapper = vm ;
while ( wrapper &&
wrapper . $vnode &&
wrapper . $parent &&
wrapper . $vnode === wrapper . $parent . _vnode ) {
wrapper . $parent . $el = wrapper . $el ;
wrapper = wrapper . $parent ;
}
// updated hook is called by the scheduler to ensure that children are
// updated in a parent's updated hook.
} ;
Vue . prototype . $forceUpdate = function ( ) {
const vm = this ;
if ( vm . _watcher ) {
vm . _watcher . update ( ) ;
}
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
Vue . prototype . $destroy = function ( ) {
const vm = this ;
if ( vm . _isBeingDestroyed ) {
return ;
}
callHook$1 ( vm , 'beforeDestroy' ) ;
vm . _isBeingDestroyed = true ;
// remove self from parent
const parent = vm . $parent ;
if ( parent && ! parent . _isBeingDestroyed && ! vm . $options . abstract ) {
remove$2 ( parent . $children , vm ) ;
}
// teardown scope. this includes both the render watcher and other
// watchers created
vm . _scope . stop ( ) ;
// remove reference from data ob
// frozen object may not have observer.
if ( vm . _data . _ _ob _ _ ) {
vm . _data . _ _ob _ _ . vmCount -- ;
}
// call the last hook...
vm . _isDestroyed = true ;
// invoke destroy hooks on current rendered tree
vm . _ _patch _ _ ( vm . _vnode , null ) ;
// fire destroyed hook
callHook$1 ( vm , 'destroyed' ) ;
// turn off all instance listeners.
vm . $off ( ) ;
// remove __vue__ reference
if ( vm . $el ) {
vm . $el . _ _vue _ _ = null ;
}
// release circular reference (#6759)
if ( vm . $vnode ) {
vm . $vnode . parent = null ;
}
} ;
}
function mountComponent ( vm , el , hydrating ) {
vm . $el = el ;
if ( ! vm . $options . render ) {
// @ts-expect-error invalid type
vm . $options . render = createEmptyVNode ;
{
/* istanbul ignore if */
if ( ( vm . $options . template && vm . $options . template . charAt ( 0 ) !== '#' ) ||
vm . $options . el ||
el ) {
warn ( 'You are using the runtime-only build of Vue where the template ' +
'compiler is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.' , vm ) ;
}
else {
warn ( 'Failed to mount component: template or render function not defined.' , vm ) ;
}
}
}
callHook$1 ( vm , 'beforeMount' ) ;
let updateComponent ;
/* istanbul ignore if */
if ( config . performance && mark ) {
updateComponent = ( ) => {
const name = vm . _name ;
const id = vm . _uid ;
const startTag = ` vue-perf-start: ${ id } ` ;
const endTag = ` vue-perf-end: ${ id } ` ;
mark ( startTag ) ;
const vnode = vm . _render ( ) ;
mark ( endTag ) ;
measure ( ` vue ${ name } render ` , startTag , endTag ) ;
mark ( startTag ) ;
vm . _update ( vnode , hydrating ) ;
mark ( endTag ) ;
measure ( ` vue ${ name } patch ` , startTag , endTag ) ;
} ;
}
else {
updateComponent = ( ) => {
vm . _update ( vm . _render ( ) , hydrating ) ;
} ;
}
const watcherOptions = {
before ( ) {
if ( vm . _isMounted && ! vm . _isDestroyed ) {
callHook$1 ( vm , 'beforeUpdate' ) ;
}
}
} ;
{
watcherOptions . onTrack = e => callHook$1 ( vm , 'renderTracked' , [ e ] ) ;
watcherOptions . onTrigger = e => callHook$1 ( vm , 'renderTriggered' , [ e ] ) ;
}
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher ( vm , updateComponent , noop , watcherOptions , true /* isRenderWatcher */ ) ;
hydrating = false ;
// flush buffer for flush: "pre" watchers queued in setup()
const preWatchers = vm . _preWatchers ;
if ( preWatchers ) {
for ( let i = 0 ; i < preWatchers . length ; i ++ ) {
preWatchers [ i ] . run ( ) ;
}
}
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if ( vm . $vnode == null ) {
vm . _isMounted = true ;
callHook$1 ( vm , 'mounted' ) ;
}
return vm ;
}
function updateChildComponent ( vm , propsData , listeners , parentVnode , renderChildren ) {
{
isUpdatingChildComponent = true ;
}
// determine whether component has slot children
// we need to do this before overwriting $options._renderChildren.
// check if there are dynamic scopedSlots (hand-written or compiled but with
// dynamic slot names). Static scoped slots compiled from template has the
// "$stable" marker.
const newScopedSlots = parentVnode . data . scopedSlots ;
const oldScopedSlots = vm . $scopedSlots ;
const hasDynamicScopedSlot = ! ! ( ( newScopedSlots && ! newScopedSlots . $stable ) ||
( oldScopedSlots !== emptyObject && ! oldScopedSlots . $stable ) ||
( newScopedSlots && vm . $scopedSlots . $key !== newScopedSlots . $key ) ||
( ! newScopedSlots && vm . $scopedSlots . $key ) ) ;
// Any static slot children from the parent may have changed during parent's
// update. Dynamic scoped slots may also have changed. In such cases, a forced
// update is necessary to ensure correctness.
let needsForceUpdate = ! ! ( renderChildren || // has new static slots
vm . $options . _renderChildren || // has old static slots
hasDynamicScopedSlot ) ;
const prevVNode = vm . $vnode ;
vm . $options . _parentVnode = parentVnode ;
vm . $vnode = parentVnode ; // update vm's placeholder node without re-render
if ( vm . _vnode ) {
// update child tree's parent
vm . _vnode . parent = parentVnode ;
}
vm . $options . _renderChildren = renderChildren ;
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
const attrs = parentVnode . data . attrs || emptyObject ;
if ( vm . _attrsProxy ) {
// force update if attrs are accessed and has changed since it may be
// passed to a child component.
if ( syncSetupProxy ( vm . _attrsProxy , attrs , ( prevVNode . data && prevVNode . data . attrs ) || emptyObject , vm , '$attrs' ) ) {
needsForceUpdate = true ;
}
}
vm . $attrs = attrs ;
// update listeners
listeners = listeners || emptyObject ;
const prevListeners = vm . $options . _parentListeners ;
if ( vm . _listenersProxy ) {
syncSetupProxy ( vm . _listenersProxy , listeners , prevListeners || emptyObject , vm , '$listeners' ) ;
}
vm . $listeners = vm . $options . _parentListeners = listeners ;
updateComponentListeners ( vm , listeners , prevListeners ) ;
// update props
if ( propsData && vm . $options . props ) {
toggleObserving ( false ) ;
const props = vm . _props ;
const propKeys = vm . $options . _propKeys || [ ] ;
for ( let i = 0 ; i < propKeys . length ; i ++ ) {
const key = propKeys [ i ] ;
const propOptions = vm . $options . props ; // wtf flow?
props [ key ] = validateProp ( key , propOptions , propsData , vm ) ;
}
toggleObserving ( true ) ;
// keep a copy of raw propsData
vm . $options . propsData = propsData ;
}
// resolve slots + force update if has children
if ( needsForceUpdate ) {
vm . $slots = resolveSlots ( renderChildren , parentVnode . context ) ;
vm . $forceUpdate ( ) ;
}
{
isUpdatingChildComponent = false ;
}
}
function isInInactiveTree ( vm ) {
while ( vm && ( vm = vm . $parent ) ) {
if ( vm . _inactive )
return true ;
}
return false ;
}
function activateChildComponent ( vm , direct ) {
if ( direct ) {
vm . _directInactive = false ;
if ( isInInactiveTree ( vm ) ) {
return ;
}
}
else if ( vm . _directInactive ) {
return ;
}
if ( vm . _inactive || vm . _inactive === null ) {
vm . _inactive = false ;
for ( let i = 0 ; i < vm . $children . length ; i ++ ) {
activateChildComponent ( vm . $children [ i ] ) ;
}
callHook$1 ( vm , 'activated' ) ;
}
}
function deactivateChildComponent ( vm , direct ) {
if ( direct ) {
vm . _directInactive = true ;
if ( isInInactiveTree ( vm ) ) {
return ;
}
}
if ( ! vm . _inactive ) {
vm . _inactive = true ;
for ( let i = 0 ; i < vm . $children . length ; i ++ ) {
deactivateChildComponent ( vm . $children [ i ] ) ;
}
callHook$1 ( vm , 'deactivated' ) ;
}
}
function callHook$1 ( vm , hook , args , setContext = true ) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget ( ) ;
const prevInst = currentInstance ;
const prevScope = getCurrentScope ( ) ;
setContext && setCurrentInstance ( vm ) ;
const handlers = vm . $options [ hook ] ;
const info = ` ${ hook } hook ` ;
if ( handlers ) {
for ( let i = 0 , j = handlers . length ; i < j ; i ++ ) {
invokeWithErrorHandling ( handlers [ i ] , vm , args || null , vm , info ) ;
}
}
if ( vm . _hasHookEvent ) {
vm . $emit ( 'hook:' + hook ) ;
}
if ( setContext ) {
setCurrentInstance ( prevInst ) ;
prevScope && prevScope . on ( ) ;
}
popTarget ( ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
const MAX _UPDATE _COUNT = 100 ;
const queue = [ ] ;
const activatedChildren = [ ] ;
let has = { } ;
let circular = { } ;
let waiting = false ;
let flushing = false ;
let index = 0 ;
/ * *
* Reset the scheduler ' s state .
* /
function resetSchedulerState ( ) {
index = queue . length = activatedChildren . length = 0 ;
has = { } ;
{
circular = { } ;
}
waiting = flushing = false ;
}
// Async edge case #6566 requires saving the timestamp when event listeners are
// attached. However, calling performance.now() has a perf overhead especially
// if the page has thousands of event listeners. Instead, we take a timestamp
// every time the scheduler flushes and use that for all event listeners
// attached during that flush.
let currentFlushTimestamp = 0 ;
// Async edge case fix requires storing an event listener's attach timestamp.
let getNow = Date . now ;
// Determine what event timestamp the browser is using. Annoyingly, the
// timestamp can either be hi-res (relative to page load) or low-res
// (relative to UNIX epoch), so in order to compare time we have to use the
// same timestamp type when saving the flush timestamp.
// All IE versions use low-res event timestamps, and have problematic clock
// implementations (#9632)
if ( inBrowser && ! isIE ) {
const performance = window . performance ;
if ( performance &&
typeof performance . now === 'function' &&
getNow ( ) > document . createEvent ( 'Event' ) . timeStamp ) {
// if the event timestamp, although evaluated AFTER the Date.now(), is
// smaller than it, it means the event is using a hi-res timestamp,
// and we need to use the hi-res version for event listener timestamps as
// well.
getNow = ( ) => performance . now ( ) ;
}
}
const sortCompareFn = ( a , b ) => {
if ( a . post ) {
if ( ! b . post )
return 1 ;
}
else if ( b . post ) {
return - 1 ;
}
return a . id - b . id ;
} ;
/ * *
* Flush both queues and run the watchers .
* /
function flushSchedulerQueue ( ) {
currentFlushTimestamp = getNow ( ) ;
flushing = true ;
let watcher , id ;
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue . sort ( sortCompareFn ) ;
// do not cache length because more watchers might be pushed
// as we run existing watchers
for ( index = 0 ; index < queue . length ; index ++ ) {
watcher = queue [ index ] ;
if ( watcher . before ) {
watcher . before ( ) ;
}
id = watcher . id ;
has [ id ] = null ;
watcher . run ( ) ;
// in dev build, check and stop circular updates.
if ( has [ id ] != null ) {
circular [ id ] = ( circular [ id ] || 0 ) + 1 ;
if ( circular [ id ] > MAX _UPDATE _COUNT ) {
warn ( 'You may have an infinite update loop ' +
( watcher . user
? ` in watcher with expression " ${ watcher . expression } " `
: ` in a component render function. ` ) , watcher . vm ) ;
break ;
}
}
}
// keep copies of post queues before resetting state
const activatedQueue = activatedChildren . slice ( ) ;
const updatedQueue = queue . slice ( ) ;
resetSchedulerState ( ) ;
// call component updated and activated hooks
callActivatedHooks ( activatedQueue ) ;
callUpdatedHooks ( updatedQueue ) ;
cleanupDeps ( ) ;
// devtool hook
/* istanbul ignore if */
if ( devtools && config . devtools ) {
devtools . emit ( 'flush' ) ;
}
}
function callUpdatedHooks ( queue ) {
let i = queue . length ;
while ( i -- ) {
const watcher = queue [ i ] ;
const vm = watcher . vm ;
if ( vm && vm . _watcher === watcher && vm . _isMounted && ! vm . _isDestroyed ) {
callHook$1 ( vm , 'updated' ) ;
}
}
}
/ * *
* Queue a kept - alive component that was activated during patch .
* The queue will be processed after the entire tree has been patched .
* /
function queueActivatedComponent ( vm ) {
// setting _inactive to false here so that a render function can
// rely on checking whether it's in an inactive tree (e.g. router-view)
vm . _inactive = false ;
activatedChildren . push ( vm ) ;
}
function callActivatedHooks ( queue ) {
for ( let i = 0 ; i < queue . length ; i ++ ) {
queue [ i ] . _inactive = true ;
activateChildComponent ( queue [ i ] , true /* true */ ) ;
}
}
/ * *
* Push a watcher into the watcher queue .
* Jobs with duplicate IDs will be skipped unless it ' s
* pushed when the queue is being flushed .
* /
function queueWatcher ( watcher ) {
const id = watcher . id ;
if ( has [ id ] != null ) {
return ;
}
if ( watcher === Dep . target && watcher . noRecurse ) {
return ;
}
has [ id ] = true ;
if ( ! flushing ) {
queue . push ( watcher ) ;
}
else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue . length - 1 ;
while ( i > index && queue [ i ] . id > watcher . id ) {
i -- ;
}
queue . splice ( i + 1 , 0 , watcher ) ;
}
// queue the flush
if ( ! waiting ) {
waiting = true ;
if ( ! config . async ) {
flushSchedulerQueue ( ) ;
return ;
}
nextTick ( flushSchedulerQueue ) ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function initProvide ( vm ) {
const provideOption = vm . $options . provide ;
if ( provideOption ) {
const provided = isFunction ( provideOption )
? provideOption . call ( vm )
: provideOption ;
if ( ! isObject ( provided ) ) {
return ;
}
const source = resolveProvided ( vm ) ;
// IE9 doesn't support Object.getOwnPropertyDescriptors so we have to
// iterate the keys ourselves.
const keys = hasSymbol ? Reflect . ownKeys ( provided ) : Object . keys ( provided ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const key = keys [ i ] ;
Object . defineProperty ( source , key , Object . getOwnPropertyDescriptor ( provided , key ) ) ;
}
}
}
function initInjections ( vm ) {
const result = resolveInject ( vm . $options . inject , vm ) ;
if ( result ) {
toggleObserving ( false ) ;
Object . keys ( result ) . forEach ( key => {
/* istanbul ignore else */
{
defineReactive ( vm , key , result [ key ] , ( ) => {
warn ( ` Avoid mutating an injected value directly since the changes will be ` +
` overwritten whenever the provided component re-renders. ` +
` injection being mutated: " ${ key } " ` , vm ) ;
} ) ;
}
} ) ;
toggleObserving ( true ) ;
}
}
function resolveInject ( inject , vm ) {
if ( inject ) {
// inject is :any because flow is not smart enough to figure out cached
const result = Object . create ( null ) ;
const keys = hasSymbol ? Reflect . ownKeys ( inject ) : Object . keys ( inject ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const key = keys [ i ] ;
// #6574 in case the inject object is observed...
if ( key === '__ob__' )
continue ;
const provideKey = inject [ key ] . from ;
if ( provideKey in vm . _provided ) {
result [ key ] = vm . _provided [ provideKey ] ;
}
else if ( 'default' in inject [ key ] ) {
const provideDefault = inject [ key ] . default ;
result [ key ] = isFunction ( provideDefault )
? provideDefault . call ( vm )
: provideDefault ;
}
else {
warn ( ` Injection " ${ key } " not found ` , vm ) ;
}
}
return result ;
}
}
function FunctionalRenderContext ( data , props , children , parent , Ctor ) {
const options = Ctor . options ;
// ensure the createElement function in functional components
// gets a unique context - this is necessary for correct named slot check
let contextVm ;
if ( hasOwn ( parent , '_uid' ) ) {
contextVm = Object . create ( parent ) ;
contextVm . _original = parent ;
}
else {
// the context vm passed in is a functional context as well.
// in this case we want to make sure we are able to get a hold to the
// real context instance.
contextVm = parent ;
// @ts-ignore
parent = parent . _original ;
}
const isCompiled = isTrue ( options . _compiled ) ;
const needNormalization = ! isCompiled ;
this . data = data ;
this . props = props ;
this . children = children ;
this . parent = parent ;
this . listeners = data . on || emptyObject ;
this . injections = resolveInject ( options . inject , parent ) ;
this . slots = ( ) => {
if ( ! this . $slots ) {
normalizeScopedSlots ( parent , data . scopedSlots , ( this . $slots = resolveSlots ( children , parent ) ) ) ;
}
return this . $slots ;
} ;
Object . defineProperty ( this , 'scopedSlots' , {
enumerable : true ,
get ( ) {
return normalizeScopedSlots ( parent , data . scopedSlots , this . slots ( ) ) ;
}
} ) ;
// support for compiled functional template
if ( isCompiled ) {
// exposing $options for renderStatic()
this . $options = options ;
// pre-resolve slots for renderSlot()
this . $slots = this . slots ( ) ;
this . $scopedSlots = normalizeScopedSlots ( parent , data . scopedSlots , this . $slots ) ;
}
if ( options . _scopeId ) {
this . _c = ( a , b , c , d ) => {
const vnode = createElement$1 ( contextVm , a , b , c , d , needNormalization ) ;
if ( vnode && ! isArray ( vnode ) ) {
vnode . fnScopeId = options . _scopeId ;
vnode . fnContext = parent ;
}
return vnode ;
} ;
}
else {
this . _c = ( a , b , c , d ) => createElement$1 ( contextVm , a , b , c , d , needNormalization ) ;
}
}
installRenderHelpers ( FunctionalRenderContext . prototype ) ;
function createFunctionalComponent ( Ctor , propsData , data , contextVm , children ) {
const options = Ctor . options ;
const props = { } ;
const propOptions = options . props ;
if ( isDef ( propOptions ) ) {
for ( const key in propOptions ) {
props [ key ] = validateProp ( key , propOptions , propsData || emptyObject ) ;
}
}
else {
if ( isDef ( data . attrs ) )
mergeProps ( props , data . attrs ) ;
if ( isDef ( data . props ) )
mergeProps ( props , data . props ) ;
}
const renderContext = new FunctionalRenderContext ( data , props , children , contextVm , Ctor ) ;
const vnode = options . render . call ( null , renderContext . _c , renderContext ) ;
if ( vnode instanceof VNode ) {
return cloneAndMarkFunctionalResult ( vnode , data , renderContext . parent , options , renderContext ) ;
}
else if ( isArray ( vnode ) ) {
const vnodes = normalizeChildren ( vnode ) || [ ] ;
const res = new Array ( vnodes . length ) ;
for ( let i = 0 ; i < vnodes . length ; i ++ ) {
res [ i ] = cloneAndMarkFunctionalResult ( vnodes [ i ] , data , renderContext . parent , options , renderContext ) ;
}
return res ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function cloneAndMarkFunctionalResult ( vnode , data , contextVm , options , renderContext ) {
// #7817 clone node before setting fnContext, otherwise if the node is reused
// (e.g. it was from a cached normal slot) the fnContext causes named slots
// that should not be matched to match.
const clone = cloneVNode ( vnode ) ;
clone . fnContext = contextVm ;
clone . fnOptions = options ;
{
( clone . devtoolsMeta = clone . devtoolsMeta || { } ) . renderContext =
renderContext ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( data . slot ) {
( clone . data || ( clone . data = { } ) ) . slot = data . slot ;
}
return clone ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function mergeProps ( to , from ) {
for ( const key in from ) {
to [ camelize ( key ) ] = from [ key ] ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getComponentName ( options ) {
return options . name || options . _ _name || options . _componentTag ;
}
// inline hooks to be invoked on component VNodes during patch
const componentVNodeHooks = {
init ( vnode , hydrating ) {
if ( vnode . componentInstance &&
! vnode . componentInstance . _isDestroyed &&
vnode . data . keepAlive ) {
// kept-alive components, treat as a patch
const mountedNode = vnode ; // work around flow
componentVNodeHooks . prepatch ( mountedNode , mountedNode ) ;
}
else {
const child = ( vnode . componentInstance = createComponentInstanceForVnode ( vnode , activeInstance ) ) ;
child . $mount ( hydrating ? vnode . elm : undefined , hydrating ) ;
}
} ,
prepatch ( oldVnode , vnode ) {
const options = vnode . componentOptions ;
const child = ( vnode . componentInstance = oldVnode . componentInstance ) ;
updateChildComponent ( child , options . propsData , // updated props
options . listeners , // updated listeners
vnode , // new parent vnode
options . children // new children
) ;
} ,
insert ( vnode ) {
const { context , componentInstance } = vnode ;
if ( ! componentInstance . _isMounted ) {
componentInstance . _isMounted = true ;
callHook$1 ( componentInstance , 'mounted' ) ;
}
if ( vnode . data . keepAlive ) {
if ( context . _isMounted ) {
// vue-router#1212
// During updates, a kept-alive component's child components may
// change, so directly walking the tree here may call activated hooks
// on incorrect children. Instead we push them into a queue which will
// be processed after the whole patch process ended.
queueActivatedComponent ( componentInstance ) ;
}
else {
activateChildComponent ( componentInstance , true /* direct */ ) ;
}
}
} ,
destroy ( vnode ) {
const { componentInstance } = vnode ;
if ( ! componentInstance . _isDestroyed ) {
if ( ! vnode . data . keepAlive ) {
componentInstance . $destroy ( ) ;
}
else {
deactivateChildComponent ( componentInstance , true /* direct */ ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
} ;
const hooksToMerge = Object . keys ( componentVNodeHooks ) ;
function createComponent ( Ctor , data , context , children , tag ) {
if ( isUndef ( Ctor ) ) {
return ;
}
const baseCtor = context . $options . _base ;
// plain options object: turn it into a constructor
if ( isObject ( Ctor ) ) {
Ctor = baseCtor . extend ( Ctor ) ;
}
// if at this stage it's not a constructor or an async component factory,
// reject.
if ( typeof Ctor !== 'function' ) {
{
warn ( ` Invalid Component definition: ${ String ( Ctor ) } ` , context ) ;
}
return ;
}
// async component
let asyncFactory ;
// @ts-expect-error
if ( isUndef ( Ctor . cid ) ) {
asyncFactory = Ctor ;
Ctor = resolveAsyncComponent ( asyncFactory , baseCtor ) ;
if ( Ctor === undefined ) {
// return a placeholder node for async component, which is rendered
// as a comment node but preserves all the raw information for the node.
// the information will be used for async server-rendering and hydration.
return createAsyncPlaceholder ( asyncFactory , data , context , children , tag ) ;
}
}
data = data || { } ;
// resolve constructor options in case global mixins are applied after
// component constructor creation
resolveConstructorOptions ( Ctor ) ;
// transform component v-model data into props & events
if ( isDef ( data . model ) ) {
// @ts-expect-error
transformModel ( Ctor . options , data ) ;
}
// extract props
// @ts-expect-error
const propsData = extractPropsFromVNodeData ( data , Ctor , tag ) ;
// functional component
// @ts-expect-error
if ( isTrue ( Ctor . options . functional ) ) {
return createFunctionalComponent ( Ctor , propsData , data , context , children ) ;
}
// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data . on ;
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data . on = data . nativeOn ;
// @ts-expect-error
if ( isTrue ( Ctor . options . abstract ) ) {
// abstract components do not keep anything
// other than props & listeners & slot
// work around flow
const slot = data . slot ;
data = { } ;
if ( slot ) {
data . slot = slot ;
}
}
// install component management hooks onto the placeholder node
installComponentHooks ( data ) ;
// return a placeholder vnode
// @ts-expect-error
const name = getComponentName ( Ctor . options ) || tag ;
const vnode = new VNode (
// @ts-expect-error
` vue-component- ${ Ctor . cid } ${ name ? ` - ${ name } ` : '' } ` , data , undefined , undefined , undefined , context ,
// @ts-expect-error
{ Ctor , propsData , listeners , tag , children } , asyncFactory ) ;
return vnode ;
}
function createComponentInstanceForVnode (
// we know it's MountedComponentVNode but flow doesn't
vnode ,
// activeInstance in lifecycle state
parent ) {
const options = {
_isComponent : true ,
_parentVnode : vnode ,
parent
} ;
// check inline-template render functions
const inlineTemplate = vnode . data . inlineTemplate ;
if ( isDef ( inlineTemplate ) ) {
options . render = inlineTemplate . render ;
options . staticRenderFns = inlineTemplate . staticRenderFns ;
}
return new vnode . componentOptions . Ctor ( options ) ;
}
function installComponentHooks ( data ) {
const hooks = data . hook || ( data . hook = { } ) ;
for ( let i = 0 ; i < hooksToMerge . length ; i ++ ) {
const key = hooksToMerge [ i ] ;
const existing = hooks [ key ] ;
const toMerge = componentVNodeHooks [ key ] ;
// @ts-expect-error
if ( existing !== toMerge && ! ( existing && existing . _merged ) ) {
hooks [ key ] = existing ? mergeHook ( toMerge , existing ) : toMerge ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function mergeHook ( f1 , f2 ) {
const merged = ( a , b ) => {
// flow complains about extra args which is why we use any
f1 ( a , b ) ;
f2 ( a , b ) ;
} ;
merged . _merged = true ;
return merged ;
}
// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel ( options , data ) {
const prop = ( options . model && options . model . prop ) || 'value' ;
const event = ( options . model && options . model . event ) || 'input' ;
( data . attrs || ( data . attrs = { } ) ) [ prop ] = data . model . value ;
const on = data . on || ( data . on = { } ) ;
const existing = on [ event ] ;
const callback = data . model . callback ;
if ( isDef ( existing ) ) {
if ( isArray ( existing )
? existing . indexOf ( callback ) === - 1
: existing !== callback ) {
on [ event ] = [ callback ] . concat ( existing ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
on [ event ] = callback ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
let warn = noop ;
let tip = noop ;
let generateComponentTrace ; // work around flow check
let formatComponentName ;
{
const hasConsole = typeof console !== 'undefined' ;
const classifyRE = /(?:^|[-_])(\w)/g ;
const classify = str => str . replace ( classifyRE , c => c . toUpperCase ( ) ) . replace ( /[-_]/g , '' ) ;
warn = ( msg , vm = currentInstance ) => {
const trace = vm ? generateComponentTrace ( vm ) : '' ;
if ( config . warnHandler ) {
config . warnHandler . call ( null , msg , vm , trace ) ;
}
else if ( hasConsole && ! config . silent ) {
console . error ( ` [Vue warn]: ${ msg } ${ trace } ` ) ;
}
} ;
tip = ( msg , vm ) => {
if ( hasConsole && ! config . silent ) {
console . warn ( ` [Vue tip]: ${ msg } ` + ( vm ? generateComponentTrace ( vm ) : '' ) ) ;
}
} ;
formatComponentName = ( vm , includeFile ) => {
if ( vm . $root === vm ) {
return '<Root>' ;
}
const options = isFunction ( vm ) && vm . cid != null
? vm . options
: vm . _isVue
? vm . $options || vm . constructor . options
: vm ;
let name = getComponentName ( options ) ;
const file = options . _ _file ;
if ( ! name && file ) {
const match = file . match ( /([^/\\]+)\.vue$/ ) ;
name = match && match [ 1 ] ;
}
return ( ( name ? ` < ${ classify ( name ) } > ` : ` <Anonymous> ` ) +
( file && includeFile !== false ? ` at ${ file } ` : '' ) ) ;
} ;
const repeat = ( str , n ) => {
let res = '' ;
while ( n ) {
if ( n % 2 === 1 )
res += str ;
if ( n > 1 )
str += str ;
n >>= 1 ;
}
return res ;
} ;
generateComponentTrace = ( vm ) => {
if ( vm . _isVue && vm . $parent ) {
const tree = [ ] ;
let currentRecursiveSequence = 0 ;
while ( vm ) {
if ( tree . length > 0 ) {
const last = tree [ tree . length - 1 ] ;
if ( last . constructor === vm . constructor ) {
currentRecursiveSequence ++ ;
vm = vm . $parent ;
continue ;
}
else if ( currentRecursiveSequence > 0 ) {
tree [ tree . length - 1 ] = [ last , currentRecursiveSequence ] ;
currentRecursiveSequence = 0 ;
}
}
tree . push ( vm ) ;
vm = vm . $parent ;
}
return ( '\n\nfound in\n\n' +
tree
. map ( ( vm , i ) => ` ${ i === 0 ? '---> ' : repeat ( ' ' , 5 + i * 2 ) } ${ isArray ( vm )
? ` ${ formatComponentName ( vm [ 0 ] ) } ... ( ${ vm [ 1 ] } recursive calls) `
: formatComponentName ( vm ) } ` )
. join ( '\n' ) ) ;
}
else {
return ` \n \n (found in ${ formatComponentName ( vm ) } ) ` ;
}
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Option overwriting strategies are functions that handle
* how to merge a parent option value and a child option
* value into the final value .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
const strats = config . optionMergeStrategies ;
/ * *
* Options with restrictions
* /
{
strats . el = strats . propsData = function ( parent , child , vm , key ) {
if ( ! vm ) {
warn ( ` option " ${ key } " can only be used during instance ` +
'creation with the `new` keyword.' ) ;
}
return defaultStrat ( parent , child ) ;
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Helper that recursively merges two data objects together .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function mergeData ( to , from , recursive = true ) {
if ( ! from )
return to ;
let key , toVal , fromVal ;
const keys = hasSymbol
? Reflect . ownKeys ( from )
: Object . keys ( from ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
key = keys [ i ] ;
// in case the object is already observed...
if ( key === '__ob__' )
continue ;
toVal = to [ key ] ;
fromVal = from [ key ] ;
if ( ! recursive || ! hasOwn ( to , key ) ) {
set ( to , key , fromVal ) ;
}
else if ( toVal !== fromVal &&
isPlainObject ( toVal ) &&
isPlainObject ( fromVal ) ) {
mergeData ( toVal , fromVal ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return to ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* Data
* /
function mergeDataOrFn ( parentVal , childVal , vm ) {
if ( ! vm ) {
// in a Vue.extend merge, both should be functions
if ( ! childVal ) {
return parentVal ;
}
if ( ! parentVal ) {
return childVal ;
}
// when parentVal & childVal are both present,
// we need to return a function that returns the
// merged result of both functions... no need to
// check if parentVal is a function here because
// it has to be a function to pass previous merges.
return function mergedDataFn ( ) {
return mergeData ( isFunction ( childVal ) ? childVal . call ( this , this ) : childVal , isFunction ( parentVal ) ? parentVal . call ( this , this ) : parentVal ) ;
} ;
}
else {
return function mergedInstanceDataFn ( ) {
// instance merge
const instanceData = isFunction ( childVal )
? childVal . call ( vm , vm )
: childVal ;
const defaultData = isFunction ( parentVal )
? parentVal . call ( vm , vm )
: parentVal ;
if ( instanceData ) {
return mergeData ( instanceData , defaultData ) ;
}
else {
return defaultData ;
}
} ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
strats . data = function ( parentVal , childVal , vm ) {
if ( ! vm ) {
if ( childVal && typeof childVal !== 'function' ) {
warn ( 'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.' , vm ) ;
return parentVal ;
}
return mergeDataOrFn ( parentVal , childVal ) ;
}
return mergeDataOrFn ( parentVal , childVal , vm ) ;
} ;
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Hooks and props are merged as arrays .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function mergeLifecycleHook ( parentVal , childVal ) {
const res = childVal
? parentVal
? parentVal . concat ( childVal )
: isArray ( childVal )
? childVal
: [ childVal ]
: parentVal ;
return res ? dedupeHooks ( res ) : res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function dedupeHooks ( hooks ) {
const res = [ ] ;
for ( let i = 0 ; i < hooks . length ; i ++ ) {
if ( res . indexOf ( hooks [ i ] ) === - 1 ) {
res . push ( hooks [ i ] ) ;
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
LIFECYCLE _HOOKS . forEach ( hook => {
strats [ hook ] = mergeLifecycleHook ;
} ) ;
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Assets
*
* When a vm is present ( instance creation ) , we need to do
* a three - way merge between constructor options , instance
* options and parent options .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function mergeAssets ( parentVal , childVal , vm , key ) {
const res = Object . create ( parentVal || null ) ;
if ( childVal ) {
assertObjectType ( key , childVal , vm ) ;
return extend ( res , childVal ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
return res ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
ASSET _TYPES . forEach ( function ( type ) {
strats [ type + 's' ] = mergeAssets ;
} ) ;
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Watchers .
*
* Watchers hashes should not overwrite one
* another , so we merge them as arrays .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
strats . watch = function ( parentVal , childVal , vm , key ) {
// work around Firefox's Object.prototype.watch...
//@ts-expect-error work around
if ( parentVal === nativeWatch )
parentVal = undefined ;
//@ts-expect-error work around
if ( childVal === nativeWatch )
childVal = undefined ;
/* istanbul ignore if */
if ( ! childVal )
return Object . create ( parentVal || null ) ;
{
assertObjectType ( key , childVal , vm ) ;
}
if ( ! parentVal )
return childVal ;
const ret = { } ;
extend ( ret , parentVal ) ;
for ( const key in childVal ) {
let parent = ret [ key ] ;
const child = childVal [ key ] ;
if ( parent && ! isArray ( parent ) ) {
parent = [ parent ] ;
}
ret [ key ] = parent ? parent . concat ( child ) : isArray ( child ) ? child : [ child ] ;
}
return ret ;
2023-12-18 13:12:25 +08:00
} ;
/ * *
2024-01-16 21:26:16 +08:00
* Other object hashes .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
strats . props =
strats . methods =
strats . inject =
strats . computed =
function ( parentVal , childVal , vm , key ) {
if ( childVal && true ) {
assertObjectType ( key , childVal , vm ) ;
}
if ( ! parentVal )
return childVal ;
const ret = Object . create ( null ) ;
extend ( ret , parentVal ) ;
if ( childVal )
extend ( ret , childVal ) ;
return ret ;
} ;
strats . provide = function ( parentVal , childVal ) {
if ( ! parentVal )
return childVal ;
return function ( ) {
const ret = Object . create ( null ) ;
mergeData ( ret , isFunction ( parentVal ) ? parentVal . call ( this ) : parentVal ) ;
if ( childVal ) {
mergeData ( ret , isFunction ( childVal ) ? childVal . call ( this ) : childVal , false // non-recursive
) ;
}
return ret ;
} ;
2023-12-18 13:12:25 +08:00
} ;
/ * *
2024-01-16 21:26:16 +08:00
* Default strategy .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
const defaultStrat = function ( parentVal , childVal ) {
return childVal === undefined ? parentVal : childVal ;
2023-12-18 13:12:25 +08:00
} ;
/ * *
2024-01-16 21:26:16 +08:00
* Validate component names
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function checkComponents ( options ) {
for ( const key in options . components ) {
validateComponentName ( key ) ;
}
}
function validateComponentName ( name ) {
if ( ! new RegExp ( ` ^[a-zA-Z][ \\ - \\ .0-9_ ${ unicodeRegExp . source } ]* $ ` ) . test ( name ) ) {
warn ( 'Invalid component name: "' +
name +
'". Component names ' +
'should conform to valid custom element name in html5 specification.' ) ;
}
if ( isBuiltInTag ( name ) || config . isReservedTag ( name ) ) {
warn ( 'Do not use built-in or reserved HTML elements as component ' +
'id: ' +
name ) ;
}
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Ensure all props option syntax are normalized into the
* Object - based format .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function normalizeProps ( options , vm ) {
const props = options . props ;
if ( ! props )
return ;
const res = { } ;
let i , val , name ;
if ( isArray ( props ) ) {
i = props . length ;
while ( i -- ) {
val = props [ i ] ;
if ( typeof val === 'string' ) {
name = camelize ( val ) ;
res [ name ] = { type : null } ;
}
else {
warn ( 'props must be strings when using array syntax.' ) ;
}
}
}
else if ( isPlainObject ( props ) ) {
for ( const key in props ) {
val = props [ key ] ;
name = camelize ( key ) ;
res [ name ] = isPlainObject ( val ) ? val : { type : val } ;
}
}
else {
warn ( ` Invalid value for option "props": expected an Array or an Object, ` +
` but got ${ toRawType ( props ) } . ` , vm ) ;
}
options . props = res ;
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Normalize all injections into Object - based format
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function normalizeInject ( options , vm ) {
const inject = options . inject ;
if ( ! inject )
return ;
const normalized = ( options . inject = { } ) ;
if ( isArray ( inject ) ) {
for ( let i = 0 ; i < inject . length ; i ++ ) {
normalized [ inject [ i ] ] = { from : inject [ i ] } ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
else if ( isPlainObject ( inject ) ) {
for ( const key in inject ) {
const val = inject [ key ] ;
normalized [ key ] = isPlainObject ( val )
? extend ( { from : key } , val )
: { from : val } ;
}
}
else {
warn ( ` Invalid value for option "inject": expected an Array or an Object, ` +
` but got ${ toRawType ( inject ) } . ` , vm ) ;
}
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Normalize raw function directives into object format .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function normalizeDirectives$1 ( options ) {
const dirs = options . directives ;
if ( dirs ) {
for ( const key in dirs ) {
const def = dirs [ key ] ;
if ( isFunction ( def ) ) {
dirs [ key ] = { bind : def , update : def } ;
}
}
}
}
function assertObjectType ( name , value , vm ) {
if ( ! isPlainObject ( value ) ) {
warn ( ` Invalid value for option " ${ name } ": expected an Object, ` +
` but got ${ toRawType ( value ) } . ` , vm ) ;
}
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Merge two option objects into a new one .
* Core utility used in both instantiation and inheritance .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function mergeOptions ( parent , child , vm ) {
{
checkComponents ( child ) ;
}
if ( isFunction ( child ) ) {
// @ts-expect-error
child = child . options ;
}
normalizeProps ( child , vm ) ;
normalizeInject ( child , vm ) ;
normalizeDirectives$1 ( child ) ;
// Apply extends and mixins on the child options,
// but only if it is a raw options object that isn't
// the result of another mergeOptions call.
// Only merged options has the _base property.
if ( ! child . _base ) {
if ( child . extends ) {
parent = mergeOptions ( parent , child . extends , vm ) ;
}
if ( child . mixins ) {
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 ) ;
}
for ( key in child ) {
if ( ! hasOwn ( parent , key ) ) {
mergeField ( key ) ;
}
}
function mergeField ( key ) {
const strat = strats [ key ] || defaultStrat ;
options [ key ] = strat ( parent [ key ] , child [ key ] , vm , key ) ;
}
return options ;
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Resolve an asset .
* This function is used because child instances need access
* to assets defined in its ancestor chain .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function resolveAsset ( options , type , id , warnMissing ) {
/* istanbul ignore if */
if ( typeof id !== 'string' ) {
return ;
}
const assets = options [ type ] ;
// check local registration variations first
if ( hasOwn ( assets , id ) )
return assets [ id ] ;
const camelizedId = camelize ( id ) ;
if ( hasOwn ( assets , camelizedId ) )
return assets [ camelizedId ] ;
const PascalCaseId = capitalize ( camelizedId ) ;
if ( hasOwn ( assets , PascalCaseId ) )
return assets [ PascalCaseId ] ;
// fallback to prototype chain
const res = assets [ id ] || assets [ camelizedId ] || assets [ PascalCaseId ] ;
if ( warnMissing && ! res ) {
warn ( 'Failed to resolve ' + type . slice ( 0 , - 1 ) + ': ' + id ) ;
}
return res ;
}
function validateProp ( key , propOptions , propsData , vm ) {
const prop = propOptions [ key ] ;
const absent = ! hasOwn ( propsData , key ) ;
let value = propsData [ key ] ;
// boolean casting
const booleanIndex = getTypeIndex ( Boolean , prop . type ) ;
if ( booleanIndex > - 1 ) {
if ( absent && ! hasOwn ( prop , 'default' ) ) {
value = false ;
}
else if ( value === '' || value === hyphenate ( key ) ) {
// only cast empty string / same name to boolean if
// boolean has higher priority
const stringIndex = getTypeIndex ( String , prop . type ) ;
if ( stringIndex < 0 || booleanIndex < stringIndex ) {
value = true ;
}
}
}
// check default value
if ( value === undefined ) {
value = getPropDefaultValue ( vm , prop , key ) ;
// since the default value is a fresh copy,
// make sure to observe it.
const prevShouldObserve = shouldObserve ;
toggleObserving ( true ) ;
observe ( value ) ;
toggleObserving ( prevShouldObserve ) ;
}
{
assertProp ( prop , key , value , vm , absent ) ;
}
return value ;
}
/ * *
* Get the default value of a prop .
* /
function getPropDefaultValue ( vm , prop , key ) {
// no default, return undefined
if ( ! hasOwn ( prop , 'default' ) ) {
return undefined ;
}
const def = prop . default ;
// warn against non-factory defaults for Object & Array
if ( isObject ( def ) ) {
warn ( 'Invalid default value for prop "' +
key +
'": ' +
'Props with type Object/Array must use a factory function ' +
'to return the default value.' , vm ) ;
}
// the raw prop value was also undefined from previous render,
// return previous default value to avoid unnecessary watcher trigger
if ( vm &&
vm . $options . propsData &&
vm . $options . propsData [ key ] === undefined &&
vm . _props [ key ] !== undefined ) {
return vm . _props [ key ] ;
}
// call factory function for non-Function types
// a value is Function if its prototype is function even across different execution context
return isFunction ( def ) && getType ( prop . type ) !== 'Function'
? def . call ( vm )
: def ;
}
/ * *
* Assert whether a prop is valid .
* /
function assertProp ( prop , name , value , vm , absent ) {
if ( prop . required && absent ) {
warn ( 'Missing required prop: "' + name + '"' , vm ) ;
return ;
}
if ( value == null && ! prop . required ) {
return ;
}
let type = prop . type ;
let valid = ! type || type === true ;
const expectedTypes = [ ] ;
if ( type ) {
if ( ! isArray ( type ) ) {
type = [ type ] ;
}
for ( let i = 0 ; i < type . length && ! valid ; i ++ ) {
const assertedType = assertType ( value , type [ i ] , vm ) ;
expectedTypes . push ( assertedType . expectedType || '' ) ;
valid = assertedType . valid ;
}
}
const haveExpectedTypes = expectedTypes . some ( t => t ) ;
if ( ! valid && haveExpectedTypes ) {
warn ( getInvalidTypeMessage ( name , value , expectedTypes ) , vm ) ;
return ;
}
const validator = prop . validator ;
if ( validator ) {
if ( ! validator ( value ) ) {
warn ( 'Invalid prop: custom validator check failed for prop "' + name + '".' , vm ) ;
}
}
}
const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol|BigInt)$/ ;
function assertType ( value , type , vm ) {
let valid ;
const expectedType = getType ( type ) ;
if ( simpleCheckRE . test ( expectedType ) ) {
const t = typeof value ;
valid = t === expectedType . toLowerCase ( ) ;
// for primitive wrapper objects
if ( ! valid && t === 'object' ) {
valid = value instanceof type ;
}
}
else if ( expectedType === 'Object' ) {
valid = isPlainObject ( value ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( expectedType === 'Array' ) {
valid = isArray ( value ) ;
}
else {
try {
valid = value instanceof type ;
}
catch ( e ) {
warn ( 'Invalid prop type: "' + String ( type ) + '" is not a constructor' , vm ) ;
valid = false ;
}
}
return {
valid ,
expectedType
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const functionTypeCheckRE = /^\s*function (\w+)/ ;
/ * *
* Use function string name to check built - in types ,
* because a simple equality check will fail when running
* across different vms / iframes .
* /
function getType ( fn ) {
const match = fn && fn . toString ( ) . match ( functionTypeCheckRE ) ;
return match ? match [ 1 ] : '' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isSameType ( a , b ) {
return getType ( a ) === getType ( b ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getTypeIndex ( type , expectedTypes ) {
if ( ! isArray ( expectedTypes ) ) {
return isSameType ( expectedTypes , type ) ? 0 : - 1 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
for ( let i = 0 , len = expectedTypes . length ; i < len ; i ++ ) {
if ( isSameType ( expectedTypes [ i ] , type ) ) {
return i ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return - 1 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getInvalidTypeMessage ( name , value , expectedTypes ) {
let message = ` Invalid prop: type check failed for prop " ${ name } ". ` +
` Expected ${ expectedTypes . map ( capitalize ) . join ( ', ' ) } ` ;
const expectedType = expectedTypes [ 0 ] ;
const receivedType = toRawType ( value ) ;
// check if we need to specify expected value
if ( expectedTypes . length === 1 &&
isExplicable ( expectedType ) &&
isExplicable ( typeof value ) &&
! isBoolean ( expectedType , receivedType ) ) {
message += ` with value ${ styleValue ( value , expectedType ) } ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
message += ` , got ${ receivedType } ` ;
// check if we need to specify received value
if ( isExplicable ( receivedType ) ) {
message += ` with value ${ styleValue ( value , receivedType ) } . ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return message ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function styleValue ( value , type ) {
if ( type === 'String' ) {
return ` " ${ value } " ` ;
}
else if ( type === 'Number' ) {
return ` ${ Number ( value ) } ` ;
}
else {
return ` ${ value } ` ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const EXPLICABLE _TYPES = [ 'string' , 'number' , 'boolean' ] ;
function isExplicable ( value ) {
return EXPLICABLE _TYPES . some ( elem => value . toLowerCase ( ) === elem ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isBoolean ( ... args ) {
return args . some ( elem => elem . toLowerCase ( ) === 'boolean' ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/* not type checking this file because flow doesn't play well with Proxy */
let initProxy ;
{
const allowedGlobals = makeMap ( 'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' +
'require' // for Webpack/Browserify
) ;
const warnNonPresent = ( target , key ) => {
warn ( ` Property or method " ${ key } " is not defined on the instance but ` +
'referenced during render. Make sure that this property is reactive, ' +
'either in the data option, or for class-based components, by ' +
'initializing the property. ' +
'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.' , target ) ;
} ;
const warnReservedPrefix = ( target , key ) => {
warn ( ` Property " ${ key } " must be accessed with " $ data. ${ key } " because ` +
'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
'prevent conflicts with Vue internals. ' +
'See: https://v2.vuejs.org/v2/api/#data' , target ) ;
} ;
const hasProxy = typeof Proxy !== 'undefined' && isNative ( Proxy ) ;
if ( hasProxy ) {
const isBuiltInModifier = makeMap ( 'stop,prevent,self,ctrl,shift,alt,meta,exact' ) ;
config . keyCodes = new Proxy ( config . keyCodes , {
set ( target , key , value ) {
if ( isBuiltInModifier ( key ) ) {
warn ( ` Avoid overwriting built-in modifier in config.keyCodes: . ${ key } ` ) ;
return false ;
}
else {
target [ key ] = value ;
return true ;
}
}
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
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 ;
}
} ;
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 ] ;
}
} ;
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 ;
}
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const sharedPropertyDefinition = {
enumerable : true ,
configurable : true ,
get : noop ,
set : noop
} ;
function proxy ( target , sourceKey , key ) {
sharedPropertyDefinition . get = function proxyGetter ( ) {
return this [ sourceKey ] [ key ] ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
sharedPropertyDefinition . set = function proxySetter ( val ) {
this [ sourceKey ] [ key ] = val ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
Object . defineProperty ( target , key , sharedPropertyDefinition ) ;
}
function initState ( vm ) {
const opts = vm . $options ;
if ( opts . props )
initProps$1 ( vm , opts . props ) ;
// Composition API
initSetup ( vm ) ;
if ( opts . methods )
initMethods ( vm , opts . methods ) ;
if ( opts . data ) {
initData ( vm ) ;
}
else {
const ob = observe ( ( vm . _data = { } ) ) ;
ob && ob . vmCount ++ ;
}
if ( opts . computed )
initComputed$1 ( vm , opts . computed ) ;
if ( opts . watch && opts . watch !== nativeWatch ) {
initWatch ( vm , opts . watch ) ;
}
}
function initProps$1 ( vm , propsOptions ) {
const propsData = vm . $options . propsData || { } ;
const props = ( vm . _props = shallowReactive ( { } ) ) ;
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = ( vm . $options . _propKeys = [ ] ) ;
const isRoot = ! vm . $parent ;
// root instance props should be converted
if ( ! isRoot ) {
toggleObserving ( false ) ;
}
for ( const key in propsOptions ) {
keys . push ( key ) ;
const value = validateProp ( key , propsOptions , propsData , vm ) ;
/* istanbul ignore else */
{
const hyphenatedKey = hyphenate ( key ) ;
if ( isReservedAttribute ( hyphenatedKey ) ||
config . isReservedAttr ( hyphenatedKey ) ) {
warn ( ` " ${ hyphenatedKey } " is a reserved attribute and cannot be used as component prop. ` , vm ) ;
}
defineReactive ( props , key , value , ( ) => {
if ( ! isRoot && ! isUpdatingChildComponent ) {
warn ( ` Avoid mutating a prop directly since the value will be ` +
` overwritten whenever the parent component re-renders. ` +
` Instead, use a data or computed property based on the prop's ` +
` value. Prop being mutated: " ${ key } " ` , vm ) ;
}
} , true /* shallow */ ) ;
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if ( ! ( key in vm ) ) {
proxy ( vm , ` _props ` , key ) ;
}
}
toggleObserving ( true ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initData ( vm ) {
let data = vm . $options . data ;
data = vm . _data = isFunction ( data ) ? getData ( data , vm ) : data || { } ;
if ( ! isPlainObject ( data ) ) {
data = { } ;
warn ( 'data functions should return an object:\n' +
'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function' , vm ) ;
}
// proxy data on instance
const keys = Object . keys ( data ) ;
const props = vm . $options . props ;
const methods = vm . $options . methods ;
let i = keys . length ;
while ( i -- ) {
const key = keys [ i ] ;
{
if ( methods && hasOwn ( methods , key ) ) {
warn ( ` Method " ${ key } " has already been defined as a data property. ` , vm ) ;
}
}
if ( props && hasOwn ( props , key ) ) {
warn ( ` The data property " ${ key } " is already declared as a prop. ` +
` Use prop default value instead. ` , vm ) ;
}
else if ( ! isReserved ( key ) ) {
proxy ( vm , ` _data ` , key ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// observe data
const ob = observe ( data ) ;
ob && ob . vmCount ++ ;
}
function getData ( data , vm ) {
// #7573 disable dep collection when invoking data getters
pushTarget ( ) ;
try {
return data . call ( vm , vm ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
catch ( e ) {
handleError ( e , vm , ` data() ` ) ;
return { } ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
finally {
popTarget ( ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
const computedWatcherOptions = { lazy : true } ;
function initComputed$1 ( vm , computed ) {
// $flow-disable-line
const watchers = ( vm . _computedWatchers = Object . create ( null ) ) ;
// computed properties are just getters during SSR
const isSSR = isServerRendering ( ) ;
for ( const key in computed ) {
const userDef = computed [ key ] ;
const getter = isFunction ( userDef ) ? userDef : userDef . get ;
if ( getter == null ) {
warn ( ` Getter is missing for computed property " ${ key } ". ` , vm ) ;
}
if ( ! isSSR ) {
// create internal watcher for the computed property.
watchers [ key ] = new Watcher ( vm , getter || noop , noop , computedWatcherOptions ) ;
}
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if ( ! ( key in vm ) ) {
defineComputed ( vm , key , userDef ) ;
}
else {
if ( key in vm . $data ) {
warn ( ` The computed property " ${ key } " is already defined in data. ` , vm ) ;
}
else if ( vm . $options . props && key in vm . $options . props ) {
warn ( ` The computed property " ${ key } " is already defined as a prop. ` , vm ) ;
}
else if ( vm . $options . methods && key in vm . $options . methods ) {
warn ( ` The computed property " ${ key } " is already defined as a method. ` , vm ) ;
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function defineComputed ( target , key , userDef ) {
const shouldCache = ! isServerRendering ( ) ;
if ( isFunction ( userDef ) ) {
sharedPropertyDefinition . get = shouldCache
? createComputedGetter ( key )
: createGetterInvoker ( userDef ) ;
sharedPropertyDefinition . set = noop ;
}
else {
sharedPropertyDefinition . get = userDef . get
? shouldCache && userDef . cache !== false
? createComputedGetter ( key )
: createGetterInvoker ( userDef . get )
: noop ;
sharedPropertyDefinition . set = userDef . set || noop ;
}
if ( sharedPropertyDefinition . set === noop ) {
sharedPropertyDefinition . set = function ( ) {
warn ( ` Computed property " ${ key } " was assigned to but it has no setter. ` , this ) ;
} ;
}
Object . defineProperty ( target , key , sharedPropertyDefinition ) ;
}
function createComputedGetter ( key ) {
return function computedGetter ( ) {
const watcher = this . _computedWatchers && this . _computedWatchers [ key ] ;
if ( watcher ) {
if ( watcher . dirty ) {
watcher . evaluate ( ) ;
}
if ( Dep . target ) {
if ( Dep . target . onTrack ) {
Dep . target . onTrack ( {
effect : Dep . target ,
target : this ,
type : "get" /* TrackOpTypes.GET */ ,
key
} ) ;
}
watcher . depend ( ) ;
}
return watcher . value ;
}
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createGetterInvoker ( fn ) {
return function computedGetter ( ) {
return fn . call ( this , this ) ;
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initMethods ( vm , methods ) {
const props = vm . $options . props ;
for ( const key in methods ) {
{
if ( typeof methods [ key ] !== 'function' ) {
warn ( ` Method " ${ key } " has type " ${ typeof methods [ key ] } " in the component definition. ` +
` Did you reference the function correctly? ` , vm ) ;
}
if ( props && hasOwn ( props , key ) ) {
warn ( ` Method " ${ key } " has already been defined as a prop. ` , vm ) ;
}
if ( key in vm && isReserved ( key ) ) {
warn ( ` Method " ${ key } " conflicts with an existing Vue instance method. ` +
` Avoid defining component methods that start with _ or $ . ` ) ;
}
}
vm [ key ] = typeof methods [ key ] !== 'function' ? noop : bind ( methods [ key ] , vm ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function initWatch ( vm , watch ) {
for ( const key in watch ) {
const handler = watch [ key ] ;
if ( isArray ( handler ) ) {
for ( let i = 0 ; i < handler . length ; i ++ ) {
createWatcher ( vm , key , handler [ i ] ) ;
}
}
else {
createWatcher ( vm , key , handler ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createWatcher ( vm , expOrFn , handler , options ) {
if ( isPlainObject ( handler ) ) {
options = handler ;
handler = handler . handler ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( typeof handler === 'string' ) {
handler = vm [ handler ] ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return vm . $watch ( expOrFn , handler , options ) ;
}
function stateMixin ( Vue ) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef = { } ;
dataDef . get = function ( ) {
return this . _data ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const propsDef = { } ;
propsDef . get = function ( ) {
return this . _props ;
} ;
{
dataDef . set = function ( ) {
warn ( 'Avoid replacing instance root $data. ' +
'Use nested data properties instead.' , this ) ;
} ;
propsDef . set = function ( ) {
warn ( ` $ props is readonly. ` , this ) ;
} ;
}
Object . defineProperty ( Vue . prototype , '$data' , dataDef ) ;
Object . defineProperty ( Vue . prototype , '$props' , propsDef ) ;
Vue . prototype . $set = set ;
Vue . prototype . $delete = del ;
Vue . prototype . $watch = function ( expOrFn , cb , options ) {
const vm = this ;
if ( isPlainObject ( cb ) ) {
return createWatcher ( vm , expOrFn , cb , options ) ;
}
options = options || { } ;
options . user = true ;
const watcher = new Watcher ( vm , expOrFn , cb , options ) ;
if ( options . immediate ) {
const info = ` callback for immediate watcher " ${ watcher . expression } " ` ;
pushTarget ( ) ;
invokeWithErrorHandling ( cb , vm , [ watcher . value ] , vm , info ) ;
popTarget ( ) ;
}
return function unwatchFn ( ) {
watcher . teardown ( ) ;
} ;
} ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let uid = 0 ;
function initMixin$1 ( Vue ) {
Vue . prototype . _init = function ( options ) {
const vm = this ;
// a uid
vm . _uid = uid ++ ;
let startTag , endTag ;
/* istanbul ignore if */
if ( config . performance && mark ) {
startTag = ` vue-perf-start: ${ vm . _uid } ` ;
endTag = ` vue-perf-end: ${ vm . _uid } ` ;
mark ( startTag ) ;
}
// a flag to mark this as a Vue instance without having to do instanceof
// check
vm . _isVue = true ;
// avoid instances from being observed
vm . _ _v _skip = true ;
// effect scope
vm . _scope = new EffectScope ( true /* detached */ ) ;
// #13134 edge case where a child component is manually created during the
// render of a parent component
vm . _scope . parent = undefined ;
vm . _scope . _vm = true ;
// merge options
if ( options && options . _isComponent ) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent ( vm , options ) ;
}
else {
vm . $options = mergeOptions ( resolveConstructorOptions ( vm . constructor ) , options || { } , vm ) ;
}
/* istanbul ignore else */
{
initProxy ( vm ) ;
}
// expose real self
vm . _self = vm ;
initLifecycle ( vm ) ;
initEvents ( vm ) ;
initRender ( vm ) ;
callHook$1 ( vm , 'beforeCreate' , undefined , false /* setContext */ ) ;
initInjections ( vm ) ; // resolve injections before data/props
initState ( vm ) ;
initProvide ( vm ) ; // resolve provide after data/props
callHook$1 ( vm , 'created' ) ;
/* istanbul ignore if */
if ( config . performance && mark ) {
vm . _name = formatComponentName ( vm , false ) ;
mark ( endTag ) ;
measure ( ` vue ${ vm . _name } init ` , startTag , endTag ) ;
}
if ( vm . $options . el ) {
vm . $mount ( vm . $options . el ) ;
}
} ;
}
function initInternalComponent ( vm , options ) {
const opts = ( vm . $options = Object . create ( vm . constructor . options ) ) ;
// doing this because it's faster than dynamic enumeration.
const parentVnode = options . _parentVnode ;
opts . parent = options . parent ;
opts . _parentVnode = parentVnode ;
const vnodeComponentOptions = parentVnode . componentOptions ;
opts . propsData = vnodeComponentOptions . propsData ;
opts . _parentListeners = vnodeComponentOptions . listeners ;
opts . _renderChildren = vnodeComponentOptions . children ;
opts . _componentTag = vnodeComponentOptions . tag ;
if ( options . render ) {
opts . render = options . render ;
opts . staticRenderFns = options . staticRenderFns ;
}
}
function resolveConstructorOptions ( Ctor ) {
let options = Ctor . options ;
if ( Ctor . super ) {
const superOptions = resolveConstructorOptions ( Ctor . super ) ;
const cachedSuperOptions = Ctor . superOptions ;
if ( superOptions !== cachedSuperOptions ) {
// super option changed,
// need to resolve new options.
Ctor . superOptions = superOptions ;
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions ( Ctor ) ;
// update base extend options
if ( modifiedOptions ) {
extend ( Ctor . extendOptions , modifiedOptions ) ;
}
options = Ctor . options = mergeOptions ( superOptions , Ctor . extendOptions ) ;
if ( options . name ) {
options . components [ options . name ] = Ctor ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return options ;
}
function resolveModifiedOptions ( Ctor ) {
let modified ;
const latest = Ctor . options ;
const sealed = Ctor . sealedOptions ;
for ( const key in latest ) {
if ( latest [ key ] !== sealed [ key ] ) {
if ( ! modified )
modified = { } ;
modified [ key ] = latest [ key ] ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return modified ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function Vue ( options ) {
if ( ! ( this instanceof Vue ) ) {
warn ( 'Vue is a constructor and should be called with the `new` keyword' ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
this . _init ( options ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
//@ts-expect-error Vue has function type
initMixin$1 ( Vue ) ;
//@ts-expect-error Vue has function type
stateMixin ( Vue ) ;
//@ts-expect-error Vue has function type
eventsMixin ( Vue ) ;
//@ts-expect-error Vue has function type
lifecycleMixin ( Vue ) ;
//@ts-expect-error Vue has function type
renderMixin ( Vue ) ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function initUse ( Vue ) {
Vue . use = function ( plugin ) {
const installedPlugins = this . _installedPlugins || ( this . _installedPlugins = [ ] ) ;
if ( installedPlugins . indexOf ( plugin ) > - 1 ) {
return this ;
}
// additional parameters
const args = toArray ( arguments , 1 ) ;
args . unshift ( this ) ;
if ( isFunction ( plugin . install ) ) {
plugin . install . apply ( plugin , args ) ;
}
else if ( isFunction ( plugin ) ) {
plugin . apply ( null , args ) ;
}
installedPlugins . push ( plugin ) ;
return this ;
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initMixin ( Vue ) {
Vue . mixin = function ( mixin ) {
this . options = mergeOptions ( this . options , mixin ) ;
return this ;
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initExtend ( Vue ) {
/ * *
* Each instance constructor , including Vue , has a unique
* cid . This enables us to create wrapped " child
* constructors " for prototypal inheritance and cache them .
* /
Vue . cid = 0 ;
let cid = 1 ;
/ * *
* Class inheritance
* /
Vue . extend = function ( extendOptions ) {
extendOptions = extendOptions || { } ;
const Super = this ;
const SuperId = Super . cid ;
const cachedCtors = extendOptions . _Ctor || ( extendOptions . _Ctor = { } ) ;
if ( cachedCtors [ SuperId ] ) {
return cachedCtors [ SuperId ] ;
}
const name = getComponentName ( extendOptions ) || getComponentName ( Super . options ) ;
if ( name ) {
validateComponentName ( name ) ;
}
const Sub = function VueComponent ( options ) {
this . _init ( options ) ;
} ;
Sub . prototype = Object . create ( Super . prototype ) ;
Sub . prototype . constructor = Sub ;
Sub . cid = cid ++ ;
Sub . options = mergeOptions ( Super . options , extendOptions ) ;
Sub [ 'super' ] = Super ;
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if ( Sub . options . props ) {
initProps ( Sub ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( Sub . options . computed ) {
initComputed ( Sub ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// allow further extension/mixin/plugin usage
Sub . extend = Super . extend ;
Sub . mixin = Super . mixin ;
Sub . use = Super . use ;
// create asset registers, so extended classes
// can have their private assets too.
ASSET _TYPES . forEach ( function ( type ) {
Sub [ type ] = Super [ type ] ;
} ) ;
// enable recursive self-lookup
if ( name ) {
Sub . options . components [ name ] = Sub ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub . superOptions = Super . options ;
Sub . extendOptions = extendOptions ;
Sub . sealedOptions = extend ( { } , Sub . options ) ;
// cache constructor
cachedCtors [ SuperId ] = Sub ;
return Sub ;
2023-12-18 13:12:25 +08:00
} ;
}
2024-01-16 21:26:16 +08:00
function initProps ( Comp ) {
const props = Comp . options . props ;
for ( const key in props ) {
proxy ( Comp . prototype , ` _props ` , key ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initComputed ( Comp ) {
const computed = Comp . options . computed ;
for ( const key in computed ) {
defineComputed ( Comp . prototype , key , computed [ key ] ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function initAssetRegisters ( Vue ) {
/ * *
* Create asset registration methods .
* /
ASSET _TYPES . forEach ( type => {
// @ts-expect-error function is not exact same type
Vue [ type ] = function ( id , definition ) {
if ( ! definition ) {
return this . options [ type + 's' ] [ id ] ;
}
else {
/* istanbul ignore if */
if ( type === 'component' ) {
validateComponentName ( id ) ;
}
if ( type === 'component' && isPlainObject ( definition ) ) {
// @ts-expect-error
definition . name = definition . name || id ;
definition = this . options . _base . extend ( definition ) ;
}
if ( type === 'directive' && isFunction ( definition ) ) {
definition = { bind : definition , update : definition } ;
}
this . options [ type + 's' ] [ id ] = definition ;
return definition ;
}
} ;
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function _getComponentName ( opts ) {
return opts && ( getComponentName ( opts . Ctor . options ) || opts . tag ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function matches ( pattern , name ) {
if ( isArray ( pattern ) ) {
return pattern . indexOf ( name ) > - 1 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( typeof pattern === 'string' ) {
return pattern . split ( ',' ) . indexOf ( name ) > - 1 ;
}
else if ( isRegExp ( pattern ) ) {
return pattern . test ( name ) ;
}
/* istanbul ignore next */
return false ;
}
function pruneCache ( keepAliveInstance , filter ) {
const { cache , keys , _vnode , $vnode } = keepAliveInstance ;
for ( const key in cache ) {
const entry = cache [ key ] ;
if ( entry ) {
const name = entry . name ;
if ( name && ! filter ( name ) ) {
pruneCacheEntry ( cache , key , keys , _vnode ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
$vnode . componentOptions . children = undefined ;
}
function pruneCacheEntry ( cache , key , keys , current ) {
const entry = cache [ key ] ;
if ( entry && ( ! current || entry . tag !== current . tag ) ) {
// @ts-expect-error can be undefined
entry . componentInstance . $destroy ( ) ;
}
cache [ key ] = null ;
remove$2 ( keys , key ) ;
}
const patternTypes = [ String , RegExp , Array ] ;
// TODO defineComponent
var KeepAlive = {
name : 'keep-alive' ,
abstract : true ,
props : {
include : patternTypes ,
exclude : patternTypes ,
max : [ String , Number ]
} ,
methods : {
cacheVNode ( ) {
const { cache , keys , vnodeToCache , keyToCache } = this ;
if ( vnodeToCache ) {
const { tag , componentInstance , componentOptions } = vnodeToCache ;
cache [ keyToCache ] = {
name : _getComponentName ( componentOptions ) ,
tag ,
componentInstance
} ;
keys . push ( keyToCache ) ;
// prune oldest entry
if ( this . max && keys . length > parseInt ( this . max ) ) {
pruneCacheEntry ( cache , keys [ 0 ] , keys , this . _vnode ) ;
}
this . vnodeToCache = null ;
}
}
} ,
created ( ) {
this . cache = Object . create ( null ) ;
this . keys = [ ] ;
} ,
destroyed ( ) {
for ( const key in this . cache ) {
pruneCacheEntry ( this . cache , key , this . keys ) ;
}
} ,
mounted ( ) {
this . cacheVNode ( ) ;
this . $watch ( 'include' , val => {
pruneCache ( this , name => matches ( val , name ) ) ;
} ) ;
this . $watch ( 'exclude' , val => {
pruneCache ( this , name => ! matches ( val , name ) ) ;
} ) ;
} ,
updated ( ) {
this . cacheVNode ( ) ;
} ,
render ( ) {
const slot = this . $slots . default ;
const vnode = getFirstComponentChild ( slot ) ;
const componentOptions = vnode && vnode . componentOptions ;
if ( componentOptions ) {
// check pattern
const name = _getComponentName ( componentOptions ) ;
const { include , exclude } = this ;
if (
// not included
( include && ( ! name || ! matches ( include , name ) ) ) ||
// excluded
( exclude && name && matches ( exclude , name ) ) ) {
return vnode ;
}
const { cache , keys } = this ;
const key = vnode . key == null
? // same constructor may get registered as different local components
// so cid alone is not enough (#3269)
componentOptions . Ctor . cid +
( componentOptions . tag ? ` :: ${ componentOptions . tag } ` : '' )
: vnode . key ;
if ( cache [ key ] ) {
vnode . componentInstance = cache [ key ] . componentInstance ;
// make current key freshest
remove$2 ( keys , key ) ;
keys . push ( key ) ;
}
else {
// delay setting the cache until update
this . vnodeToCache = vnode ;
this . keyToCache = key ;
}
// @ts-expect-error can vnode.data can be undefined
vnode . data . keepAlive = true ;
}
return vnode || ( slot && slot [ 0 ] ) ;
}
} ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
var builtInComponents = {
KeepAlive
} ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function initGlobalAPI ( Vue ) {
// config
const configDef = { } ;
configDef . get = ( ) => config ;
{
configDef . set = ( ) => {
warn ( 'Do not replace the Vue.config object, set individual fields instead.' ) ;
} ;
}
Object . defineProperty ( Vue , 'config' , configDef ) ;
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue . util = {
warn ,
extend ,
mergeOptions ,
defineReactive
} ;
Vue . set = set ;
Vue . delete = del ;
Vue . nextTick = nextTick ;
// 2.6 explicit observable API
Vue . observable = ( obj ) => {
observe ( obj ) ;
return obj ;
} ;
Vue . options = Object . create ( null ) ;
ASSET _TYPES . forEach ( type => {
Vue . options [ type + 's' ] = Object . create ( null ) ;
} ) ;
// this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue . options . _base = Vue ;
extend ( Vue . options . components , builtInComponents ) ;
initUse ( Vue ) ;
initMixin ( Vue ) ;
initExtend ( Vue ) ;
initAssetRegisters ( Vue ) ;
2023-12-18 13:12:25 +08:00
}
initGlobalAPI ( Vue ) ;
Object . defineProperty ( Vue . prototype , '$isServer' , {
2024-01-16 21:26:16 +08:00
get : isServerRendering
2023-12-18 13:12:25 +08:00
} ) ;
Object . defineProperty ( Vue . prototype , '$ssrContext' , {
2024-01-16 21:26:16 +08:00
get ( ) {
/* istanbul ignore next */
return this . $vnode && this . $vnode . ssrContext ;
}
2023-12-18 13:12:25 +08:00
} ) ;
// expose FunctionalRenderContext for ssr runtime helper installation
Object . defineProperty ( Vue , 'FunctionalRenderContext' , {
2024-01-16 21:26:16 +08:00
value : FunctionalRenderContext
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
Vue . version = version ;
2023-12-18 13:12:25 +08:00
// these are reserved for web because they are directly compiled away
// during template compilation
2024-01-16 21:26:16 +08:00
const isReservedAttr = makeMap ( 'style,class' ) ;
2023-12-18 13:12:25 +08:00
// attributes that should be using props for binding
2024-01-16 21:26:16 +08:00
const acceptValue = makeMap ( 'input,textarea,option,select,progress' ) ;
const mustUseProp = ( tag , type , attr ) => {
return ( ( attr === 'value' && acceptValue ( tag ) && type !== 'button' ) ||
( attr === 'selected' && tag === 'option' ) ||
( attr === 'checked' && tag === 'input' ) ||
( attr === 'muted' && tag === 'video' ) ) ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const isEnumeratedAttr = makeMap ( 'contenteditable,draggable,spellcheck' ) ;
const isValidContentEditableValue = makeMap ( 'events,caret,typing,plaintext-only' ) ;
const convertEnumeratedValue = ( key , value ) => {
return isFalsyAttrValue ( value ) || value === 'false'
? 'false'
: // allow arbitrary string value for contenteditable
key === 'contenteditable' && isValidContentEditableValue ( value )
? value
: 'true' ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const isBooleanAttr = makeMap ( 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
'required,reversed,scoped,seamless,selected,sortable,' +
'truespeed,typemustmatch,visible' ) ;
const xlinkNS = 'http://www.w3.org/1999/xlink' ;
const isXlink = ( name ) => {
return name . charAt ( 5 ) === ':' && name . slice ( 0 , 5 ) === 'xlink' ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const getXlinkProp = ( name ) => {
return isXlink ( name ) ? name . slice ( 6 , name . length ) : '' ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const isFalsyAttrValue = ( val ) => {
return val == null || val === false ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function genClassForVnode ( vnode ) {
let data = vnode . data ;
let parentNode = vnode ;
let childNode = vnode ;
while ( isDef ( childNode . componentInstance ) ) {
childNode = childNode . componentInstance . _vnode ;
if ( childNode && childNode . data ) {
data = mergeClassData ( childNode . data , data ) ;
}
}
// @ts-expect-error parentNode.parent not VNodeWithData
while ( isDef ( ( parentNode = parentNode . parent ) ) ) {
if ( parentNode && parentNode . data ) {
data = mergeClassData ( data , parentNode . data ) ;
}
}
return renderClass ( data . staticClass , data . class ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function mergeClassData ( child , parent ) {
return {
staticClass : concat ( child . staticClass , parent . staticClass ) ,
class : isDef ( child . class ) ? [ child . class , parent . class ] : parent . class
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function renderClass ( staticClass , dynamicClass ) {
if ( isDef ( staticClass ) || isDef ( dynamicClass ) ) {
return concat ( staticClass , stringifyClass ( dynamicClass ) ) ;
}
/* istanbul ignore next */
return '' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function concat ( a , b ) {
return a ? ( b ? a + ' ' + b : a ) : b || '' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function stringifyClass ( value ) {
if ( Array . isArray ( value ) ) {
return stringifyArray ( value ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( isObject ( value ) ) {
return stringifyObject ( value ) ;
}
if ( typeof value === 'string' ) {
return value ;
}
/* istanbul ignore next */
return '' ;
}
function stringifyArray ( value ) {
let res = '' ;
let stringified ;
for ( let i = 0 , l = value . length ; i < l ; i ++ ) {
if ( isDef ( ( stringified = stringifyClass ( value [ i ] ) ) ) && stringified !== '' ) {
if ( res )
res += ' ' ;
res += stringified ;
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function stringifyObject ( value ) {
let res = '' ;
for ( const key in value ) {
if ( value [ key ] ) {
if ( res )
res += ' ' ;
res += key ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const namespaceMap = {
svg : 'http://www.w3.org/2000/svg' ,
math : 'http://www.w3.org/1998/Math/MathML'
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const isHTMLTag = makeMap ( 'html,body,base,head,link,meta,style,title,' +
'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
'embed,object,param,source,canvas,script,noscript,del,ins,' +
'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
'output,progress,select,textarea,' +
'details,dialog,menu,menuitem,summary,' +
'content,element,shadow,template,blockquote,iframe,tfoot' ) ;
2023-12-18 13:12:25 +08:00
// this map is intentionally selective, only covering SVG elements that may
// contain child elements.
2024-01-16 21:26:16 +08:00
const isSVG = makeMap ( 'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
'foreignobject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view' , true ) ;
const isReservedTag = ( tag ) => {
return isHTMLTag ( tag ) || isSVG ( tag ) ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function getTagNamespace ( tag ) {
if ( isSVG ( tag ) ) {
return 'svg' ;
}
// basic support for MathML
// note it doesn't support other MathML elements being component roots
if ( tag === 'math' ) {
return 'math' ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const unknownElementCache = Object . create ( null ) ;
function isUnknownElement ( tag ) {
/* istanbul ignore if */
if ( ! inBrowser ) {
return true ;
}
if ( isReservedTag ( tag ) ) {
return false ;
}
tag = tag . toLowerCase ( ) ;
/* istanbul ignore if */
if ( unknownElementCache [ tag ] != null ) {
return unknownElementCache [ tag ] ;
}
const el = document . createElement ( tag ) ;
if ( tag . indexOf ( '-' ) > - 1 ) {
// https://stackoverflow.com/a/28210364/1070244
return ( unknownElementCache [ tag ] =
el . constructor === window . HTMLUnknownElement ||
el . constructor === window . HTMLElement ) ;
}
else {
return ( unknownElementCache [ tag ] = /HTMLUnknownElement/ . test ( el . toString ( ) ) ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const isTextInputType = makeMap ( 'text,number,password,search,email,tel,url' ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Query an element selector if it ' s not an element already .
* /
2024-01-16 21:26:16 +08:00
function query ( el ) {
if ( typeof el === 'string' ) {
const selected = document . querySelector ( el ) ;
if ( ! selected ) {
warn ( 'Cannot find element: ' + el ) ;
return document . createElement ( 'div' ) ;
}
return selected ;
}
else {
return el ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createElement ( tagName , vnode ) {
const elm = document . createElement ( tagName ) ;
if ( tagName !== 'select' ) {
return elm ;
}
// false or null will remove the attribute but undefined will not
if ( vnode . data &&
vnode . data . attrs &&
vnode . data . attrs . multiple !== undefined ) {
elm . setAttribute ( 'multiple' , 'multiple' ) ;
}
return elm ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createElementNS ( namespace , tagName ) {
return document . createElementNS ( namespaceMap [ namespace ] , tagName ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createTextNode ( text ) {
return document . createTextNode ( text ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createComment ( text ) {
return document . createComment ( text ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function insertBefore ( parentNode , newNode , referenceNode ) {
parentNode . insertBefore ( newNode , referenceNode ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function removeChild ( node , child ) {
node . removeChild ( child ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function appendChild ( node , child ) {
node . appendChild ( child ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parentNode ( node ) {
return node . parentNode ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function nextSibling ( node ) {
return node . nextSibling ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function tagName ( node ) {
return node . tagName ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function setTextContent ( node , text ) {
node . textContent = text ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function setStyleScope ( node , scopeId ) {
node . setAttribute ( scopeId , '' ) ;
2023-12-18 13:12:25 +08:00
}
var nodeOps = /*#__PURE__*/ Object . freeze ( {
2024-01-16 21:26:16 +08:00
_ _proto _ _ : null ,
createElement : createElement ,
2023-12-18 13:12:25 +08:00
createElementNS : createElementNS ,
createTextNode : createTextNode ,
createComment : createComment ,
insertBefore : insertBefore ,
removeChild : removeChild ,
appendChild : appendChild ,
parentNode : parentNode ,
nextSibling : nextSibling ,
tagName : tagName ,
setTextContent : setTextContent ,
setStyleScope : setStyleScope
} ) ;
var ref = {
2024-01-16 21:26:16 +08:00
create ( _ , vnode ) {
registerRef ( vnode ) ;
} ,
update ( oldVnode , vnode ) {
if ( oldVnode . data . ref !== vnode . data . ref ) {
registerRef ( oldVnode , true ) ;
registerRef ( vnode ) ;
}
} ,
destroy ( vnode ) {
registerRef ( vnode , true ) ;
}
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function registerRef ( vnode , isRemoval ) {
const ref = vnode . data . ref ;
if ( ! isDef ( ref ) )
return ;
const vm = vnode . context ;
const refValue = vnode . componentInstance || vnode . elm ;
const value = isRemoval ? null : refValue ;
const $refsValue = isRemoval ? undefined : refValue ;
if ( isFunction ( ref ) ) {
invokeWithErrorHandling ( ref , vm , [ value ] , vm , ` template ref function ` ) ;
return ;
}
const isFor = vnode . data . refInFor ;
const _isString = typeof ref === 'string' || typeof ref === 'number' ;
const _isRef = isRef ( ref ) ;
const refs = vm . $refs ;
if ( _isString || _isRef ) {
if ( isFor ) {
const existing = _isString ? refs [ ref ] : ref . value ;
if ( isRemoval ) {
isArray ( existing ) && remove$2 ( existing , refValue ) ;
}
else {
if ( ! isArray ( existing ) ) {
if ( _isString ) {
refs [ ref ] = [ refValue ] ;
setSetupRef ( vm , ref , refs [ ref ] ) ;
}
else {
ref . value = [ refValue ] ;
}
}
else if ( ! existing . includes ( refValue ) ) {
existing . push ( refValue ) ;
}
}
}
else if ( _isString ) {
if ( isRemoval && refs [ ref ] !== refValue ) {
return ;
}
refs [ ref ] = $refsValue ;
setSetupRef ( vm , ref , value ) ;
}
else if ( _isRef ) {
if ( isRemoval && ref . value !== refValue ) {
return ;
}
ref . value = value ;
}
else {
warn ( ` Invalid template ref type: ${ typeof ref } ` ) ;
}
}
}
function setSetupRef ( { _setupState } , key , val ) {
if ( _setupState && hasOwn ( _setupState , key ) ) {
if ( isRef ( _setupState [ key ] ) ) {
_setupState [ key ] . value = val ;
}
else {
_setupState [ key ] = val ;
}
2023-12-18 13:12:25 +08:00
}
}
/ * *
* Virtual DOM patching algorithm based on Snabbdom by
* Simon Friis Vindum ( @ paldepind )
* Licensed under the MIT License
* https : //github.com/paldepind/snabbdom/blob/master/LICENSE
*
* modified by Evan You ( @ yyx990803 )
*
* Not type - checking this because this file is perf - critical and the cost
* of making flow understand it is not worth it .
* /
2024-01-16 21:26:16 +08:00
const emptyNode = new VNode ( '' , { } , [ ] ) ;
const hooks = [ 'create' , 'activate' , 'update' , 'remove' , 'destroy' ] ;
function sameVnode ( a , b ) {
return ( a . key === b . key &&
2023-12-18 13:12:25 +08:00
a . asyncFactory === b . asyncFactory &&
2024-01-16 21:26:16 +08:00
( ( a . tag === b . tag &&
a . isComment === b . isComment &&
isDef ( a . data ) === isDef ( b . data ) &&
sameInputType ( a , b ) ) ||
( isTrue ( a . isAsyncPlaceholder ) && isUndef ( b . asyncFactory . error ) ) ) ) ;
}
function sameInputType ( a , b ) {
if ( a . tag !== 'input' )
return true ;
let i ;
const typeA = isDef ( ( i = a . data ) ) && isDef ( ( i = i . attrs ) ) && i . type ;
const typeB = isDef ( ( i = b . data ) ) && isDef ( ( i = i . attrs ) ) && i . type ;
return typeA === typeB || ( isTextInputType ( typeA ) && isTextInputType ( typeB ) ) ;
}
function createKeyToOldIdx ( children , beginIdx , endIdx ) {
let i , key ;
const map = { } ;
for ( i = beginIdx ; i <= endIdx ; ++ i ) {
key = children [ i ] . key ;
if ( isDef ( key ) )
map [ key ] = i ;
}
return map ;
}
function createPatchFunction ( backend ) {
let i , j ;
const cbs = { } ;
const { modules , nodeOps } = backend ;
for ( i = 0 ; i < hooks . length ; ++ i ) {
cbs [ hooks [ i ] ] = [ ] ;
for ( j = 0 ; j < modules . length ; ++ j ) {
if ( isDef ( modules [ j ] [ hooks [ i ] ] ) ) {
cbs [ hooks [ i ] ] . push ( modules [ j ] [ hooks [ i ] ] ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function emptyNodeAt ( elm ) {
return new VNode ( nodeOps . tagName ( elm ) . toLowerCase ( ) , { } , [ ] , undefined , elm ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createRmCb ( childElm , listeners ) {
function remove ( ) {
if ( -- remove . listeners === 0 ) {
removeNode ( childElm ) ;
}
}
remove . listeners = listeners ;
return remove ;
}
function removeNode ( el ) {
const parent = nodeOps . parentNode ( el ) ;
// element may have already been removed due to v-html / v-text
if ( isDef ( parent ) ) {
nodeOps . removeChild ( parent , el ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isUnknownElement ( vnode , inVPre ) {
return ( ! inVPre &&
! vnode . ns &&
! ( config . ignoredElements . length &&
config . ignoredElements . some ( ignore => {
return isRegExp ( ignore )
? ignore . test ( vnode . tag )
: ignore === vnode . tag ;
} ) ) &&
config . isUnknownElement ( vnode . tag ) ) ;
}
let creatingElmInVPre = 0 ;
function createElm ( vnode , insertedVnodeQueue , parentElm , refElm , nested , ownerArray , index ) {
if ( isDef ( vnode . elm ) && isDef ( ownerArray ) ) {
// This vnode was used in a previous render!
// now it's used as a new node, overwriting its elm would cause
// potential patch errors down the road when it's used as an insertion
// reference node. Instead, we clone the node on-demand before creating
// associated DOM element for it.
vnode = ownerArray [ index ] = cloneVNode ( vnode ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
vnode . isRootInsert = ! nested ; // for transition enter check
if ( createComponent ( vnode , insertedVnodeQueue , parentElm , refElm ) ) {
return ;
}
const data = vnode . data ;
const children = vnode . children ;
const tag = vnode . tag ;
if ( isDef ( tag ) ) {
{
if ( data && data . pre ) {
creatingElmInVPre ++ ;
}
if ( isUnknownElement ( vnode , creatingElmInVPre ) ) {
warn ( 'Unknown custom element: <' +
tag +
'> - did you ' +
'register the component correctly? For recursive components, ' +
'make sure to provide the "name" option.' , vnode . context ) ;
}
}
vnode . elm = vnode . ns
? nodeOps . createElementNS ( vnode . ns , tag )
: nodeOps . createElement ( tag , vnode ) ;
setScope ( vnode ) ;
createChildren ( vnode , children , insertedVnodeQueue ) ;
if ( isDef ( data ) ) {
invokeCreateHooks ( vnode , insertedVnodeQueue ) ;
}
insert ( parentElm , vnode . elm , refElm ) ;
if ( data && data . pre ) {
creatingElmInVPre -- ;
}
}
else if ( isTrue ( vnode . isComment ) ) {
vnode . elm = nodeOps . createComment ( vnode . text ) ;
insert ( parentElm , vnode . elm , refElm ) ;
}
else {
vnode . elm = nodeOps . createTextNode ( vnode . text ) ;
insert ( parentElm , vnode . elm , refElm ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function createComponent ( vnode , insertedVnodeQueue , parentElm , refElm ) {
let i = vnode . data ;
if ( isDef ( i ) ) {
const isReactivated = isDef ( vnode . componentInstance ) && i . keepAlive ;
if ( isDef ( ( i = i . hook ) ) && isDef ( ( i = i . init ) ) ) {
i ( vnode , false /* hydrating */ ) ;
}
// after calling the init hook, if the vnode is a child component
// it should've created a child instance and mounted it. the child
// component also has set the placeholder vnode's elm.
// in that case we can just return the element and be done.
if ( isDef ( vnode . componentInstance ) ) {
initComponent ( vnode , insertedVnodeQueue ) ;
insert ( parentElm , vnode . elm , refElm ) ;
if ( isTrue ( isReactivated ) ) {
reactivateComponent ( vnode , insertedVnodeQueue , parentElm , refElm ) ;
}
return true ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function initComponent ( vnode , insertedVnodeQueue ) {
if ( isDef ( vnode . data . pendingInsert ) ) {
insertedVnodeQueue . push . apply ( insertedVnodeQueue , vnode . data . pendingInsert ) ;
vnode . data . pendingInsert = null ;
}
vnode . elm = vnode . componentInstance . $el ;
if ( isPatchable ( vnode ) ) {
invokeCreateHooks ( vnode , insertedVnodeQueue ) ;
setScope ( vnode ) ;
}
else {
// empty component root.
// skip all element-related modules except for ref (#3455)
registerRef ( vnode ) ;
// make sure to invoke the insert hook
insertedVnodeQueue . push ( vnode ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function reactivateComponent ( vnode , insertedVnodeQueue , parentElm , refElm ) {
let i ;
// hack for #4339: a reactivated component with inner transition
// does not trigger because the inner node's created hooks are not called
// again. It's not ideal to involve module-specific logic in here but
// there doesn't seem to be a better way to do it.
let innerNode = vnode ;
while ( innerNode . componentInstance ) {
innerNode = innerNode . componentInstance . _vnode ;
if ( isDef ( ( i = innerNode . data ) ) && isDef ( ( i = i . transition ) ) ) {
for ( i = 0 ; i < cbs . activate . length ; ++ i ) {
cbs . activate [ i ] ( emptyNode , innerNode ) ;
}
insertedVnodeQueue . push ( innerNode ) ;
break ;
}
}
// unlike a newly created component,
// a reactivated keep-alive component doesn't insert itself
insert ( parentElm , vnode . elm , refElm ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function insert ( parent , elm , ref ) {
if ( isDef ( parent ) ) {
if ( isDef ( ref ) ) {
if ( nodeOps . parentNode ( ref ) === parent ) {
nodeOps . insertBefore ( parent , elm , ref ) ;
}
}
else {
nodeOps . appendChild ( parent , elm ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createChildren ( vnode , children , insertedVnodeQueue ) {
if ( isArray ( children ) ) {
{
checkDuplicateKeys ( children ) ;
}
for ( let i = 0 ; i < children . length ; ++ i ) {
createElm ( children [ i ] , insertedVnodeQueue , vnode . elm , null , true , children , i ) ;
}
}
else if ( isPrimitive ( vnode . text ) ) {
nodeOps . appendChild ( vnode . elm , nodeOps . createTextNode ( String ( vnode . text ) ) ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isPatchable ( vnode ) {
while ( vnode . componentInstance ) {
vnode = vnode . componentInstance . _vnode ;
}
return isDef ( vnode . tag ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function invokeCreateHooks ( vnode , insertedVnodeQueue ) {
for ( let i = 0 ; i < cbs . create . length ; ++ i ) {
cbs . create [ i ] ( emptyNode , vnode ) ;
}
i = vnode . data . hook ; // Reuse variable
if ( isDef ( i ) ) {
if ( isDef ( i . create ) )
i . create ( emptyNode , vnode ) ;
if ( isDef ( i . insert ) )
insertedVnodeQueue . push ( vnode ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// set scope id attribute for scoped CSS.
// this is implemented as a special case to avoid the overhead
// of going through the normal attribute patching process.
function setScope ( vnode ) {
let i ;
if ( isDef ( ( i = vnode . fnScopeId ) ) ) {
nodeOps . setStyleScope ( vnode . elm , i ) ;
}
else {
let ancestor = vnode ;
while ( ancestor ) {
if ( isDef ( ( i = ancestor . context ) ) && isDef ( ( i = i . $options . _scopeId ) ) ) {
nodeOps . setStyleScope ( vnode . elm , i ) ;
}
ancestor = ancestor . parent ;
}
}
// for slot content they should also get the scopeId from the host instance.
if ( isDef ( ( i = activeInstance ) ) &&
i !== vnode . context &&
i !== vnode . fnContext &&
isDef ( ( i = i . $options . _scopeId ) ) ) {
nodeOps . setStyleScope ( vnode . elm , i ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function addVnodes ( parentElm , refElm , vnodes , startIdx , endIdx , insertedVnodeQueue ) {
for ( ; startIdx <= endIdx ; ++ startIdx ) {
createElm ( vnodes [ startIdx ] , insertedVnodeQueue , parentElm , refElm , false , vnodes , startIdx ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function invokeDestroyHook ( vnode ) {
let i , j ;
const data = vnode . data ;
if ( isDef ( data ) ) {
if ( isDef ( ( i = data . hook ) ) && isDef ( ( i = i . destroy ) ) )
i ( vnode ) ;
for ( i = 0 ; i < cbs . destroy . length ; ++ i )
cbs . destroy [ i ] ( vnode ) ;
}
if ( isDef ( ( i = vnode . children ) ) ) {
for ( j = 0 ; j < vnode . children . length ; ++ j ) {
invokeDestroyHook ( vnode . children [ j ] ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function removeVnodes ( vnodes , startIdx , endIdx ) {
for ( ; startIdx <= endIdx ; ++ startIdx ) {
const ch = vnodes [ startIdx ] ;
if ( isDef ( ch ) ) {
if ( isDef ( ch . tag ) ) {
removeAndInvokeRemoveHook ( ch ) ;
invokeDestroyHook ( ch ) ;
}
else {
// Text node
removeNode ( ch . elm ) ;
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function removeAndInvokeRemoveHook ( vnode , rm ) {
if ( isDef ( rm ) || isDef ( vnode . data ) ) {
let i ;
const listeners = cbs . remove . length + 1 ;
if ( isDef ( rm ) ) {
// we have a recursively passed down rm callback
// increase the listeners count
rm . listeners += listeners ;
}
else {
// directly removing
rm = createRmCb ( vnode . elm , listeners ) ;
}
// recursively invoke hooks on child component root node
if ( isDef ( ( i = vnode . componentInstance ) ) &&
isDef ( ( i = i . _vnode ) ) &&
isDef ( i . data ) ) {
removeAndInvokeRemoveHook ( i , rm ) ;
}
for ( i = 0 ; i < cbs . remove . length ; ++ i ) {
cbs . remove [ i ] ( vnode , rm ) ;
}
if ( isDef ( ( i = vnode . data . hook ) ) && isDef ( ( i = i . remove ) ) ) {
i ( vnode , rm ) ;
}
else {
rm ( ) ;
}
}
else {
removeNode ( vnode . elm ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function updateChildren ( parentElm , oldCh , newCh , insertedVnodeQueue , removeOnly ) {
let oldStartIdx = 0 ;
let newStartIdx = 0 ;
let oldEndIdx = oldCh . length - 1 ;
let oldStartVnode = oldCh [ 0 ] ;
let oldEndVnode = oldCh [ oldEndIdx ] ;
let newEndIdx = newCh . length - 1 ;
let newStartVnode = newCh [ 0 ] ;
let newEndVnode = newCh [ newEndIdx ] ;
let oldKeyToIdx , idxInOld , vnodeToMove , refElm ;
// removeOnly is a special flag used only by <transition-group>
// to ensure removed elements stay in correct relative positions
// during leaving transitions
const canMove = ! removeOnly ;
2023-12-18 13:12:25 +08:00
{
2024-01-16 21:26:16 +08:00
checkDuplicateKeys ( newCh ) ;
}
while ( oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx ) {
if ( isUndef ( oldStartVnode ) ) {
oldStartVnode = oldCh [ ++ oldStartIdx ] ; // Vnode has been moved left
}
else if ( isUndef ( oldEndVnode ) ) {
oldEndVnode = oldCh [ -- oldEndIdx ] ;
}
else if ( sameVnode ( oldStartVnode , newStartVnode ) ) {
patchVnode ( oldStartVnode , newStartVnode , insertedVnodeQueue , newCh , newStartIdx ) ;
oldStartVnode = oldCh [ ++ oldStartIdx ] ;
newStartVnode = newCh [ ++ newStartIdx ] ;
}
else if ( sameVnode ( oldEndVnode , newEndVnode ) ) {
patchVnode ( oldEndVnode , newEndVnode , insertedVnodeQueue , newCh , newEndIdx ) ;
oldEndVnode = oldCh [ -- oldEndIdx ] ;
newEndVnode = newCh [ -- newEndIdx ] ;
}
else if ( sameVnode ( oldStartVnode , newEndVnode ) ) {
// Vnode moved right
patchVnode ( oldStartVnode , newEndVnode , insertedVnodeQueue , newCh , newEndIdx ) ;
canMove &&
nodeOps . insertBefore ( parentElm , oldStartVnode . elm , nodeOps . nextSibling ( oldEndVnode . elm ) ) ;
oldStartVnode = oldCh [ ++ oldStartIdx ] ;
newEndVnode = newCh [ -- newEndIdx ] ;
}
else if ( sameVnode ( oldEndVnode , newStartVnode ) ) {
// Vnode moved left
patchVnode ( oldEndVnode , newStartVnode , insertedVnodeQueue , newCh , newStartIdx ) ;
canMove &&
nodeOps . insertBefore ( parentElm , oldEndVnode . elm , oldStartVnode . elm ) ;
oldEndVnode = oldCh [ -- oldEndIdx ] ;
newStartVnode = newCh [ ++ newStartIdx ] ;
}
else {
if ( isUndef ( oldKeyToIdx ) )
oldKeyToIdx = createKeyToOldIdx ( oldCh , oldStartIdx , oldEndIdx ) ;
idxInOld = isDef ( newStartVnode . key )
? oldKeyToIdx [ newStartVnode . key ]
: findIdxInOld ( newStartVnode , oldCh , oldStartIdx , oldEndIdx ) ;
if ( isUndef ( idxInOld ) ) {
// New element
createElm ( newStartVnode , insertedVnodeQueue , parentElm , oldStartVnode . elm , false , newCh , newStartIdx ) ;
}
else {
vnodeToMove = oldCh [ idxInOld ] ;
if ( sameVnode ( vnodeToMove , newStartVnode ) ) {
patchVnode ( vnodeToMove , newStartVnode , insertedVnodeQueue , newCh , newStartIdx ) ;
oldCh [ idxInOld ] = undefined ;
canMove &&
nodeOps . insertBefore ( parentElm , vnodeToMove . elm , oldStartVnode . elm ) ;
}
else {
// same key but different element. treat as new element
createElm ( newStartVnode , insertedVnodeQueue , parentElm , oldStartVnode . elm , false , newCh , newStartIdx ) ;
}
}
newStartVnode = newCh [ ++ newStartIdx ] ;
}
}
if ( oldStartIdx > oldEndIdx ) {
refElm = isUndef ( newCh [ newEndIdx + 1 ] ) ? null : newCh [ newEndIdx + 1 ] . elm ;
addVnodes ( parentElm , refElm , newCh , newStartIdx , newEndIdx , insertedVnodeQueue ) ;
}
else if ( newStartIdx > newEndIdx ) {
removeVnodes ( oldCh , oldStartIdx , oldEndIdx ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkDuplicateKeys ( children ) {
const seenKeys = { } ;
for ( let i = 0 ; i < children . length ; i ++ ) {
const vnode = children [ i ] ;
const key = vnode . key ;
if ( isDef ( key ) ) {
if ( seenKeys [ key ] ) {
warn ( ` Duplicate keys detected: ' ${ key } '. This may cause an update error. ` , vnode . context ) ;
}
else {
seenKeys [ key ] = true ;
}
}
}
}
function findIdxInOld ( node , oldCh , start , end ) {
for ( let i = start ; i < end ; i ++ ) {
const c = oldCh [ i ] ;
if ( isDef ( c ) && sameVnode ( node , c ) )
return i ;
}
}
function patchVnode ( oldVnode , vnode , insertedVnodeQueue , ownerArray , index , removeOnly ) {
if ( oldVnode === vnode ) {
return ;
}
if ( isDef ( vnode . elm ) && isDef ( ownerArray ) ) {
// clone reused vnode
vnode = ownerArray [ index ] = cloneVNode ( vnode ) ;
}
const elm = ( vnode . elm = oldVnode . elm ) ;
if ( isTrue ( oldVnode . isAsyncPlaceholder ) ) {
if ( isDef ( vnode . asyncFactory . resolved ) ) {
hydrate ( oldVnode . elm , vnode , insertedVnodeQueue ) ;
}
else {
vnode . isAsyncPlaceholder = true ;
}
return ;
}
// reuse element for static trees.
// note we only do this if the vnode is cloned -
// if the new node is not cloned it means the render functions have been
// reset by the hot-reload-api and we need to do a proper re-render.
if ( isTrue ( vnode . isStatic ) &&
isTrue ( oldVnode . isStatic ) &&
vnode . key === oldVnode . key &&
( isTrue ( vnode . isCloned ) || isTrue ( vnode . isOnce ) ) ) {
vnode . componentInstance = oldVnode . componentInstance ;
return ;
}
let i ;
const data = vnode . data ;
if ( isDef ( data ) && isDef ( ( i = data . hook ) ) && isDef ( ( i = i . prepatch ) ) ) {
i ( oldVnode , vnode ) ;
}
const oldCh = oldVnode . children ;
const ch = vnode . children ;
if ( isDef ( data ) && isPatchable ( vnode ) ) {
for ( i = 0 ; i < cbs . update . length ; ++ i )
cbs . update [ i ] ( oldVnode , vnode ) ;
if ( isDef ( ( i = data . hook ) ) && isDef ( ( i = i . update ) ) )
i ( oldVnode , vnode ) ;
}
if ( isUndef ( vnode . text ) ) {
if ( isDef ( oldCh ) && isDef ( ch ) ) {
if ( oldCh !== ch )
updateChildren ( elm , oldCh , ch , insertedVnodeQueue , removeOnly ) ;
}
else if ( isDef ( ch ) ) {
{
checkDuplicateKeys ( ch ) ;
}
if ( isDef ( oldVnode . text ) )
nodeOps . setTextContent ( elm , '' ) ;
addVnodes ( elm , null , ch , 0 , ch . length - 1 , insertedVnodeQueue ) ;
}
else if ( isDef ( oldCh ) ) {
removeVnodes ( oldCh , 0 , oldCh . length - 1 ) ;
}
else if ( isDef ( oldVnode . text ) ) {
nodeOps . setTextContent ( elm , '' ) ;
}
}
else if ( oldVnode . text !== vnode . text ) {
nodeOps . setTextContent ( elm , vnode . text ) ;
}
if ( isDef ( data ) ) {
if ( isDef ( ( i = data . hook ) ) && isDef ( ( i = i . postpatch ) ) )
i ( oldVnode , vnode ) ;
}
}
function invokeInsertHook ( vnode , queue , initial ) {
// delay insert hooks for component root nodes, invoke them after the
// element is really inserted
if ( isTrue ( initial ) && isDef ( vnode . parent ) ) {
vnode . parent . data . pendingInsert = queue ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
for ( let i = 0 ; i < queue . length ; ++ i ) {
queue [ i ] . data . hook . insert ( queue [ i ] ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
let hydrationBailed = false ;
// list of modules that can skip create hook during hydration because they
// are already rendered on the client or has no need for initialization
// Note: style is excluded because it relies on initial clone for future
// deep updates (#7063).
const isRenderedModule = makeMap ( 'attrs,class,staticClass,staticStyle,key' ) ;
// Note: this is a browser-only function so we can assume elms are DOM nodes.
function hydrate ( elm , vnode , insertedVnodeQueue , inVPre ) {
let i ;
const { tag , data , children } = vnode ;
inVPre = inVPre || ( data && data . pre ) ;
vnode . elm = elm ;
if ( isTrue ( vnode . isComment ) && isDef ( vnode . asyncFactory ) ) {
vnode . isAsyncPlaceholder = true ;
return true ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// assert node match
{
if ( ! assertNodeMatch ( elm , vnode , inVPre ) ) {
return false ;
}
}
if ( isDef ( data ) ) {
if ( isDef ( ( i = data . hook ) ) && isDef ( ( i = i . init ) ) )
i ( vnode , true /* hydrating */ ) ;
if ( isDef ( ( i = vnode . componentInstance ) ) ) {
// child component. it should have hydrated its own tree.
initComponent ( vnode , insertedVnodeQueue ) ;
return true ;
}
}
if ( isDef ( tag ) ) {
if ( isDef ( children ) ) {
// empty element, allow client to pick up and populate children
if ( ! elm . hasChildNodes ( ) ) {
createChildren ( vnode , children , insertedVnodeQueue ) ;
}
else {
// v-html and domProps: innerHTML
if ( isDef ( ( i = data ) ) &&
isDef ( ( i = i . domProps ) ) &&
isDef ( ( i = i . innerHTML ) ) ) {
if ( i !== elm . innerHTML ) {
/* istanbul ignore if */
if ( typeof console !== 'undefined' &&
! hydrationBailed ) {
hydrationBailed = true ;
console . warn ( 'Parent: ' , elm ) ;
console . warn ( 'server innerHTML: ' , i ) ;
console . warn ( 'client innerHTML: ' , elm . innerHTML ) ;
}
return false ;
}
}
else {
// iterate and compare children lists
let childrenMatch = true ;
let childNode = elm . firstChild ;
for ( let i = 0 ; i < children . length ; i ++ ) {
if ( ! childNode ||
! hydrate ( childNode , children [ i ] , insertedVnodeQueue , inVPre ) ) {
childrenMatch = false ;
break ;
}
childNode = childNode . nextSibling ;
}
// if childNode is not null, it means the actual childNodes list is
// longer than the virtual children list.
if ( ! childrenMatch || childNode ) {
/* istanbul ignore if */
if ( typeof console !== 'undefined' &&
! hydrationBailed ) {
hydrationBailed = true ;
console . warn ( 'Parent: ' , elm ) ;
console . warn ( 'Mismatching childNodes vs. VNodes: ' , elm . childNodes , children ) ;
}
return false ;
}
}
}
}
if ( isDef ( data ) ) {
let fullInvoke = false ;
for ( const key in data ) {
if ( ! isRenderedModule ( key ) ) {
fullInvoke = true ;
invokeCreateHooks ( vnode , insertedVnodeQueue ) ;
break ;
}
}
if ( ! fullInvoke && data [ 'class' ] ) {
// ensure collecting deps for deep class bindings for future updates
traverse ( data [ 'class' ] ) ;
2023-12-18 13:12:25 +08:00
}
}
}
2024-01-16 21:26:16 +08:00
else if ( elm . data !== vnode . text ) {
elm . data = vnode . text ;
}
return true ;
}
function assertNodeMatch ( node , vnode , inVPre ) {
if ( isDef ( vnode . tag ) ) {
return ( vnode . tag . indexOf ( 'vue-component' ) === 0 ||
( ! isUnknownElement ( vnode , inVPre ) &&
vnode . tag . toLowerCase ( ) ===
( node . tagName && node . tagName . toLowerCase ( ) ) ) ) ;
}
else {
return node . nodeType === ( vnode . isComment ? 8 : 3 ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
return function patch ( oldVnode , vnode , hydrating , removeOnly ) {
if ( isUndef ( vnode ) ) {
if ( isDef ( oldVnode ) )
invokeDestroyHook ( oldVnode ) ;
return ;
}
let isInitialPatch = false ;
const insertedVnodeQueue = [ ] ;
if ( isUndef ( oldVnode ) ) {
// empty mount (likely as component), create new root element
isInitialPatch = true ;
createElm ( vnode , insertedVnodeQueue ) ;
}
else {
const isRealElement = isDef ( oldVnode . nodeType ) ;
if ( ! isRealElement && sameVnode ( oldVnode , vnode ) ) {
// patch existing root node
patchVnode ( oldVnode , vnode , insertedVnodeQueue , null , null , removeOnly ) ;
}
else {
if ( isRealElement ) {
// mounting to a real element
// check if this is server-rendered content and if we can perform
// a successful hydration.
if ( oldVnode . nodeType === 1 && oldVnode . hasAttribute ( SSR _ATTR ) ) {
oldVnode . removeAttribute ( SSR _ATTR ) ;
hydrating = true ;
}
if ( isTrue ( hydrating ) ) {
if ( hydrate ( oldVnode , vnode , insertedVnodeQueue ) ) {
invokeInsertHook ( vnode , insertedVnodeQueue , true ) ;
return oldVnode ;
}
else {
warn ( 'The client-side rendered virtual DOM tree is not matching ' +
'server-rendered content. This is likely caused by incorrect ' +
'HTML markup, for example nesting block-level elements inside ' +
'<p>, or missing <tbody>. Bailing hydration and performing ' +
'full client-side render.' ) ;
}
}
// either not server-rendered, or hydration failed.
// create an empty node and replace it
oldVnode = emptyNodeAt ( oldVnode ) ;
}
// replacing existing element
const oldElm = oldVnode . elm ;
const parentElm = nodeOps . parentNode ( oldElm ) ;
// create new node
createElm ( vnode , insertedVnodeQueue ,
// extremely rare edge case: do not insert if old element is in a
// leaving transition. Only happens when combining transition +
// keep-alive + HOCs. (#4590)
oldElm . _leaveCb ? null : parentElm , nodeOps . nextSibling ( oldElm ) ) ;
// update parent placeholder node element, recursively
if ( isDef ( vnode . parent ) ) {
let ancestor = vnode . parent ;
const patchable = isPatchable ( vnode ) ;
while ( ancestor ) {
for ( let i = 0 ; i < cbs . destroy . length ; ++ i ) {
cbs . destroy [ i ] ( ancestor ) ;
}
ancestor . elm = vnode . elm ;
if ( patchable ) {
for ( let i = 0 ; i < cbs . create . length ; ++ i ) {
cbs . create [ i ] ( emptyNode , ancestor ) ;
}
// #6513
// invoke insert hooks that may have been merged by create hooks.
// e.g. for directives that uses the "inserted" hook.
const insert = ancestor . data . hook . insert ;
if ( insert . merged ) {
// start at index 1 to avoid re-invoking component mounted hook
// clone insert hooks to avoid being mutated during iteration.
// e.g. for customed directives under transition group.
const cloned = insert . fns . slice ( 1 ) ;
for ( let i = 0 ; i < cloned . length ; i ++ ) {
cloned [ i ] ( ) ;
}
}
}
else {
registerRef ( ancestor ) ;
}
ancestor = ancestor . parent ;
}
}
// destroy old node
if ( isDef ( parentElm ) ) {
removeVnodes ( [ oldVnode ] , 0 , 0 ) ;
}
else if ( isDef ( oldVnode . tag ) ) {
invokeDestroyHook ( oldVnode ) ;
}
}
}
invokeInsertHook ( vnode , insertedVnodeQueue , isInitialPatch ) ;
return vnode . elm ;
} ;
2023-12-18 13:12:25 +08:00
}
var directives = {
2024-01-16 21:26:16 +08:00
create : updateDirectives ,
update : updateDirectives ,
destroy : function unbindDirectives ( vnode ) {
// @ts-expect-error emptyNode is not VNodeWithData
updateDirectives ( vnode , emptyNode ) ;
}
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function updateDirectives ( oldVnode , vnode ) {
if ( oldVnode . data . directives || vnode . data . directives ) {
_update ( oldVnode , vnode ) ;
}
}
function _update ( oldVnode , vnode ) {
const isCreate = oldVnode === emptyNode ;
const isDestroy = vnode === emptyNode ;
const oldDirs = normalizeDirectives ( oldVnode . data . directives , oldVnode . context ) ;
const newDirs = normalizeDirectives ( vnode . data . directives , vnode . context ) ;
const dirsWithInsert = [ ] ;
const dirsWithPostpatch = [ ] ;
let key , oldDir , dir ;
for ( key in newDirs ) {
oldDir = oldDirs [ key ] ;
dir = newDirs [ key ] ;
if ( ! oldDir ) {
// new directive, bind
callHook ( dir , 'bind' , vnode , oldVnode ) ;
if ( dir . def && dir . def . inserted ) {
dirsWithInsert . push ( dir ) ;
}
}
else {
// existing directive, update
dir . oldValue = oldDir . value ;
dir . oldArg = oldDir . arg ;
callHook ( dir , 'update' , vnode , oldVnode ) ;
if ( dir . def && dir . def . componentUpdated ) {
dirsWithPostpatch . push ( dir ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( dirsWithInsert . length ) {
const callInsert = ( ) => {
for ( let i = 0 ; i < dirsWithInsert . length ; i ++ ) {
callHook ( dirsWithInsert [ i ] , 'inserted' , vnode , oldVnode ) ;
}
} ;
if ( isCreate ) {
mergeVNodeHook ( vnode , 'insert' , callInsert ) ;
}
else {
callInsert ( ) ;
}
}
if ( dirsWithPostpatch . length ) {
mergeVNodeHook ( vnode , 'postpatch' , ( ) => {
for ( let i = 0 ; i < dirsWithPostpatch . length ; i ++ ) {
callHook ( dirsWithPostpatch [ i ] , 'componentUpdated' , vnode , oldVnode ) ;
}
} ) ;
}
if ( ! isCreate ) {
for ( key in oldDirs ) {
if ( ! newDirs [ key ] ) {
// no longer present, unbind
callHook ( oldDirs [ key ] , 'unbind' , oldVnode , oldVnode , isDestroy ) ;
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
const emptyModifiers = Object . create ( null ) ;
function normalizeDirectives ( dirs , vm ) {
const res = Object . create ( null ) ;
if ( ! dirs ) {
// $flow-disable-line
return res ;
}
let i , dir ;
for ( i = 0 ; i < dirs . length ; i ++ ) {
dir = dirs [ i ] ;
if ( ! dir . modifiers ) {
// $flow-disable-line
dir . modifiers = emptyModifiers ;
}
res [ getRawDirName ( dir ) ] = dir ;
if ( vm . _setupState && vm . _setupState . _ _sfc ) {
const setupDef = dir . def || resolveAsset ( vm , '_setupState' , 'v-' + dir . name ) ;
if ( typeof setupDef === 'function' ) {
dir . def = {
bind : setupDef ,
update : setupDef ,
} ;
}
else {
dir . def = setupDef ;
}
}
dir . def = dir . def || resolveAsset ( vm . $options , 'directives' , dir . name , true ) ;
}
2023-12-18 13:12:25 +08:00
// $flow-disable-line
2024-01-16 21:26:16 +08:00
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getRawDirName ( dir ) {
return ( dir . rawName || ` ${ dir . name } . ${ Object . keys ( dir . modifiers || { } ).join('.')} ` ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function callHook ( dir , hook , vnode , oldVnode , isDestroy ) {
const fn = dir . def && dir . def [ hook ] ;
if ( fn ) {
try {
fn ( vnode . elm , dir , vnode , oldVnode , isDestroy ) ;
}
catch ( e ) {
handleError ( e , vnode . context , ` directive ${ dir . name } ${ hook } hook ` ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
var baseModules = [ ref , directives ] ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function updateAttrs ( oldVnode , vnode ) {
const opts = vnode . componentOptions ;
if ( isDef ( opts ) && opts . Ctor . options . inheritAttrs === false ) {
return ;
}
if ( isUndef ( oldVnode . data . attrs ) && isUndef ( vnode . data . attrs ) ) {
return ;
}
let key , cur , old ;
const elm = vnode . elm ;
const oldAttrs = oldVnode . data . attrs || { } ;
let attrs = vnode . data . attrs || { } ;
// clone observed objects, as the user probably wants to mutate it
if ( isDef ( attrs . _ _ob _ _ ) || isTrue ( attrs . _v _attr _proxy ) ) {
attrs = vnode . data . attrs = extend ( { } , attrs ) ;
}
for ( key in attrs ) {
cur = attrs [ key ] ;
old = oldAttrs [ key ] ;
if ( old !== cur ) {
setAttr ( elm , key , cur , vnode . data . pre ) ;
}
}
// #4391: in IE9, setting type can reset value for input[type=radio]
// #6666: IE/Edge forces progress value down to 1 before setting a max
/* istanbul ignore if */
if ( ( isIE || isEdge ) && attrs . value !== oldAttrs . value ) {
setAttr ( elm , 'value' , attrs . value ) ;
}
for ( key in oldAttrs ) {
if ( isUndef ( attrs [ key ] ) ) {
if ( isXlink ( key ) ) {
elm . removeAttributeNS ( xlinkNS , getXlinkProp ( key ) ) ;
}
else if ( ! isEnumeratedAttr ( key ) ) {
elm . removeAttribute ( key ) ;
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function setAttr ( el , key , value , isInPre ) {
if ( isInPre || el . tagName . indexOf ( '-' ) > - 1 ) {
baseSetAttr ( el , key , value ) ;
}
else if ( isBooleanAttr ( key ) ) {
// set attribute for blank value
// e.g. <option disabled>Select one</option>
if ( isFalsyAttrValue ( value ) ) {
el . removeAttribute ( key ) ;
}
else {
// technically allowfullscreen is a boolean attribute for <iframe>,
// but Flash expects a value of "true" when used on <embed> tag
value = key === 'allowfullscreen' && el . tagName === 'EMBED' ? 'true' : key ;
el . setAttribute ( key , value ) ;
}
}
else if ( isEnumeratedAttr ( key ) ) {
el . setAttribute ( key , convertEnumeratedValue ( key , value ) ) ;
}
else if ( isXlink ( key ) ) {
if ( isFalsyAttrValue ( value ) ) {
el . removeAttributeNS ( xlinkNS , getXlinkProp ( key ) ) ;
}
else {
el . setAttributeNS ( xlinkNS , key , value ) ;
}
}
else {
baseSetAttr ( el , key , value ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function baseSetAttr ( el , key , value ) {
if ( isFalsyAttrValue ( value ) ) {
el . removeAttribute ( key ) ;
}
else {
// #7138: IE10 & 11 fires input event when setting placeholder on
// <textarea>... block the first input event and remove the blocker
// immediately.
/* istanbul ignore if */
if ( isIE &&
! isIE9 &&
el . tagName === 'TEXTAREA' &&
key === 'placeholder' &&
value !== '' &&
! el . _ _ieph ) {
const blocker = e => {
e . stopImmediatePropagation ( ) ;
el . removeEventListener ( 'input' , blocker ) ;
} ;
el . addEventListener ( 'input' , blocker ) ;
// $flow-disable-line
el . _ _ieph = true ; /* IE placeholder patched */
}
el . setAttribute ( key , value ) ;
}
2023-12-18 13:12:25 +08:00
}
var attrs = {
2024-01-16 21:26:16 +08:00
create : updateAttrs ,
update : updateAttrs
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function updateClass ( oldVnode , vnode ) {
const el = vnode . elm ;
const data = vnode . data ;
const oldData = oldVnode . data ;
if ( isUndef ( data . staticClass ) &&
isUndef ( data . class ) &&
( isUndef ( oldData ) ||
( isUndef ( oldData . staticClass ) && isUndef ( oldData . class ) ) ) ) {
return ;
}
let cls = genClassForVnode ( vnode ) ;
// handle transition classes
const transitionClass = el . _transitionClasses ;
if ( isDef ( transitionClass ) ) {
cls = concat ( cls , stringifyClass ( transitionClass ) ) ;
}
// set the class
if ( cls !== el . _prevClass ) {
el . setAttribute ( 'class' , cls ) ;
el . _prevClass = cls ;
}
2023-12-18 13:12:25 +08:00
}
var klass = {
2024-01-16 21:26:16 +08:00
create : updateClass ,
update : updateClass
2023-12-18 13:12:25 +08:00
} ;
// in some cases, the event used has to be determined at runtime
// so we used some reserved tokens during compile.
2024-01-16 21:26:16 +08:00
const RANGE _TOKEN = '__r' ;
const CHECKBOX _RADIO _TOKEN = '__c' ;
2023-12-18 13:12:25 +08:00
// normalize v-model event tokens that can only be determined at runtime.
// it's important to place the event as the first in the array because
// the whole point is ensuring the v-model callback gets called before
// user-attached handlers.
2024-01-16 21:26:16 +08:00
function normalizeEvents ( on ) {
/* istanbul ignore if */
if ( isDef ( on [ RANGE _TOKEN ] ) ) {
// IE input[type=range] only supports `change` event
const event = isIE ? 'change' : 'input' ;
on [ event ] = [ ] . concat ( on [ RANGE _TOKEN ] , on [ event ] || [ ] ) ;
delete on [ RANGE _TOKEN ] ;
}
// This was originally intended to fix #4521 but no longer necessary
// after 2.5. Keeping it for backwards compat with generated code from < 2.4
/* istanbul ignore if */
if ( isDef ( on [ CHECKBOX _RADIO _TOKEN ] ) ) {
on . change = [ ] . concat ( on [ CHECKBOX _RADIO _TOKEN ] , on . change || [ ] ) ;
delete on [ CHECKBOX _RADIO _TOKEN ] ;
}
}
let target ;
function createOnceHandler ( event , handler , capture ) {
const _target = target ; // save current target element in closure
return function onceHandler ( ) {
const res = handler . apply ( null , arguments ) ;
if ( res !== null ) {
remove ( event , onceHandler , capture , _target ) ;
}
} ;
2023-12-18 13:12:25 +08:00
}
// #9446: Firefox <= 53 (in particular, ESR 52) has incorrect Event.timeStamp
// implementation and does not fire microtasks in between event propagation, so
// safe to exclude.
2024-01-16 21:26:16 +08:00
const useMicrotaskFix = isUsingMicroTask && ! ( isFF && Number ( isFF [ 1 ] ) <= 53 ) ;
function add ( name , handler , capture , passive ) {
// async edge case #6566: inner click event triggers patch, event handler
// attached to outer element during patch, and triggered again. This
// happens because browsers fire microtask ticks between event propagation.
// the solution is simple: we save the timestamp when a handler is attached,
// and the handler would only fire if the event passed to it was fired
// AFTER it was attached.
if ( useMicrotaskFix ) {
const attachedTimestamp = currentFlushTimestamp ;
const original = handler ;
//@ts-expect-error
handler = original . _wrapper = function ( e ) {
if (
// no bubbling, should always fire.
// this is just a safety net in case event.timeStamp is unreliable in
// certain weird environments...
e . target === e . currentTarget ||
// event is fired after handler attachment
e . timeStamp >= attachedTimestamp ||
// bail for environments that have buggy event.timeStamp implementations
// #9462 iOS 9 bug: event.timeStamp is 0 after history.pushState
// #9681 QtWebEngine event.timeStamp is negative value
e . timeStamp <= 0 ||
// #9448 bail if event is fired in another document in a multi-page
// electron/nw.js app, since event.timeStamp will be using a different
// starting reference
e . target . ownerDocument !== document ) {
return original . apply ( this , arguments ) ;
}
} ;
}
target . addEventListener ( name , handler , supportsPassive ? { capture , passive } : capture ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function remove ( name , handler , capture , _target ) {
( _target || target ) . removeEventListener ( name ,
//@ts-expect-error
handler . _wrapper || handler , capture ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function updateDOMListeners ( oldVnode , vnode ) {
if ( isUndef ( oldVnode . data . on ) && isUndef ( vnode . data . on ) ) {
return ;
}
const on = vnode . data . on || { } ;
const oldOn = oldVnode . data . on || { } ;
// vnode is empty when removing all listeners,
// and use old vnode dom element
target = vnode . elm || oldVnode . elm ;
normalizeEvents ( on ) ;
updateListeners ( on , oldOn , add , remove , createOnceHandler , vnode . context ) ;
target = undefined ;
2023-12-18 13:12:25 +08:00
}
var events = {
2024-01-16 21:26:16 +08:00
create : updateDOMListeners ,
update : updateDOMListeners ,
// @ts-expect-error emptyNode has actually data
destroy : ( vnode ) => updateDOMListeners ( vnode , emptyNode )
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
let svgContainer ;
function updateDOMProps ( oldVnode , vnode ) {
if ( isUndef ( oldVnode . data . domProps ) && isUndef ( vnode . data . domProps ) ) {
return ;
}
let key , cur ;
const elm = vnode . elm ;
const oldProps = oldVnode . data . domProps || { } ;
let props = vnode . data . domProps || { } ;
// clone observed objects, as the user probably wants to mutate it
if ( isDef ( props . _ _ob _ _ ) || isTrue ( props . _v _attr _proxy ) ) {
props = vnode . data . domProps = extend ( { } , props ) ;
}
for ( key in oldProps ) {
if ( ! ( key in props ) ) {
elm [ key ] = '' ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
for ( key in props ) {
cur = props [ key ] ;
// ignore children if the node has textContent or innerHTML,
// as these will throw away existing DOM nodes and cause removal errors
// on subsequent patches (#3360)
if ( key === 'textContent' || key === 'innerHTML' ) {
if ( vnode . children )
vnode . children . length = 0 ;
if ( cur === oldProps [ key ] )
continue ;
// #6601 work around Chrome version <= 55 bug where single textNode
// replaced by innerHTML/textContent retains its parentNode property
if ( elm . childNodes . length === 1 ) {
elm . removeChild ( elm . childNodes [ 0 ] ) ;
}
}
if ( key === 'value' && elm . tagName !== 'PROGRESS' ) {
// store value as _value as well since
// non-string values will be stringified
elm . _value = cur ;
// avoid resetting cursor position when value is the same
const strCur = isUndef ( cur ) ? '' : String ( cur ) ;
if ( shouldUpdateValue ( elm , strCur ) ) {
elm . value = strCur ;
}
}
else if ( key === 'innerHTML' &&
isSVG ( elm . tagName ) &&
isUndef ( elm . innerHTML ) ) {
// IE doesn't support innerHTML for SVG elements
svgContainer = svgContainer || document . createElement ( 'div' ) ;
svgContainer . innerHTML = ` <svg> ${ cur } </svg> ` ;
const svg = svgContainer . firstChild ;
while ( elm . firstChild ) {
elm . removeChild ( elm . firstChild ) ;
}
while ( svg . firstChild ) {
elm . appendChild ( svg . firstChild ) ;
}
}
else if (
// skip the update if old and new VDOM state is the same.
// `value` is handled separately because the DOM value may be temporarily
// out of sync with VDOM state due to focus, composition and modifiers.
// This #4521 by skipping the unnecessary `checked` update.
cur !== oldProps [ key ] ) {
// some property updates can throw
// e.g. `value` on <progress> w/ non-finite value
try {
elm [ key ] = cur ;
}
catch ( e ) { }
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function shouldUpdateValue ( elm , checkVal ) {
return (
//@ts-expect-error
! elm . composing &&
( elm . tagName === 'OPTION' ||
isNotInFocusAndDirty ( elm , checkVal ) ||
isDirtyWithModifiers ( elm , checkVal ) ) ) ;
}
function isNotInFocusAndDirty ( elm , checkVal ) {
// return true when textbox (.number and .trim) loses focus and its value is
// not equal to the updated value
let notInFocus = true ;
// #6157
// work around IE bug when accessing document.activeElement in an iframe
try {
notInFocus = document . activeElement !== elm ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
catch ( e ) { }
return notInFocus && elm . value !== checkVal ;
}
function isDirtyWithModifiers ( elm , newVal ) {
const value = elm . value ;
const modifiers = elm . _vModifiers ; // injected by v-model runtime
if ( isDef ( modifiers ) ) {
if ( modifiers . number ) {
return toNumber ( value ) !== toNumber ( newVal ) ;
}
if ( modifiers . trim ) {
return value . trim ( ) !== newVal . trim ( ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return value !== newVal ;
2023-12-18 13:12:25 +08:00
}
var domProps = {
2024-01-16 21:26:16 +08:00
create : updateDOMProps ,
update : updateDOMProps
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const parseStyleText = cached ( function ( cssText ) {
const res = { } ;
const listDelimiter = /;(?![^(]*\))/g ;
const propertyDelimiter = /:(.+)/ ;
cssText . split ( listDelimiter ) . forEach ( function ( item ) {
if ( item ) {
const tmp = item . split ( propertyDelimiter ) ;
tmp . length > 1 && ( res [ tmp [ 0 ] . trim ( ) ] = tmp [ 1 ] . trim ( ) ) ;
}
} ) ;
return res ;
2023-12-18 13:12:25 +08:00
} ) ;
// merge static and dynamic style data on the same vnode
2024-01-16 21:26:16 +08:00
function normalizeStyleData ( data ) {
const style = normalizeStyleBinding ( data . style ) ;
// static style is pre-processed into an object during compilation
// and is always a fresh object, so it's safe to merge into it
return data . staticStyle ? extend ( data . staticStyle , style ) : style ;
2023-12-18 13:12:25 +08:00
}
// normalize possible array / string values into Object
2024-01-16 21:26:16 +08:00
function normalizeStyleBinding ( bindingStyle ) {
if ( Array . isArray ( bindingStyle ) ) {
return toObject ( bindingStyle ) ;
}
if ( typeof bindingStyle === 'string' ) {
return parseStyleText ( bindingStyle ) ;
}
return bindingStyle ;
2023-12-18 13:12:25 +08:00
}
/ * *
* parent component style should be after child ' s
* so that parent component ' s style could override it
* /
2024-01-16 21:26:16 +08:00
function getStyle ( vnode , checkChild ) {
const res = { } ;
let styleData ;
if ( checkChild ) {
let childNode = vnode ;
while ( childNode . componentInstance ) {
childNode = childNode . componentInstance . _vnode ;
if ( childNode &&
childNode . data &&
( styleData = normalizeStyleData ( childNode . data ) ) ) {
extend ( res , styleData ) ;
}
}
}
if ( ( styleData = normalizeStyleData ( vnode . data ) ) ) {
2023-12-18 13:12:25 +08:00
extend ( res , styleData ) ;
}
2024-01-16 21:26:16 +08:00
let parentNode = vnode ;
// @ts-expect-error parentNode.parent not VNodeWithData
while ( ( parentNode = parentNode . parent ) ) {
if ( parentNode . data && ( styleData = normalizeStyleData ( parentNode . data ) ) ) {
extend ( res , styleData ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const cssVarRE = /^--/ ;
const importantRE = /\s*!important$/ ;
const setProp = ( el , name , val ) => {
/* istanbul ignore if */
if ( cssVarRE . test ( name ) ) {
el . style . setProperty ( name , val ) ;
}
else if ( importantRE . test ( val ) ) {
el . style . setProperty ( hyphenate ( name ) , val . replace ( importantRE , '' ) , 'important' ) ;
}
else {
const normalizedName = normalize ( name ) ;
if ( Array . isArray ( val ) ) {
// Support values array created by autoprefixer, e.g.
// {display: ["-webkit-box", "-ms-flexbox", "flex"]}
// Set them one by one, and the browser will only set those it can recognize
for ( let i = 0 , len = val . length ; i < len ; i ++ ) {
el . style [ normalizedName ] = val [ i ] ;
}
}
else {
el . style [ normalizedName ] = val ;
}
}
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const vendorNames = [ 'Webkit' , 'Moz' , 'ms' ] ;
let emptyStyle ;
const normalize = cached ( function ( prop ) {
emptyStyle = emptyStyle || document . createElement ( 'div' ) . style ;
prop = camelize ( prop ) ;
if ( prop !== 'filter' && prop in emptyStyle ) {
return prop ;
}
const capName = prop . charAt ( 0 ) . toUpperCase ( ) + prop . slice ( 1 ) ;
for ( let i = 0 ; i < vendorNames . length ; i ++ ) {
const name = vendorNames [ i ] + capName ;
if ( name in emptyStyle ) {
return name ;
}
}
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
function updateStyle ( oldVnode , vnode ) {
const data = vnode . data ;
const oldData = oldVnode . data ;
if ( isUndef ( data . staticStyle ) &&
isUndef ( data . style ) &&
isUndef ( oldData . staticStyle ) &&
isUndef ( oldData . style ) ) {
return ;
}
let cur , name ;
const el = vnode . elm ;
const oldStaticStyle = oldData . staticStyle ;
const oldStyleBinding = oldData . normalizedStyle || oldData . style || { } ;
// if static style exists, stylebinding already merged into it when doing normalizeStyleData
const oldStyle = oldStaticStyle || oldStyleBinding ;
const style = normalizeStyleBinding ( vnode . data . style ) || { } ;
// store normalized style under a different key for next diff
// make sure to clone it if it's reactive, since the user likely wants
// to mutate it.
vnode . data . normalizedStyle = isDef ( style . _ _ob _ _ ) ? extend ( { } , style ) : style ;
const newStyle = getStyle ( vnode , true ) ;
for ( name in oldStyle ) {
if ( isUndef ( newStyle [ name ] ) ) {
setProp ( el , name , '' ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
for ( name in newStyle ) {
cur = newStyle [ name ] ;
// ie9 setting to null has no effect, must use empty string
setProp ( el , name , cur == null ? '' : cur ) ;
2023-12-18 13:12:25 +08:00
}
}
var style = {
2024-01-16 21:26:16 +08:00
create : updateStyle ,
update : updateStyle
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const whitespaceRE = /\s+/ ;
2023-12-18 13:12:25 +08:00
/ * *
* Add class with compatibility for SVG since classList is not supported on
* SVG elements in IE
* /
2024-01-16 21:26:16 +08:00
function addClass ( el , cls ) {
/* istanbul ignore if */
if ( ! cls || ! ( cls = cls . trim ( ) ) ) {
return ;
}
/* istanbul ignore else */
if ( el . classList ) {
if ( cls . indexOf ( ' ' ) > - 1 ) {
cls . split ( whitespaceRE ) . forEach ( c => el . classList . add ( c ) ) ;
}
else {
el . classList . add ( cls ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
const cur = ` ${ el . getAttribute ( 'class' ) || '' } ` ;
if ( cur . indexOf ( ' ' + cls + ' ' ) < 0 ) {
el . setAttribute ( 'class' , ( cur + cls ) . trim ( ) ) ;
}
2023-12-18 13:12:25 +08:00
}
}
/ * *
* Remove class with compatibility for SVG since classList is not supported on
* SVG elements in IE
* /
2024-01-16 21:26:16 +08:00
function removeClass ( el , cls ) {
/* istanbul ignore if */
if ( ! cls || ! ( cls = cls . trim ( ) ) ) {
return ;
}
/* istanbul ignore else */
if ( el . classList ) {
if ( cls . indexOf ( ' ' ) > - 1 ) {
cls . split ( whitespaceRE ) . forEach ( c => el . classList . remove ( c ) ) ;
}
else {
el . classList . remove ( cls ) ;
}
if ( ! el . classList . length ) {
el . removeAttribute ( 'class' ) ;
}
}
else {
let cur = ` ${ el . getAttribute ( 'class' ) || '' } ` ;
const tar = ' ' + cls + ' ' ;
while ( cur . indexOf ( tar ) >= 0 ) {
cur = cur . replace ( tar , ' ' ) ;
}
cur = cur . trim ( ) ;
if ( cur ) {
el . setAttribute ( 'class' , cur ) ;
}
else {
el . removeAttribute ( 'class' ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function resolveTransition ( def ) {
if ( ! def ) {
return ;
}
/* istanbul ignore else */
if ( typeof def === 'object' ) {
const res = { } ;
if ( def . css !== false ) {
extend ( res , autoCssTransition ( def . name || 'v' ) ) ;
}
extend ( res , def ) ;
return res ;
}
else if ( typeof def === 'string' ) {
return autoCssTransition ( def ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const autoCssTransition = cached ( name => {
return {
enterClass : ` ${ name } -enter ` ,
enterToClass : ` ${ name } -enter-to ` ,
enterActiveClass : ` ${ name } -enter-active ` ,
leaveClass : ` ${ name } -leave ` ,
leaveToClass : ` ${ name } -leave-to ` ,
leaveActiveClass : ` ${ name } -leave-active `
} ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
const hasTransition = inBrowser && ! isIE9 ;
const TRANSITION = 'transition' ;
const ANIMATION = 'animation' ;
2023-12-18 13:12:25 +08:00
// Transition property/event sniffing
2024-01-16 21:26:16 +08:00
let transitionProp = 'transition' ;
let transitionEndEvent = 'transitionend' ;
let animationProp = 'animation' ;
let animationEndEvent = 'animationend' ;
2023-12-18 13:12:25 +08:00
if ( hasTransition ) {
2024-01-16 21:26:16 +08:00
/* istanbul ignore if */
if ( window . ontransitionend === undefined &&
window . onwebkittransitionend !== undefined ) {
transitionProp = 'WebkitTransition' ;
transitionEndEvent = 'webkitTransitionEnd' ;
}
if ( window . onanimationend === undefined &&
window . onwebkitanimationend !== undefined ) {
animationProp = 'WebkitAnimation' ;
animationEndEvent = 'webkitAnimationEnd' ;
}
2023-12-18 13:12:25 +08:00
}
// binding to window is necessary to make hot reload work in IE in strict mode
2024-01-16 21:26:16 +08:00
const raf = inBrowser
? window . requestAnimationFrame
? window . requestAnimationFrame . bind ( window )
: setTimeout
: /* istanbul ignore next */ /* istanbul ignore next */ fn => fn ( ) ;
function nextFrame ( fn ) {
raf ( ( ) => {
// @ts-expect-error
raf ( fn ) ;
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function addTransitionClass ( el , cls ) {
const transitionClasses = el . _transitionClasses || ( el . _transitionClasses = [ ] ) ;
if ( transitionClasses . indexOf ( cls ) < 0 ) {
transitionClasses . push ( cls ) ;
addClass ( el , cls ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function removeTransitionClass ( el , cls ) {
if ( el . _transitionClasses ) {
remove$2 ( el . _transitionClasses , cls ) ;
}
removeClass ( el , cls ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function whenTransitionEnds ( el , expectedType , cb ) {
const { type , timeout , propCount } = getTransitionInfo ( el , expectedType ) ;
if ( ! type )
return cb ( ) ;
const event = type === TRANSITION ? transitionEndEvent : animationEndEvent ;
let ended = 0 ;
const end = ( ) => {
el . removeEventListener ( event , onEnd ) ;
cb ( ) ;
} ;
const onEnd = e => {
if ( e . target === el ) {
if ( ++ ended >= propCount ) {
end ( ) ;
}
}
} ;
setTimeout ( ( ) => {
if ( ended < propCount ) {
end ( ) ;
}
} , timeout + 1 ) ;
el . addEventListener ( event , onEnd ) ;
}
const transformRE = /\b(transform|all)(,|$)/ ;
function getTransitionInfo ( el , expectedType ) {
const styles = window . getComputedStyle ( el ) ;
// JSDOM may return undefined for transition properties
const transitionDelays = ( styles [ transitionProp + 'Delay' ] || '' ) . split ( ', ' ) ;
const transitionDurations = ( styles [ transitionProp + 'Duration' ] || '' ) . split ( ', ' ) ;
const transitionTimeout = getTimeout ( transitionDelays , transitionDurations ) ;
const animationDelays = ( styles [ animationProp + 'Delay' ] || '' ) . split ( ', ' ) ;
const animationDurations = ( styles [ animationProp + 'Duration' ] || '' ) . split ( ', ' ) ;
const animationTimeout = getTimeout ( animationDelays , animationDurations ) ;
let type ;
let timeout = 0 ;
let propCount = 0 ;
/* istanbul ignore if */
if ( expectedType === TRANSITION ) {
if ( transitionTimeout > 0 ) {
type = TRANSITION ;
timeout = transitionTimeout ;
propCount = transitionDurations . length ;
}
}
else if ( expectedType === ANIMATION ) {
if ( animationTimeout > 0 ) {
type = ANIMATION ;
timeout = animationTimeout ;
propCount = animationDurations . length ;
}
}
else {
timeout = Math . max ( transitionTimeout , animationTimeout ) ;
type =
timeout > 0
? transitionTimeout > animationTimeout
? TRANSITION
: ANIMATION
: null ;
propCount = type
? type === TRANSITION
? transitionDurations . length
: animationDurations . length
: 0 ;
}
const hasTransform = type === TRANSITION && transformRE . test ( styles [ transitionProp + 'Property' ] ) ;
return {
type ,
timeout ,
propCount ,
hasTransform
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getTimeout ( delays , durations ) {
/* istanbul ignore next */
while ( delays . length < durations . length ) {
delays = delays . concat ( delays ) ;
}
return Math . max . apply ( null , durations . map ( ( d , i ) => {
return toMs ( d ) + toMs ( delays [ i ] ) ;
} ) ) ;
2023-12-18 13:12:25 +08:00
}
// Old versions of Chromium (below 61.0.3163.100) formats floating pointer numbers
// in a locale-dependent way, using a comma instead of a dot.
// If comma is not replaced with a dot, the input will be rounded down (i.e. acting
// as a floor function) causing unexpected behaviors
2024-01-16 21:26:16 +08:00
function toMs ( s ) {
return Number ( s . slice ( 0 , - 1 ) . replace ( ',' , '.' ) ) * 1000 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function enter ( vnode , toggleDisplay ) {
const el = vnode . elm ;
// call leave callback now
if ( isDef ( el . _leaveCb ) ) {
el . _leaveCb . cancelled = true ;
el . _leaveCb ( ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const data = resolveTransition ( vnode . data . transition ) ;
if ( isUndef ( data ) ) {
return ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/* istanbul ignore if */
if ( isDef ( el . _enterCb ) || el . nodeType !== 1 ) {
return ;
}
const { css , type , enterClass , enterToClass , enterActiveClass , appearClass , appearToClass , appearActiveClass , beforeEnter , enter , afterEnter , enterCancelled , beforeAppear , appear , afterAppear , appearCancelled , duration } = data ;
// activeInstance will always be the <transition> component managing this
// transition. One edge case to check is when the <transition> is placed
// as the root node of a child component. In that case we need to check
// <transition>'s parent for appear check.
let context = activeInstance ;
let transitionNode = activeInstance . $vnode ;
while ( transitionNode && transitionNode . parent ) {
context = transitionNode . context ;
transitionNode = transitionNode . parent ;
}
const isAppear = ! context . _isMounted || ! vnode . isRootInsert ;
if ( isAppear && ! appear && appear !== '' ) {
return ;
}
const startClass = isAppear && appearClass ? appearClass : enterClass ;
const activeClass = isAppear && appearActiveClass ? appearActiveClass : enterActiveClass ;
const toClass = isAppear && appearToClass ? appearToClass : enterToClass ;
const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter ;
const enterHook = isAppear ? ( isFunction ( appear ) ? appear : enter ) : enter ;
const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter ;
const enterCancelledHook = isAppear
? appearCancelled || enterCancelled
: enterCancelled ;
const explicitEnterDuration = toNumber ( isObject ( duration ) ? duration . enter : duration ) ;
if ( explicitEnterDuration != null ) {
checkDuration ( explicitEnterDuration , 'enter' , vnode ) ;
}
const expectsCSS = css !== false && ! isIE9 ;
const userWantsControl = getHookArgumentsLength ( enterHook ) ;
const cb = ( el . _enterCb = once ( ( ) => {
if ( expectsCSS ) {
removeTransitionClass ( el , toClass ) ;
removeTransitionClass ( el , activeClass ) ;
}
// @ts-expect-error
if ( cb . cancelled ) {
if ( expectsCSS ) {
removeTransitionClass ( el , startClass ) ;
}
enterCancelledHook && enterCancelledHook ( el ) ;
}
else {
afterEnterHook && afterEnterHook ( el ) ;
}
el . _enterCb = null ;
} ) ) ;
if ( ! vnode . data . show ) {
// remove pending leave element on enter by injecting an insert hook
mergeVNodeHook ( vnode , 'insert' , ( ) => {
const parent = el . parentNode ;
const pendingNode = parent && parent . _pending && parent . _pending [ vnode . key ] ;
if ( pendingNode &&
pendingNode . tag === vnode . tag &&
pendingNode . elm . _leaveCb ) {
pendingNode . elm . _leaveCb ( ) ;
}
enterHook && enterHook ( el , cb ) ;
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// start enter transition
beforeEnterHook && beforeEnterHook ( el ) ;
2023-12-18 13:12:25 +08:00
if ( expectsCSS ) {
2024-01-16 21:26:16 +08:00
addTransitionClass ( el , startClass ) ;
addTransitionClass ( el , activeClass ) ;
nextFrame ( ( ) => {
removeTransitionClass ( el , startClass ) ;
// @ts-expect-error
if ( ! cb . cancelled ) {
addTransitionClass ( el , toClass ) ;
if ( ! userWantsControl ) {
if ( isValidDuration ( explicitEnterDuration ) ) {
setTimeout ( cb , explicitEnterDuration ) ;
}
else {
whenTransitionEnds ( el , type , cb ) ;
}
}
}
} ) ;
}
if ( vnode . data . show ) {
toggleDisplay && toggleDisplay ( ) ;
enterHook && enterHook ( el , cb ) ;
}
2023-12-18 13:12:25 +08:00
if ( ! expectsCSS && ! userWantsControl ) {
2024-01-16 21:26:16 +08:00
cb ( ) ;
}
}
function leave ( vnode , rm ) {
const el = vnode . elm ;
// call enter callback now
if ( isDef ( el . _enterCb ) ) {
el . _enterCb . cancelled = true ;
el . _enterCb ( ) ;
}
const data = resolveTransition ( vnode . data . transition ) ;
if ( isUndef ( data ) || el . nodeType !== 1 ) {
return rm ( ) ;
}
/* istanbul ignore if */
if ( isDef ( el . _leaveCb ) ) {
return ;
}
const { css , type , leaveClass , leaveToClass , leaveActiveClass , beforeLeave , leave , afterLeave , leaveCancelled , delayLeave , duration } = data ;
const expectsCSS = css !== false && ! isIE9 ;
const userWantsControl = getHookArgumentsLength ( leave ) ;
const explicitLeaveDuration = toNumber ( isObject ( duration ) ? duration . leave : duration ) ;
if ( isDef ( explicitLeaveDuration ) ) {
checkDuration ( explicitLeaveDuration , 'leave' , vnode ) ;
}
const cb = ( el . _leaveCb = once ( ( ) => {
if ( el . parentNode && el . parentNode . _pending ) {
el . parentNode . _pending [ vnode . key ] = null ;
}
if ( expectsCSS ) {
removeTransitionClass ( el , leaveToClass ) ;
removeTransitionClass ( el , leaveActiveClass ) ;
}
// @ts-expect-error
if ( cb . cancelled ) {
if ( expectsCSS ) {
removeTransitionClass ( el , leaveClass ) ;
}
leaveCancelled && leaveCancelled ( el ) ;
}
else {
rm ( ) ;
afterLeave && afterLeave ( el ) ;
}
el . _leaveCb = null ;
} ) ) ;
if ( delayLeave ) {
delayLeave ( performLeave ) ;
}
else {
performLeave ( ) ;
}
function performLeave ( ) {
// the delayed leave may have already been cancelled
// @ts-expect-error
if ( cb . cancelled ) {
return ;
}
// record leaving element
if ( ! vnode . data . show && el . parentNode ) {
( el . parentNode . _pending || ( el . parentNode . _pending = { } ) ) [ vnode . key ] =
vnode ;
}
beforeLeave && beforeLeave ( el ) ;
if ( expectsCSS ) {
addTransitionClass ( el , leaveClass ) ;
addTransitionClass ( el , leaveActiveClass ) ;
nextFrame ( ( ) => {
removeTransitionClass ( el , leaveClass ) ;
// @ts-expect-error
if ( ! cb . cancelled ) {
addTransitionClass ( el , leaveToClass ) ;
if ( ! userWantsControl ) {
if ( isValidDuration ( explicitLeaveDuration ) ) {
setTimeout ( cb , explicitLeaveDuration ) ;
}
else {
whenTransitionEnds ( el , type , cb ) ;
}
}
}
} ) ;
}
leave && leave ( el , cb ) ;
if ( ! expectsCSS && ! userWantsControl ) {
cb ( ) ;
}
2023-12-18 13:12:25 +08:00
}
}
// only used in dev mode
2024-01-16 21:26:16 +08:00
function checkDuration ( val , name , vnode ) {
if ( typeof val !== 'number' ) {
warn ( ` <transition> explicit ${ name } duration is not a valid number - ` +
` got ${ JSON . stringify ( val ) } . ` , vnode . context ) ;
}
else if ( isNaN ( val ) ) {
warn ( ` <transition> explicit ${ name } duration is NaN - ` +
'the duration expression might be incorrect.' , vnode . context ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isValidDuration ( val ) {
return typeof val === 'number' && ! isNaN ( val ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Normalize a transition hook ' s argument length . The hook may be :
* - a merged hook ( invoker ) with the original in . fns
* - a wrapped component method ( check . _length )
* - a plain function ( . length )
* /
2024-01-16 21:26:16 +08:00
function getHookArgumentsLength ( fn ) {
if ( isUndef ( fn ) ) {
return false ;
}
// @ts-expect-error
const invokerFns = fn . fns ;
if ( isDef ( invokerFns ) ) {
// invoker
return getHookArgumentsLength ( Array . isArray ( invokerFns ) ? invokerFns [ 0 ] : invokerFns ) ;
}
else {
// @ts-expect-error
return ( fn . _length || fn . length ) > 1 ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function _enter ( _ , vnode ) {
2023-12-18 13:12:25 +08:00
if ( vnode . data . show !== true ) {
2024-01-16 21:26:16 +08:00
enter ( vnode ) ;
}
}
var transition = inBrowser
? {
create : _enter ,
activate : _enter ,
remove ( vnode , rm ) {
/* istanbul ignore else */
if ( vnode . data . show !== true ) {
// @ts-expect-error
leave ( vnode , rm ) ;
}
else {
rm ( ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
: { } ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
var platformModules = [ attrs , klass , events , domProps , style , transition ] ;
2023-12-18 13:12:25 +08:00
// the directive module should be applied last, after all
// built-in modules have been applied.
2024-01-16 21:26:16 +08:00
const modules = platformModules . concat ( baseModules ) ;
const patch = createPatchFunction ( { nodeOps , modules } ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Not type checking this file because flow doesn ' t like attaching
* properties to Elements .
* /
/* istanbul ignore if */
if ( isIE9 ) {
2024-01-16 21:26:16 +08:00
// http://www.matts411.com/post/internet-explorer-9-oninput/
document . addEventListener ( 'selectionchange' , ( ) => {
const el = document . activeElement ;
// @ts-expect-error
if ( el && el . vmodel ) {
trigger ( el , 'input' ) ;
}
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const directive = {
inserted ( el , binding , vnode , oldVnode ) {
if ( vnode . tag === 'select' ) {
// #6903
if ( oldVnode . elm && ! oldVnode . elm . _vOptions ) {
mergeVNodeHook ( vnode , 'postpatch' , ( ) => {
directive . componentUpdated ( el , binding , vnode ) ;
} ) ;
}
else {
setSelected ( el , binding , vnode . context ) ;
}
el . _vOptions = [ ] . map . call ( el . options , getValue ) ;
}
else if ( vnode . tag === 'textarea' || isTextInputType ( el . type ) ) {
el . _vModifiers = binding . modifiers ;
if ( ! binding . modifiers . lazy ) {
el . addEventListener ( 'compositionstart' , onCompositionStart ) ;
el . addEventListener ( 'compositionend' , onCompositionEnd ) ;
// Safari < 10.2 & UIWebView doesn't fire compositionend when
// switching focus before confirming composition choice
// this also fixes the issue where some browsers e.g. iOS Chrome
// fires "change" instead of "input" on autocomplete.
el . addEventListener ( 'change' , onCompositionEnd ) ;
/* istanbul ignore if */
if ( isIE9 ) {
el . vmodel = true ;
}
}
}
} ,
componentUpdated ( el , binding , vnode ) {
if ( vnode . tag === 'select' ) {
setSelected ( el , binding , vnode . context ) ;
// in case the options rendered by v-for have changed,
// it's possible that the value is out-of-sync with the rendered options.
// detect such cases and filter out values that no longer has a matching
// option in the DOM.
const prevOptions = el . _vOptions ;
const curOptions = ( el . _vOptions = [ ] . map . call ( el . options , getValue ) ) ;
if ( curOptions . some ( ( o , i ) => ! looseEqual ( o , prevOptions [ i ] ) ) ) {
// trigger change event if
// no matching option found for at least one value
const needReset = el . multiple
? binding . value . some ( v => hasNoMatchingOption ( v , curOptions ) )
: binding . value !== binding . oldValue &&
hasNoMatchingOption ( binding . value , curOptions ) ;
if ( needReset ) {
trigger ( el , 'change' ) ;
}
}
2023-12-18 13:12:25 +08:00
}
}
} ;
2024-01-16 21:26:16 +08:00
function setSelected ( el , binding , vm ) {
actuallySetSelected ( el , binding , vm ) ;
/* istanbul ignore if */
if ( isIE || isEdge ) {
setTimeout ( ( ) => {
actuallySetSelected ( el , binding , vm ) ;
} , 0 ) ;
}
}
function actuallySetSelected ( el , binding , vm ) {
const value = binding . value ;
const isMultiple = el . multiple ;
if ( isMultiple && ! Array . isArray ( value ) ) {
warn ( ` <select multiple v-model=" ${ binding . expression } "> ` +
` expects an Array value for its binding, but got ${ Object . prototype . toString
. call ( value )
. slice ( 8 , - 1 ) } ` , vm);
return ;
}
let selected , option ;
for ( let i = 0 , l = el . options . length ; i < l ; i ++ ) {
option = el . options [ i ] ;
if ( isMultiple ) {
selected = looseIndexOf ( value , getValue ( option ) ) > - 1 ;
if ( option . selected !== selected ) {
option . selected = selected ;
}
}
else {
if ( looseEqual ( getValue ( option ) , value ) ) {
if ( el . selectedIndex !== i ) {
el . selectedIndex = i ;
}
return ;
}
}
}
if ( ! isMultiple ) {
el . selectedIndex = - 1 ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function hasNoMatchingOption ( value , options ) {
return options . every ( o => ! looseEqual ( o , value ) ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getValue ( option ) {
return '_value' in option ? option . _value : option . value ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function onCompositionStart ( e ) {
e . target . composing = true ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function onCompositionEnd ( e ) {
// prevent triggering an input event for no reason
if ( ! e . target . composing )
return ;
e . target . composing = false ;
trigger ( e . target , 'input' ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function trigger ( el , type ) {
const e = document . createEvent ( 'HTMLEvents' ) ;
e . initEvent ( type , true , true ) ;
el . dispatchEvent ( e ) ;
2023-12-18 13:12:25 +08:00
}
// recursively search for possible transition defined inside the component root
2024-01-16 21:26:16 +08:00
function locateNode ( vnode ) {
// @ts-expect-error
return vnode . componentInstance && ( ! vnode . data || ! vnode . data . transition )
? locateNode ( vnode . componentInstance . _vnode )
: vnode ;
2023-12-18 13:12:25 +08:00
}
var show = {
2024-01-16 21:26:16 +08:00
bind ( el , { value } , vnode ) {
vnode = locateNode ( vnode ) ;
const transition = vnode . data && vnode . data . transition ;
const originalDisplay = ( el . _ _vOriginalDisplay =
el . style . display === 'none' ? '' : el . style . display ) ;
if ( value && transition ) {
vnode . data . show = true ;
enter ( vnode , ( ) => {
el . style . display = originalDisplay ;
} ) ;
}
else {
el . style . display = value ? originalDisplay : 'none' ;
}
} ,
update ( el , { value , oldValue } , vnode ) {
/* istanbul ignore if */
if ( ! value === ! oldValue )
return ;
vnode = locateNode ( vnode ) ;
const transition = vnode . data && vnode . data . transition ;
if ( transition ) {
vnode . data . show = true ;
if ( value ) {
enter ( vnode , ( ) => {
el . style . display = el . _ _vOriginalDisplay ;
} ) ;
}
else {
leave ( vnode , ( ) => {
el . style . display = 'none' ;
} ) ;
}
}
else {
el . style . display = value ? el . _ _vOriginalDisplay : 'none' ;
}
} ,
unbind ( el , binding , vnode , oldVnode , isDestroy ) {
if ( ! isDestroy ) {
el . style . display = el . _ _vOriginalDisplay ;
}
2023-12-18 13:12:25 +08:00
}
} ;
var platformDirectives = {
2024-01-16 21:26:16 +08:00
model : directive ,
show
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
// Provides transition support for a single element/component.
const transitionProps = {
name : String ,
appear : Boolean ,
css : Boolean ,
mode : String ,
type : String ,
enterClass : String ,
leaveClass : String ,
enterToClass : String ,
leaveToClass : String ,
enterActiveClass : String ,
leaveActiveClass : String ,
appearClass : String ,
appearActiveClass : String ,
appearToClass : String ,
duration : [ Number , String , Object ]
2023-12-18 13:12:25 +08:00
} ;
// in case the child is also an abstract component, e.g. <keep-alive>
// we want to recursively retrieve the real component to be rendered
2024-01-16 21:26:16 +08:00
function getRealChild ( vnode ) {
const compOptions = vnode && vnode . componentOptions ;
if ( compOptions && compOptions . Ctor . options . abstract ) {
return getRealChild ( getFirstComponentChild ( compOptions . children ) ) ;
}
else {
return vnode ;
}
}
function extractTransitionData ( comp ) {
const data = { } ;
const options = comp . $options ;
// props
for ( const key in options . propsData ) {
data [ key ] = comp [ key ] ;
}
// events.
// extract listeners and pass them directly to the transition methods
const listeners = options . _parentListeners ;
for ( const key in listeners ) {
data [ camelize ( key ) ] = listeners [ key ] ;
}
return data ;
}
function placeholder ( h , rawChild ) {
// @ts-expect-error
if ( /\d-keep-alive$/ . test ( rawChild . tag ) ) {
return h ( 'keep-alive' , {
props : rawChild . componentOptions . propsData
} ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function hasParentTransition ( vnode ) {
while ( ( vnode = vnode . parent ) ) {
if ( vnode . data . transition ) {
return true ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function isSameChild ( child , oldChild ) {
return oldChild . key === child . key && oldChild . tag === child . tag ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const isNotTextNode = ( c ) => c . tag || isAsyncPlaceholder ( c ) ;
const isVShowDirective = d => d . name === 'show' ;
2023-12-18 13:12:25 +08:00
var Transition = {
2024-01-16 21:26:16 +08:00
name : 'transition' ,
props : transitionProps ,
abstract : true ,
render ( h ) {
let children = this . $slots . default ;
if ( ! children ) {
return ;
}
// filter out text nodes (possible whitespaces)
children = children . filter ( isNotTextNode ) ;
/* istanbul ignore if */
if ( ! children . length ) {
return ;
}
// warn multiple elements
if ( children . length > 1 ) {
warn ( '<transition> can only be used on a single element. Use ' +
'<transition-group> for lists.' , this . $parent ) ;
}
const mode = this . mode ;
// warn invalid mode
if ( mode && mode !== 'in-out' && mode !== 'out-in' ) {
warn ( 'invalid <transition> mode: ' + mode , this . $parent ) ;
}
const rawChild = children [ 0 ] ;
// if this is a component root node and the component's
// parent container node also has transition, skip.
if ( hasParentTransition ( this . $vnode ) ) {
return rawChild ;
}
// apply transition data to child
// use getRealChild() to ignore abstract components e.g. keep-alive
const child = getRealChild ( rawChild ) ;
/* istanbul ignore if */
if ( ! child ) {
return rawChild ;
}
if ( this . _leaving ) {
return placeholder ( h , rawChild ) ;
}
// ensure a key that is unique to the vnode type and to this transition
// component instance. This key will be used to remove pending leaving nodes
// during entering.
const id = ` __transition- ${ this . _uid } - ` ;
child . key =
child . key == null
? child . isComment
? id + 'comment'
: id + child . tag
: isPrimitive ( child . key )
? String ( child . key ) . indexOf ( id ) === 0
? child . key
: id + child . key
: child . key ;
const data = ( ( child . data || ( child . data = { } ) ) . transition =
extractTransitionData ( this ) ) ;
const oldRawChild = this . _vnode ;
const oldChild = getRealChild ( oldRawChild ) ;
// mark v-show
// so that the transition module can hand over the control to the directive
if ( child . data . directives && child . data . directives . some ( isVShowDirective ) ) {
child . data . show = true ;
}
if ( oldChild &&
oldChild . data &&
! isSameChild ( child , oldChild ) &&
! isAsyncPlaceholder ( oldChild ) &&
// #6687 component root is a comment node
! ( oldChild . componentInstance &&
oldChild . componentInstance . _vnode . isComment ) ) {
// replace old child transition data with fresh one
// important for dynamic transitions!
const oldData = ( oldChild . data . transition = extend ( { } , data ) ) ;
// handle transition mode
if ( mode === 'out-in' ) {
// return placeholder node and queue update when leave finishes
this . _leaving = true ;
mergeVNodeHook ( oldData , 'afterLeave' , ( ) => {
this . _leaving = false ;
this . $forceUpdate ( ) ;
} ) ;
return placeholder ( h , rawChild ) ;
}
else if ( mode === 'in-out' ) {
if ( isAsyncPlaceholder ( child ) ) {
return oldRawChild ;
}
let delayedLeave ;
const performLeave = ( ) => {
delayedLeave ( ) ;
} ;
mergeVNodeHook ( data , 'afterEnter' , performLeave ) ;
mergeVNodeHook ( data , 'enterCancelled' , performLeave ) ;
mergeVNodeHook ( oldData , 'delayLeave' , leave => {
delayedLeave = leave ;
} ) ;
}
}
return rawChild ;
2023-12-18 13:12:25 +08:00
}
} ;
2024-01-16 21:26:16 +08:00
// Provides transition support for list items.
const props = extend ( {
tag : String ,
moveClass : String
2023-12-18 13:12:25 +08:00
} , transitionProps ) ;
delete props . mode ;
var TransitionGroup = {
2024-01-16 21:26:16 +08:00
props ,
beforeMount ( ) {
const update = this . _update ;
this . _update = ( vnode , hydrating ) => {
const restoreActiveInstance = setActiveInstance ( this ) ;
// force removing pass
this . _ _patch _ _ ( this . _vnode , this . kept , false , // hydrating
true // removeOnly (!important, avoids unnecessary moves)
) ;
this . _vnode = this . kept ;
restoreActiveInstance ( ) ;
update . call ( this , vnode , hydrating ) ;
} ;
} ,
render ( h ) {
const tag = this . tag || this . $vnode . data . tag || 'span' ;
const map = Object . create ( null ) ;
const prevChildren = ( this . prevChildren = this . children ) ;
const rawChildren = this . $slots . default || [ ] ;
const children = ( this . children = [ ] ) ;
const transitionData = extractTransitionData ( this ) ;
for ( let i = 0 ; i < rawChildren . length ; i ++ ) {
const c = rawChildren [ i ] ;
if ( c . tag ) {
if ( c . key != null && String ( c . key ) . indexOf ( '__vlist' ) !== 0 ) {
children . push ( c ) ;
map [ c . key ] = c ;
( c . data || ( c . data = { } ) ) . transition = transitionData ;
}
else {
const opts = c . componentOptions ;
const name = opts
? getComponentName ( opts . Ctor . options ) || opts . tag || ''
: c . tag ;
warn ( ` <transition-group> children must be keyed: < ${ name } > ` ) ;
}
}
}
if ( prevChildren ) {
const kept = [ ] ;
const removed = [ ] ;
for ( let i = 0 ; i < prevChildren . length ; i ++ ) {
const c = prevChildren [ i ] ;
c . data . transition = transitionData ;
// @ts-expect-error .getBoundingClientRect is not typed in Node
c . data . pos = c . elm . getBoundingClientRect ( ) ;
if ( map [ c . key ] ) {
kept . push ( c ) ;
}
else {
removed . push ( c ) ;
}
}
this . kept = h ( tag , null , kept ) ;
this . removed = removed ;
}
return h ( tag , null , children ) ;
} ,
updated ( ) {
const children = this . prevChildren ;
const moveClass = this . moveClass || ( this . name || 'v' ) + '-move' ;
if ( ! children . length || ! this . hasMove ( children [ 0 ] . elm , moveClass ) ) {
return ;
}
// we divide the work into three loops to avoid mixing DOM reads and writes
// in each iteration - which helps prevent layout thrashing.
children . forEach ( callPendingCbs ) ;
children . forEach ( recordPosition ) ;
children . forEach ( applyTranslation ) ;
// force reflow to put everything in position
// assign to this to avoid being removed in tree-shaking
// $flow-disable-line
this . _reflow = document . body . offsetHeight ;
children . forEach ( ( c ) => {
if ( c . data . moved ) {
const el = c . elm ;
const s = el . style ;
addTransitionClass ( el , moveClass ) ;
s . transform = s . WebkitTransform = s . transitionDuration = '' ;
el . addEventListener ( transitionEndEvent , ( el . _moveCb = function cb ( e ) {
if ( e && e . target !== el ) {
return ;
}
if ( ! e || /transform$/ . test ( e . propertyName ) ) {
el . removeEventListener ( transitionEndEvent , cb ) ;
el . _moveCb = null ;
removeTransitionClass ( el , moveClass ) ;
}
} ) ) ;
}
} ) ;
} ,
methods : {
hasMove ( el , moveClass ) {
/* istanbul ignore if */
if ( ! hasTransition ) {
return false ;
}
/* istanbul ignore if */
if ( this . _hasMove ) {
return this . _hasMove ;
}
// Detect whether an element with the move class applied has
// CSS transitions. Since the element may be inside an entering
// transition at this very moment, we make a clone of it and remove
// all other transition classes applied to ensure only the move class
// is applied.
const clone = el . cloneNode ( ) ;
if ( el . _transitionClasses ) {
el . _transitionClasses . forEach ( ( cls ) => {
removeClass ( clone , cls ) ;
} ) ;
}
addClass ( clone , moveClass ) ;
clone . style . display = 'none' ;
this . $el . appendChild ( clone ) ;
const info = getTransitionInfo ( clone ) ;
this . $el . removeChild ( clone ) ;
return ( this . _hasMove = info . hasTransform ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
} ;
function callPendingCbs ( c ) {
/* istanbul ignore if */
if ( c . elm . _moveCb ) {
c . elm . _moveCb ( ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/* istanbul ignore if */
if ( c . elm . _enterCb ) {
c . elm . _enterCb ( ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function recordPosition ( c ) {
c . data . newPos = c . elm . getBoundingClientRect ( ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function applyTranslation ( c ) {
const oldPos = c . data . pos ;
const newPos = c . data . newPos ;
const dx = oldPos . left - newPos . left ;
const dy = oldPos . top - newPos . top ;
if ( dx || dy ) {
c . data . moved = true ;
const s = c . elm . style ;
s . transform = s . WebkitTransform = ` translate( ${ dx } px, ${ dy } px) ` ;
s . transitionDuration = '0s' ;
}
2023-12-18 13:12:25 +08:00
}
var platformComponents = {
2024-01-16 21:26:16 +08:00
Transition ,
TransitionGroup
2023-12-18 13:12:25 +08:00
} ;
// install platform specific utils
Vue . config . mustUseProp = mustUseProp ;
Vue . config . isReservedTag = isReservedTag ;
Vue . config . isReservedAttr = isReservedAttr ;
Vue . config . getTagNamespace = getTagNamespace ;
Vue . config . isUnknownElement = isUnknownElement ;
// install platform runtime directives & components
extend ( Vue . options . directives , platformDirectives ) ;
extend ( Vue . options . components , platformComponents ) ;
// install platform patch function
Vue . prototype . _ _patch _ _ = inBrowser ? patch : noop ;
// public mount method
2024-01-16 21:26:16 +08:00
Vue . prototype . $mount = function ( el , hydrating ) {
el = el && inBrowser ? query ( el ) : undefined ;
return mountComponent ( this , el , hydrating ) ;
2023-12-18 13:12:25 +08:00
} ;
// devtools global hook
/* istanbul ignore next */
if ( inBrowser ) {
2024-01-16 21:26:16 +08:00
setTimeout ( ( ) => {
if ( config . devtools ) {
if ( devtools ) {
devtools . emit ( 'init' , Vue ) ;
}
else {
// @ts-expect-error
console [ console . info ? 'info' : 'log' ] ( 'Download the Vue Devtools extension for a better development experience:\n' +
'https://github.com/vuejs/vue-devtools' ) ;
}
}
if ( config . productionTip !== false &&
typeof console !== 'undefined' ) {
// @ts-expect-error
console [ console . info ? 'info' : 'log' ] ( ` You are running Vue in development mode. \n ` +
` Make sure to turn on production mode when deploying for production. \n ` +
` See more tips at https://vuejs.org/guide/deployment.html ` ) ;
}
} , 0 ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
extend ( Vue , vca ) ;
2023-12-18 13:12:25 +08:00
module . exports = Vue ;