vue
vue源码逐行注释分析+40多m的vue源码程序流程图思维导图(vue source code line by line annotation analysis +40 + m vue source code process flow chart mind map)
Top Related Projects
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
The Intuitive Vue Framework.
Quasar Framework - Build high-performance VueJS user interfaces in record time
🐉 Vue Component Framework
A Vue.js 2.0 UI Toolkit for Web
Quick Overview
The ygs-code/vue repository is a fork of the official Vue.js framework, maintained by a community contributor. It appears to be an experimental or learning-focused version of Vue, potentially used for exploring modifications or enhancements to the original framework.
Pros
- Provides a platform for experimenting with Vue.js internals
- Allows developers to study and modify Vue's source code directly
- May include custom features or optimizations not present in the official Vue repository
Cons
- Not the official Vue.js repository, which may lead to confusion
- Likely not as well-maintained or up-to-date as the official Vue project
- May lack proper documentation or community support compared to the official Vue
Code Examples
As this is a fork of the Vue.js framework and not a standalone library, specific code examples are not applicable. Users would typically use this repository as a reference or for contributing to Vue.js development rather than importing it directly into their projects.
Getting Started
Since this is a fork of the Vue.js framework and not intended for direct use in projects, there are no specific getting started instructions. Developers interested in exploring or contributing to this fork should follow these general steps:
-
Clone the repository:
git clone https://github.com/ygs-code/vue.git
-
Install dependencies:
cd vue npm install
-
Build the project:
npm run build
-
Explore the source code and make modifications as needed.
-
Run tests to ensure changes don't break existing functionality:
npm run test
Note: It's recommended to use the official Vue.js repository for actual project development unless you have a specific reason to use this fork.
Competitor Comparisons
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Pros of Vue
- Official Vue.js repository with extensive documentation and community support
- Regularly updated with new features and bug fixes
- Comprehensive test suite ensuring stability and reliability
Cons of Vue
- Larger codebase and more complex architecture
- Steeper learning curve for contributors due to its extensive feature set
- Stricter contribution guidelines and review process
Code Comparison
Vue (official):
export function createApp(rootComponent, rootProps = null) {
const app = ensureRenderer().createApp(rootComponent, rootProps)
const { mount } = app
app.mount = (containerOrSelector) => {
// ...
}
return app
}
ygs-code/vue:
export function createApp (component, props) {
const app = ensureRenderer().createApp(component, props)
app.mount = (el) => {
// ...
}
return app
}
Summary
The official Vue repository offers a more comprehensive and well-maintained codebase with extensive community support. However, it may be more complex for beginners to contribute to. The ygs-code/vue repository appears to be a simplified version or fork of Vue, potentially easier to understand but lacking the full feature set and ongoing development of the official repository. The code comparison shows similar structure but with slight differences in implementation details.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
Pros of core
- Official Vue.js repository with active development and frequent updates
- Extensive documentation and community support
- Optimized performance and smaller bundle size
Cons of core
- Steeper learning curve for beginners
- Less flexibility for customization compared to ygs-code/vue
Code Comparison
core:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
vue:
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
Key Differences
- core uses the Composition API, while vue primarily uses the Options API
- core has better TypeScript support and integration
- vue may be easier for beginners to understand and modify
- core offers improved performance and tree-shaking capabilities
Conclusion
While core is the official and more actively maintained repository with better performance and modern features, vue may be more suitable for those who prefer the traditional Vue 2.x style or need more customization options. The choice between the two depends on project requirements and developer preferences.
The Intuitive Vue Framework.
Pros of Nuxt
- More comprehensive framework with built-in server-side rendering (SSR) capabilities
- Extensive ecosystem with official modules and plugins
- Better performance optimization out-of-the-box
Cons of Nuxt
- Steeper learning curve due to additional concepts and conventions
- Less flexibility for custom configurations compared to a basic Vue setup
Code Comparison
Nuxt:
// nuxt.config.js
export default {
modules: ['@nuxtjs/axios'],
axios: {
baseURL: 'https://api.example.com'
}
}
Vue:
// main.js
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.$http = axios.create({
baseURL: 'https://api.example.com'
})
Key Differences
- Nuxt provides a more opinionated structure and built-in features
- Vue offers more flexibility but requires manual setup for advanced features
- Nuxt excels in SSR and static site generation, while Vue is primarily client-side rendering focused
- Nuxt has a larger file size due to additional features, while Vue is more lightweight
Use Cases
- Choose Nuxt for large-scale applications requiring SSR or static site generation
- Opt for Vue for smaller projects or when more control over the application structure is needed
Community and Support
- Both projects have active communities and regular updates
- Nuxt has more official resources and documentation for its specific features
- Vue has a larger overall ecosystem due to its broader adoption
Quasar Framework - Build high-performance VueJS user interfaces in record time
Pros of Quasar
- Comprehensive UI framework with a large set of pre-built components
- Cross-platform development capabilities (web, mobile, desktop)
- Active community and regular updates
Cons of Quasar
- Steeper learning curve due to its extensive feature set
- Larger bundle size compared to Vue alone
- Opinionated structure may limit flexibility for some projects
Code Comparison
Vue (basic component):
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
}
}
}
</script>
Quasar (basic component):
<template>
<q-page class="flex flex-center">
<q-btn color="primary" label="Hello, Quasar!" />
</q-page>
</template>
<script>
export default {
name: 'PageIndex'
}
</script>
The code comparison shows that Quasar components typically use Quasar-specific elements (like q-page
and q-btn
) with built-in styling and functionality, while Vue components are more bare-bones and require custom styling and implementation of features.
🐉 Vue Component Framework
Pros of Vuetify
- Comprehensive UI component library with Material Design
- Extensive documentation and active community support
- Regular updates and maintenance
Cons of Vuetify
- Larger bundle size due to extensive component library
- Steeper learning curve for customization
- Opinionated design system may limit flexibility
Code Comparison
Vuetify component usage:
<template>
<v-app>
<v-btn color="primary">Click me</v-btn>
</v-app>
</template>
Vue component usage:
<template>
<div>
<button class="btn btn-primary">Click me</button>
</div>
</template>
Key Differences
- Vuetify provides pre-built, styled components, while Vue requires custom styling
- Vuetify enforces a specific design system, whereas Vue allows more flexibility
- Vuetify offers a more opinionated structure, while Vue is more lightweight and customizable
Use Cases
- Vuetify: Rapid development of Material Design-based applications
- Vue: Custom designs or lightweight applications with specific requirements
Community and Ecosystem
- Vuetify: Large community, extensive third-party integrations
- Vue: Broader ecosystem, more flexibility in choosing additional libraries
A Vue.js 2.0 UI Toolkit for Web
Pros of Element
- Comprehensive UI component library with extensive documentation
- Active development and large community support
- Well-established project with regular updates and releases
Cons of Element
- Larger bundle size due to extensive component library
- Steeper learning curve for developers new to component libraries
- Less flexibility for custom styling compared to building from scratch
Code Comparison
Element (component usage):
<template>
<el-button type="primary" @click="handleClick">Click me</el-button>
</template>
<script>
export default {
methods: {
handleClick() {
// Handle click event
}
}
}
</script>
vue (custom implementation):
<template>
<button class="custom-button" @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
// Handle click event
}
}
}
</script>
The code comparison shows that Element provides pre-built components with built-in functionality, while vue requires custom implementation of components and styles. Element offers a more streamlined development process for common UI elements, but vue allows for greater customization and control over the implementation details.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
English document: https://github.com/ygs-code/vue/blob/master/README_EN.md
å¼å§
vueæºç ä¸ä½æ¶é´å·®ä¸å¤çäºä¸å¹´ï¼ä»¥åå¨ç½ä¸æ¾å¸åï¼åç°å¾å¤å¸åå¾é¶æ£ï¼é½æ¯ä¸é¨åä¸é¨åè¯´ï¼æç« çå¾å¤ï¼æä»¥èªå·±ä¸å®å³å®ä¸è¡è¡çï¼ç»è¿èªå·±åæä¸åªåï¼ç°å¨åºæ¬çå®äº ãè¿ä¸ªvueæºç éè¡åæï¼æåºæ¬æ¯ä¸è¡é½æä¸æ³¨éï¼å 䏿´ä¸ªæ¡æ¶çæµç¨æç»´å¯¼å¾ï¼åºæ¬ä¸æ¯å°ç½ä¹è½çæçvueæºç äºã
说çé常ç详ç»ï¼éé¢çæºç 注éï¼æäºæ¯èªå·±å¤å¹´å¼åvueç»éªèè·å¾çï¼æäºæ¯èªå·±è·ä¸ä¸æç¨åºç¥éçï¼ å¦ææä¸è¶³çå°æ¹å¯ä»¥èç³»æQQ群 ï¼302817612 ä¿®æ¹ï¼æè åé®ä»¶ç»æ281113270@qq.com 谢谢ã 妿大家è§å¾ä¸é请å¨å¨å°ææï¼å¸®æç¹ä¸ä¸ªsatrï¼ä½ ä»¬çæ¯æå°±æ¯æçå¨åã
vue å¦ä½å»çvueæºç å¢ï¼å ¶å®mvvmæºç å¹¶æ²¡ææ³è±¡ä¸é£ä¹ç¥ç§ï¼ä»12å¹´å¼å§å°è³ä»mvvmåå±å·²ç»æäºåå å¹´åå²äºï¼ä»ä»¥åç´æ¥æä½domçjqå屿åå å¹´åå²ï¼ä½æ¯è¿åå å¹´åå²åå±ï¼å¹¶æ²¡æå¤å¤§çæ¹åï¼ææ³è¿æ¯é£äºï¼æ¨¡åè¿æ¯å为å 大åï¼
1.模æ¿è½¬æ¢ï¼
å°±æ¯æä»¬åç vue æ¨¡æ¿ æè æ¯ react jsx æä»¬é½å¯ä»¥çè§£æ¯æ¨¡æ¿ï¼ç¶åä»ä¼ç»è¿ 模æ¿ç¼è¯è½¬æ¢ï¼åvueçè¯æ¯è¿è¿ä¸ä¸ªæ¹æ³paseHTMLæ¹æ³è½¬æ¢æastæ ï¼éé¢çpaseHTMLç¨while å¾ªç¯æ¨¡æ¿ï¼ç¶åç»è¿æ£å å¹é å°vueæä»¤ï¼è¿ævueç屿§ï¼äºä»¶æ¹æ³çï¼æ¶éå°ä¸ä¸ªastæ ä¸ã
2.æ°æ®ç¸åºï¼
vueæ¯ä¸ä¸ªåæ°æ®ç¸åºçæ¡æ¶ï¼åºå±ç¨çæ¯Object.defineProperty çå¬åæææ°æ®æ¹åï¼ç¶åè°ç¨åè°æ¹æ³æ´æ°è§å¾æ´æ°ãåæ°æ®ç»å®åçæ¯ï¼obersve()æ¹æ³å¤ævalueæ²¡ææ²¡æ__ob___屿§å¹¶ä¸æ¯ä¸æ¯Obersveå®ä¾åçï¼ valueæ¯ä¸æ¯Vondeå®ä¾åçï¼å¦æä¸æ¯åè°ç¨Obersve å»ææ°æ®æ·»å å°è§å¯è ä¸ï¼ä¸ºæ°æ®æ·»å __ob__屿§ï¼ Obersve åè°ç¨defineReactiveæ¹æ³ï¼è¯¥æ¹æ³æ¯è¿æ¥Depåwactheræ¹æ³çä¸ä¸ªééï¼å©ç¨Object.definpropty() ä¸çgetåsetæ¹æ³ ç嬿°æ®ãgetæ¹æ³ä¸æ¯new Depè°ç¨depend()ã为depæ·»å ä¸ä¸ªwactherç±»ï¼watcherä¸æä¸ªæ¹æ³æ¯æ´æ°è§å¾çæ¯runè°ç¨update廿´æ°vonde ç¶åæ´æ°è§å¾ã ç¶åsetæ¹æ³å°±æ¯è°ç¨depä¸çnotify æ¹æ³è°ç¨wactherä¸çrun æ´æ°è§å¾
3.èædomï¼
vnodeï¼å¨vueç¨vnodeæ¯éè¿ ast对象ï¼å¨è½¬ä¹ævonde éè¦æ¸²æç彿°ï¼æ¯å¦_c('div' s('')) çè¿ç±»ç彿°ï¼ç¼è¯ævonde èædomãç¶åå°updataæ´æ°æ°æ® è°ç¨patch ævonde éè¿diffç®æ³åææ£çæ£çdomå ç´ ã
4.diifç®æ³ï¼
â vue2 çdiff ç®æ³æ¯æ·±åº¦ä¼å ç®æ³éåï¼ç¶å对æ¯ç®æ³æ¯éè¿ æ°æ§çvnode对æ¯å 对æ¯ä»ä»¬çåºæ¬å±æ§ï¼æ¯å¦key æ ç¾çï¼å¦ææ¯ç¸ååéè¿diffç®æ³å¯¹æ¯ç¶ådiffç®æ³æ¯æ°æ§çvnode对æ¯ï¼ç¶åæå个æéç´¢å¼ï¼ä¸¤ä¸ªæ°çvnodeå¼å§æéåæ°ç vnode ç»ææéï¼ä¸¤ä¸ªæ§çvnodeå¼å§æéåæ§ç vnode ç»ææéãç¶åå 夿vnodeæ¯å¦ä¸ºç©ºï¼å¦æä¸ºç©ºå°±å¾ä¸é´é æ¢ å¼å§çæé++ ç»æçæé --ãç¶å两头对æ¯ä¹åï¼å¨äº¤å对æ¯ï¼ç´å°æ¾ä¸å°ç¸åçvnodeä¹å妿å¤åºçå°±å é¤ï¼å¦æå°çè¯å°±æ°å¢ï¼ç¶å对æ¯å®ä¹å卿´æ°å°çå®domã
æºç å ¥å£æµç¨ vueæºç 解读æµç¨ 1.new Vue è°ç¨çæ¯ Vue.prototype._init ä»è¯¥å½æ°å¼å§ ç»è¿ $options åæ°åå¹¶ä¹å initLifecycle åå§åçå½å¨ææ å¿ åå§åäºä»¶ï¼åå§å渲æå½æ°ãåå§åç¶æå°±æ¯æ°æ®ãææ°æ®æ·»å å°è§å¯è ä¸å®ç°åæ°æ®ç»å®ã
new Vueå®ä¾åç¨åºå ¥å£
Vue.prototype._init = function (options) { //åå§å彿°
//... çç¥code
initLifecycle(vm); //åå§åçå½å¨æ æ å¿
initEvents(vm); //åå§åäºä»¶
initRender(vm); // åå§å渲æ
callHook(vm, 'beforeCreate'); //触åbeforeCreateé©å彿°
initInjections(vm); // resolve injections before data/props 卿°æ®/éå
·ä¹åè§£å³æ³¨å
¥é®é¢ //åå§å inject
initState(vm); // //åå§åç¶æ
initProvide(vm); // resolve provide after data/props è§£å³åæä¾æ°æ®/éå
· provide é项åºè¯¥æ¯ä¸ä¸ªå¯¹è±¡æè¿åä¸ä¸ªå¯¹è±¡ç彿°ã该对象å
å«å¯æ³¨å
¥å
¶ååç屿§ï¼ç¨äºç»ä»¶ä¹é´éä¿¡ã
callHook(vm, 'created'); //触åcreatedé©å彿°
//... çç¥code
// ç¶åæè½½æ¨¡æ¿ï¼è¿é大æ¦å°±æ¯ææ¨¡æ¿è½¬æ¢æastçå
¥å£
vm.$mount(vm.$options.el);
}
æ¥æ¾åæè½½æ¨¡æ¿
â vm.$mount è¿å ¥è¿ä¸ªæè½½æ¨¡æ¿æ¹æ³ï¼å¤ææ¯å¦æ render 彿° æè æ¯templateï¼å¦ææ²¡æå使ç¨el.outerHTML , å®é ä¸è¿éå°±æ¯è¦æ¿å°æ¨¡æ¿çhtmlå 容
Vue.prototype.$mount = function (el, hydrating) {
//... çç¥code
el = el && query(el); //è·ådom
if (!options.render) {
if (template) {
}else if (template.nodeType) {
template = template.innerHTML;
} else if (el) {
template = getOuterHTML(el);
}
ï½
// render 彿° 乿¯ ast è½¬æ¢ æ¹æ³
var ref = compileToFunctions(
template, //模æ¿å符串
{
shouldDecodeNewlines: shouldDecodeNewlines, //flase //IEå¨å±æ§å¼ä¸ç¼ç æ¢è¡ï¼èå
¶ä»æµè§å¨åä¸ä¼
shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref, //true chromeå¨a[href]ä¸ç¼ç å
容
delimiters: options.delimiters, //æ¹åçº¯ææ¬æå
¥åé符ãä¿®æ¹æä»¤ç书å飿 ¼ï¼æ¯å¦é»è®¤æ¯{{mgs}} delimiters: ['${', '}']ä¹ååæè¿æ · ${mgs}
comments: options.comments //å½è®¾ä¸º true æ¶ï¼å°ä¼ä¿ç䏿¸²ææ¨¡æ¿ä¸ç HTML 注éãé»è®¤è¡ä¸ºæ¯èå¼å®ä»¬ã
},
this
);
//... çç¥code
//æ§è¡$mountæ¹æ³ ç¨$mountçæ¹æ³ææ©å±æè½½å°domä¸
return mount.call(
this,
el, //çå®çdom
hydrating //undefined
)
ï½
ç¼è¯ASTårender彿°
è°ç¨ Vue.prototype.$mount æ¹æ³ä¹å æ¿å°æ¨¡æ¿ä¹å å°±ä¼è¿å ¥ä»¥ä¸è¿å ä¸ªæ¹æ³ï¼è¿å ä¸ªæ¹æ³ç¨äºå¾å¤å½æ°å¼ç¼ç¨
compileToFunctions
createCompiler
createCompilerCreator
baseCompile
parse
parseHTML
è¿éæ¯è¾éç¹çæ¯parseHTML 仿¯ while (html) { //循ç¯html ç¶å ç¶åç»è¿æ£å å¹é å°vueæä»¤ï¼è¿ævueç屿§ï¼äºä»¶æ¹æ³çï¼æ¶éå°ä¸ä¸ªastæ ä¸ã
function parseHTML(
html, //å符串模æ¿
options //åæ°
) {
var stack = []; // parseHTML èç¹æ ç¾å æ
var expectHTML = options.expectHTML; //true
var isUnaryTag$$1 = options.isUnaryTag || no; //彿°å¹é
æ ç¾æ¯å¦æ¯ 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no; //彿° //夿æ ç¾æ¯å¦æ¯ 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
var index = 0;
var last, //
lastTag; //
console.log(html)
while (html) { //循ç¯html
last = html; //
// Make sure we're not in a plaintext content element like script/style ç¡®ä¿æä»¬ä¸å¨åèæ¬/æ ·å¼è¿æ ·ççº¯ææ¬å
容å
ç´ ä¸
if (
!lastTag || //lastTag ä¸åå¨
!isPlainTextElement(lastTag) // 妿æ ç¾ä¸æ¯script,style,textarea
) {
var textEnd = html.indexOf('<'); //å¹é
å¼å§æ ç¾æè
ç»ææ ç¾çä½ç½®
if (textEnd === 0) { //æ è¯æ¯å¼å§æ ç¾
// Comment:
if (comment.test(html)) { //å¹é
å¼å§å符串为<!--ä»»ä½å符串,æ³¨éæ ç¾ å¦æå¹é
ä¸
var commentEnd = html.indexOf('-->'); //è·åæ³¨éæ ç¾çç»æä½ç½®
if (commentEnd >= 0) { //å¦ææ³¨éæ ç¾ç»ææ ç¾ä½ç½®å¤§äº0ï¼åææ³¨éå
容
console.log(html.substring(4, commentEnd))
if (options.shouldKeepComment) { //shouldKeepCommentä¸ºçæ¶åãè·åæ³¨éæ ç¾å
容
//æªåæ³¨éæ ç¾çå
容
options.comment(html.substring(4, commentEnd));
}
//æªååç¬¦ä¸²éæ°å¾ªç¯ while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
advance(commentEnd + 3);
continue
}
}
//è¿éæè·¯æ¯å
å¹é
å°æ³¨éèç¹ï¼å¨å¹é
å°è¿éçieæµè§å¨å è½½æ ·å¼èç¹
// http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
if (conditionalComment.test(html)) { //å¹é
å¼å§ä¸º <![ å符串 <![endif]--> å¹é
è¿æ ·å¨æå ieæµè§å¨ç å符串 <!--[if IE 8]><link href="ie8only.css" rel="stylesheet"><![endif]-->
//å¹é
ieæµè§å¨å¨æå æ ·å¼ç»æç¬¦å·
var conditionalEnd = html.indexOf(']>');
if (conditionalEnd >= 0) {
//æªååç¬¦ä¸²éæ°å¾ªç¯ while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
advance(conditionalEnd + 2);
continue
}
}
// Doctype:
//å¹é
htmlç头æä»¶ <!DOCTYPE html>
var doctypeMatch = html.match(doctype);
if (doctypeMatch) {
//æªååç¬¦ä¸²éæ°å¾ªç¯ while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
advance(doctypeMatch[0].length);
continue
}
// End tag:
//å¹é
å¼å¤´å¿
鿝</ åé¢å¯ä»¥å¿½ç¥æ¯ä»»ä½å符串 ^<\\/((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)[^>]*>
var endTagMatch = html.match(endTag);
if (endTagMatch) {
var curIndex = index;
//æ ç¾åé彿° while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
advance(endTagMatch[0].length);
console.log(endTagMatch)
console.log(curIndex, index)
//æ¥æ¾parseHTMLçstackæ ä¸ä¸å½åtagNameæ ç¾åç§°ç¸ççæ ç¾ï¼
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
parseEndTag(
endTagMatch[1],
curIndex,
index
);
continue
}
// Start tag:
//è§£æå¼å§æ è®° æ è®°å¼å§æ ç¾
// è·åå¼å§æ ç¾çåç§°ï¼å±æ§éåï¼å¼å§ä½ç½®åç»æä½ç½®ï¼å¹¶ä¸è¿å该对象
var startTagMatch = parseStartTag();
if (startTagMatch) {
//ææ°ç»å¯¹è±¡å±æ§å¼å¾ªç¯åæå¯¹è±¡ï¼è¿æ ·å¯ä»¥è¿æ»¤ç¸åç屿§
//为parseHTML èç¹æ ç¾å æ æå
¥ä¸ä¸ªæ¡æ°æ®
//è°ç¨options.start 为parse彿° stackæ ç¾å æ æ·»å ä¸ä¸ªæ ç¾
handleStartTag(startTagMatch);
//å¹é
tagæ ç¾æ¯pre,textareaï¼å¹¶ä¸ç¬¬äºä¸ªåæ°ç第ä¸ä¸ªå符æ¯å车é®
if (shouldIgnoreFirstNewline(lastTag, html)) {
//å»é¤å车é®ç©ºæ ¼
advance(1);
}
continue
}
}
var text = (void 0),
rest = (void 0),
next = (void 0);
if (textEnd >= 0) {
rest = html.slice(textEnd); //æªåå符串 var textEnd = html.indexOf('<'); //å¹é
å¼å§æ ç¾æè
ç»ææ ç¾çä½ç½®
console.log(rest)
while (
!endTag.test(rest) && //å¹é
å¼å¤´å¿
鿝</ åé¢å¯ä»¥å¿½ç¥æ¯ä»»ä½å符串
!startTagOpen.test(rest) && // å¹é
å¼å¤´å¿
鿝< åé¢å¯ä»¥å¿½ç¥æ¯ä»»ä½å符串
!comment.test(rest) && // å¹é
å¼å§å符串为<!--ä»»ä½å符串
!conditionalComment.test(rest) //å¹é
å¼å§ä¸º <![ å符串
) {
console.log(rest);
// < in plain text, be forgiving and treat it as text
// <å¨çº¯ææ¬ä¸ï¼è¦å®½å®¹ï¼æå®å½ä½ææ¬æ¥å¯¹å¾
next = rest.indexOf('<', 1); //å¹é
æ¯å¦æå¤ä¸ª<
if (next < 0) {
break
}
textEnd += next; //æªå ç´¢å¼ä½ç½®
rest = html.slice(textEnd); //è·å < å符串 < è·åä»ä»¬ä¸¤ç¬¦å·< ä¹é´çå符串
}
text = html.substring(0, textEnd); //æªåå符串 åé¢åç¬¦ä¸²å° <
//while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
advance(textEnd);
}
if (textEnd < 0) { //齿²¡æå¹é
å° < ç¬¦å· åè¡¨ç¤ºçº¯ææ¬
text = html; //åºæ¥text
html = ''; //æhtmlè³ç©º 跳槽 while循ç¯
}
if (options.chars && text) {
options.chars(text);
}
} else {
// å¤çæ¯script,style,textarea
var endTagLength = 0;
var stackedTag = lastTag.toLowerCase();
var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));
var rest$1 = html.replace(reStackedTag, function (all, text, endTag) {
endTagLength = endTag.length;
if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {
text = text
.replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298
.replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
}
//å¹é
tagæ ç¾æ¯pre,textareaï¼å¹¶ä¸ç¬¬äºä¸ªåæ°ç第ä¸ä¸ªå符æ¯å车é®
if (shouldIgnoreFirstNewline(stackedTag, text)) {
text = text.slice(1);
}
if (options.chars) {
options.chars(text);
}
return ''
});
index += html.length - rest$1.length;
html = rest$1;
parseEndTag(stackedTag, index - endTagLength, index);
}
if (html === last) {
options.chars && options.chars(html);
if ("development" !== 'production' && !stack.length && options.warn) {
options.warn(("Mal-formatted tag at end of template: \"" + html + "\""));
}
break
}
}
// Clean up any remaining tags
//æ¥æ¾parseHTMLçstackæ ä¸ä¸å½åtagNameæ ç¾åç§°ç¸ççæ ç¾ï¼
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
parseEndTag();
//while è·³åºå¾ªç¯å°±æ¯é è¯¥å½æ°ï¼æ¯æ¬¡å¹é
å°ä¹åå°±æªåæå符串ï¼ç¥éæåä¸ä¸ªæ ç¾è¢«æªå宿²¡æå¹é
å°åè·³åºå¾ªç¯
function advance(n) {
index += n; //让索å¼å å
html = html.substring(n); //æªåå½åç´¢å¼ å åé¢çå符串ã
}
//è·åå¼å§æ ç¾çåç§°ï¼æ¶é屿§éåï¼å¼å§ä½ç½®åç»æä½ç½®ï¼å¹¶ä¸è¿å该对象
function parseStartTag() {
var start = html.match(startTagOpen); //å¹é
å¼å§æ ç¾ å¹é
å¼å¤´å¿
鿝< åé¢å¯ä»¥å¿½ç¥æ¯ä»»ä½å符串 ^<((?:[a-zA-Z_][\\w\\-\\.]*\\:)?[a-zA-Z_][\\w\\-\\.]*)
console.log(start)
console.log(start[0].length)
if (start) {
var match = {
tagName: start[1], //æ ç¾åç§°
attrs: [], //æ ç¾å±æ§éå
start: index //æ ç¾çå¼å§ç´¢å¼
};
//æ è®°å¼å§æ ç¾çä½ç½®ï¼æªåäºå¼å§æ ç¾
advance(start[0].length);
var end, attr;
while (
!(end = html.match(startTagClose)) //没æå° å
³éæ ç¾ > æ ç¾
&& (attr = html.match(attribute)) //æ¶é屿§
) {
console.log(html)
//æªå屿§æ ç¾
advance(attr[0].length);
match.attrs.push(attr); //æå±æ§æ¶éå°ä¸ä¸ªéå
}
if (end) {
match.unarySlash = end[1]; //妿æ¯/>æ ç¾ åunarySlash æ¯/ã 妿æ¯>æ ç¾ åunarySlash æ¯ç©º
console.log(end)
//æªåæå¼å§æ ç¾ï¼å¹¶ä¸æ´æ°ç´¢å¼
advance(end[0].length);
match.end = index; //å¼å§æ ç¾çç»æä½ç½®
return match
}
}
}
//ææ°ç»å¯¹è±¡å±æ§å¼å¾ªç¯åæå¯¹è±¡ï¼è¿æ ·å¯ä»¥è¿æ»¤ç¸åç屿§
//为parseHTML èç¹æ ç¾å æ æå
¥ä¸ä¸ªæ¡æ°æ®
//è°ç¨options.start 为parse彿° stackæ ç¾å æ æ·»å ä¸ä¸ªæ ç¾
function handleStartTag(match) {
/*
* match = {
tagName: start[1], //æ ç¾åç§°
attrs: [], //æ ç¾å±æ§éå
start: indexï¼ //å¼å§æ ç¾çå¼å§ç´¢å¼
match:index ï¼ //å¼å§æ ç¾ç ç»æä½ç½®
unarySlash:'' //妿æ¯/>æ ç¾ åunarySlash æ¯/ã 妿æ¯>æ ç¾ åunarySlash æ¯ç©º
};
* */
var tagName = match.tagName; //å¼å§æ ç¾åç§°
var unarySlash = match.unarySlash; //妿æ¯/>æ ç¾ åunarySlash æ¯/ã 妿æ¯>æ ç¾ åunarySlash æ¯ç©º
console.log(expectHTML)
console.log('lastTag==')
console.log(lastTag)
console.log(tagName)
if (expectHTML) { //true
if (
lastTag === 'p' //ä¸ä¸ä¸ªæ ç¾æ¯p
/*
夿æ ç¾æ¯å¦æ¯
'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
'title,tr,track'
*/
&& isNonPhrasingTag(tagName)
) {
//æ¥æ¾parseHTMLçstackæ ä¸ä¸å½åtagNameæ ç¾åç§°ç¸ççæ ç¾ï¼
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
parseEndTag(lastTag);
}
if (
canBeLeftOpenTag$$1(tagName) && //夿æ ç¾æ¯å¦æ¯ 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
lastTag === tagName //ä¸ä¸ä¸ªæ ç¾åç°å¨æ ç¾ç¸å <li><li> ç¼è¯æ <li></li> 使¯è¿ç§æ
嵿¯ä¸ä¼åºç°ç å 为æµè§å¨è§£æçæ¶åä¼èªå¨è¡¥å
¨å¦ææ¯<li>ææ¯liæ ç¾<li> æµè§å¨èªå¨è§£ææ <li>ææ¯liæ ç¾</li><li> </li>
) {
//æ¥æ¾parseHTMLçstackæ ä¸ä¸å½åtagNameæ ç¾åç§°ç¸ççæ ç¾ï¼
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
parseEndTag(tagName);
}
}
var unary = isUnaryTag$$1(tagName) || //彿°å¹é
æ ç¾æ¯å¦æ¯ 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen, link,meta,param,source,track,wbr'
!!unarySlash; //妿æ¯/> å为ç
var l = match.attrs.length;
var attrs = new Array(l); //æ°ç»å±æ§å¯¹è±¡è½¬æ¢æ£çæ£çæ°ç»å¯¹è±¡
for (var i = 0; i < l; i++) {
var args = match.attrs[i]; //è·å屿§å¯¹è±¡
// hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
//对FF bugè¿è¡é»å®¢æ»å»:https://bugzilla.mozilla.org/show_bug.cgi?id=369778
if (
IS_REGEX_CAPTURING_BROKEN && //è¿ä¸ªåºè¯¥æ¯ ç«çæµè§å¨ç§æ æ å¿
args[0].indexOf('""') === -1
) {
if (args[3] === '') {
delete args[3];
}
if (args[4] === '') {
delete args[4];
}
if (args[5] === '') {
delete args[5];
}
}
var value = args[3] || args[4] || args[5] || '';
var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'
? options.shouldDecodeNewlinesForHref // true chromeå¨a[href]ä¸ç¼ç å
容
: options.shouldDecodeNewlines; //flase //IEå¨å±æ§å¼ä¸ç¼ç æ¢è¡ï¼èå
¶ä»æµè§å¨åä¸ä¼
attrs[i] = { //ææ°ç»å¯¹è±¡å±æ§å¼å¾ªç¯åæå¯¹è±¡ï¼è¿æ ·å¯ä»¥è¿æ»¤ç¸åç屿§
name: args[1], //屿§åç§°
//屿§å¼
value: decodeAttr(value, shouldDecodeNewlines) //æ¿æ¢html ä¸çç¹æ®ç¬¦å·ï¼è½¬ä¹æjsè§£æçå符串,æ¿æ¢ æ <æ¿æ¢ < ï¼ > æ¿æ¢ > ï¼ "æ¿æ¢ "ï¼ &æ¿æ¢ & ï¼ æ¿æ¢\n ï¼	æ¿æ¢\t
};
}
console.log('==!unary==')
console.log(!unary)
if (!unary) { //妿䏿¯åæ ç¾
// 为parseHTML èç¹æ ç¾å æ æå
¥ä¸ä¸ªæ¡æ°æ®
stack.push({ //æ ç¾å æ
tag: tagName, //å¼å§æ ç¾åç§°
lowerCasedTag: tagName.toLowerCase(), //åæå°åè®°å½æ ç¾
attrs: attrs //è·å屿§
});
//è®¾ç½®ç»ææ ç¾
lastTag = tagName;
console.log('== parseHTML handleStartTag stack==')
console.log(stack)
}
//
if (options.start) {
//æ ç¾å¼å§å½æ°ï¼ å建ä¸ä¸ªastæ ç¾domï¼ å¤æè·åv-for屿§æ¯å¦åå¨å¦ææåè½¬ä¹ v-foræä»¤ æforï¼aliasï¼iterator1ï¼iterator2屿§æ·»å å°èædomä¸
//è·åv-if屿§ï¼ä¸ºelèædomæ·»å v-ifï¼v-elesï¼v-else-if 屿§
//è·åv-once æä»¤å±æ§ï¼å¦æææè¯¥å±æ§ 为èædomæ ç¾ æ è®°äºä»¶ åªè§¦å䏿¬¡å鿝
//æ ¡éªå±æ§çå¼ï¼ä¸ºelæ·»å mutedï¼ eventsï¼nativeEventsï¼directivesï¼ keyï¼ refï¼slotNameæè
slotScopeæè
slotï¼componentæè
inlineTemplate æ å¿ å±æ§
// æ å¿å½åçcurrentParentå½åç element
//为parse彿° stackæ ç¾å æ æ·»å ä¸ä¸ªæ ç¾
options.start(
tagName, //æ ç¾åç§°
attrs, //æ ç¾å±æ§
unary, // 妿䏿¯åæ ç¾å为ç
match.start, //å¼å§æ ç¾çå¼å§ä½ç½®
match.end //å¼å§æ ç¾çç»æçä½ç½®
);
}
}
//æ¥æ¾parseHTMLçstackæ ä¸ä¸å½åtagNameæ ç¾åç§°ç¸ççæ ç¾ï¼
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
function parseEndTag(
tagName, //æ ç¾åç§°
start, //ç»ææ ç¾å¼å§ä½ç½®
end //ç»ææ ç¾ç»æä½ç½®
) {
var pos,
lowerCasedTagName;
if (start == null) { //å¦ææ²¡æä¼ å¼å§ä½ç½®
start = index; //å°±é£å½åç´¢å¼
}
if (end == null) { //å¦ææ²¡æä¼ ç»æä½ç½®
end = index; //å°±é£å½åç´¢å¼
}
if (tagName) { //ç»ææ ç¾åç§°
lowerCasedTagName = tagName.toLowerCase(); //å°å符串转åæå°å
}
// Find the closest opened tag of the same type æ¥æ¾æè¿æå¼çç¸åç±»åçæ è®°
if (tagName) {
// è·åstackå æ æè¿çå¹é
æ ç¾
for (pos = stack.length - 1; pos >= 0; pos--) {
//æ¾å°æè¿çæ ç¾ç¸ç
if (stack[pos].lowerCasedTag === lowerCasedTagName) {
break
}
}
} else {
// If no tag name is provided, clean shop
//å¦ææ²¡ææä¾æ ç¾åç§°ï¼è¯·æ¸
çååº
pos = 0;
}
if (pos >= 0) { //è¿éå°±è·åå°äºstackå æ çposç´¢å¼
// Close all the open elements, up the stack å
³éæææå¼çå
ç´ ï¼åä¸å æ
console.log(pos)
for (var i = stack.length - 1; i >= pos; i--) {
if ("development" !== 'production' && //妿stack䏿¾ä¸å°tagName æ ç¾çæ¶åå°±è¾åºè¦åæ¥å¿ï¼æ¾ä¸å°æ ç¾
(i > pos || !tagName) &&
options.warn
) {
options.warn(
("tag <" + (stack[i].tag) + "> has no matching end tag.")
);
}
if (options.end) {
console.log(options.end)
//è°ç¨options.end彿°ï¼å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
options.end(
stack[i].tag,//ç»ææ ç¾åç§°
start, //ç»ææ ç¾å¼å§ä½ç½®
end //ç»ææ ç¾ç»æä½ç½®
);
}
}
// Remove the open elements from the stack
//ä»å æ ä¸å 餿å¼çå
ç´
// console.log(stack[pos].tag)
// 为parseHTML èç¹æ ç¾å æ åºæ¡å½åå¹é
å°çæ ç¾
stack.length = pos;
//è·åå°ä¸ä¸ä¸ªæ ç¾ï¼å°±æ¯å½åèç¹çç¶èç¹
lastTag = pos && stack[pos - 1].tag;
console.log(stack)
console.log(lastTag)
} else if (lowerCasedTagName === 'br') {
if (options.start) {
//æ ç¾å¼å§å½æ°ï¼ å建ä¸ä¸ªastæ ç¾domï¼ å¤æè·åv-for屿§æ¯å¦åå¨å¦ææåè½¬ä¹ v-foræä»¤ æforï¼aliasï¼iterator1ï¼iterator2屿§æ·»å å°èædomä¸
//è·åv-if屿§ï¼ä¸ºelèædomæ·»å v-ifï¼v-elesï¼v-else-if 屿§
//è·åv-once æä»¤å±æ§ï¼å¦æææè¯¥å±æ§ 为èædomæ ç¾ æ è®°äºä»¶ åªè§¦å䏿¬¡å鿝
//æ ¡éªå±æ§çå¼ï¼ä¸ºelæ·»å mutedï¼ eventsï¼nativeEventsï¼directivesï¼ keyï¼ refï¼slotNameæè
slotScopeæè
slotï¼componentæè
inlineTemplate æ å¿ å±æ§
// æ å¿å½åçcurrentParentå½åç element
//为parse彿° stackæ ç¾å æ æ·»å ä¸ä¸ªæ ç¾
options.start(
tagName,
[], true,
start,
end
);
}
} else if (lowerCasedTagName === 'p') {
if (options.start) {
//æ ç¾å¼å§å½æ°ï¼ å建ä¸ä¸ªastæ ç¾domï¼ å¤æè·åv-for屿§æ¯å¦åå¨å¦ææåè½¬ä¹ v-foræä»¤ æforï¼aliasï¼iterator1ï¼iterator2屿§æ·»å å°èædomä¸
//è·åv-if屿§ï¼ä¸ºelèædomæ·»å v-ifï¼v-elesï¼v-else-if 屿§
//è·åv-once æä»¤å±æ§ï¼å¦æææè¯¥å±æ§ 为èædomæ ç¾ æ è®°äºä»¶ åªè§¦å䏿¬¡å鿝
//æ ¡éªå±æ§çå¼ï¼ä¸ºelæ·»å mutedï¼ eventsï¼nativeEventsï¼directivesï¼ keyï¼ refï¼slotNameæè
slotScopeæè
slotï¼componentæè
inlineTemplate æ å¿ å±æ§
// æ å¿å½åçcurrentParentå½åç element
//为parse彿° stackæ ç¾å æ æ·»å ä¸ä¸ªæ ç¾
options.start(
tagName,
[], false,
start,
end);
}
if (options.end) {
//å é¤å½åèç¹çåèç¹ä¸çæåä¸ä¸ªå¦ææ¯ç©ºæ ¼æè
ç©ºçææ¬èç¹åå é¤ï¼
//为stackåºæ ä¸ä¸ªå½åæ ç¾ï¼ä¸ºcurrentParentåéè·åå°å½åèç¹çç¶èç¹
options.end(
tagName,
start,
end
);
}
}
console.log(lastTag)
}
}
ä¸äºå¹é æ¨¡æ¿æ£å
var onRE = /^@|^v-on:/;//夿æ¯å¦æ¯ @æè
v-on:屿§å¼å¤´ç
var dirRE = /^v-|^@|^:/; //夿æ¯å¦æ¯ v-æè
@æè
: 屿§å¼å¤´ç
var forAliasRE = /([^]*?)\s+(?:in|of)\s+([^]*)/; //å¹é
嫿 å符串 in å符串 æè
å符串 of å符串
var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; //å¹é
ä¸, 使¯å±äºä¸¤è¾¹æ¯ [{ , ç¹ , }] æä»¥å¹é
ä¸ ,+å符串
var stripParensRE = /^\(|\)$/g; //å¹é
æ¬å· ()
var argRE = /:(.*)$/; //å¹é
å符串æ¯å¦å«æ:
var bindRE = /^:|^v-bind:/; //å¼å§å¹é
æ¯ :æè
æ¯v-bind
var modifierRE = /\.[^.]+/g; // å¹é
以ç¹å¼å¤´çåç» ä¸å±äºç¹ data.object.info.age å¹é
å° ['.object'ï¼'.info' , '.age']
var decodeHTMLCached = cached(he.decode); //è·å çæ¯domçtextContentææ¬
åæ°æ®ååº
åæ°æ®ç»å® å ¥å£ æ¹æ³å¨defineReactive彿°ä¸ ï¼ä¸ç®¡æ¯ prop è¿æ¯ state è¿æ¯ 屿§ç嬿¹æ³ set æ¹æ³ï¼è¿æ¯initInjections å ¥å£é½æ¯è¿éã
é¦å ä»ä¼å®ä¾å var dep = new Dep(); ä¾èµæ¶é Depï¼getæ¹æ³ä¼æ·»å ä¸ä¸ª
â //æ·»å ä¸ä¸ªdep â dep.depend();
â if (childOb) { //妿åèç¹åå¨ä¹æ·»å ä¸ä¸ªdep â childOb.dep.depend(); â if (Array.isArray(value)) { //夿æ¯å¦æ¯æ°ç» å¦ææ¯æ°ç» â dependArray(value); //åæ°ç»ä¹æ·»å dep â } â }
set æ¹æ³æ¯è§¦åæ´æ°è§å¾ç
//observe æ·»å è§å¯è
// ç¶å卿·»å ä¾èµ
childOb = !shallow && observe(newVal); //æ´æ°æ°æ® dep.notify();
/**
* Define a reactive property on an Object.
* å¨å¯¹è±¡ä¸å®ä¹ä¸ä¸ªæ å屿§ã
* æ´æ°æ°æ®
* éè¿definePropertyçsetæ¹æ³å»éç¥notify()订é
è
subscribersææ°çå¼ä¿®æ¹
* æ·»å è§å¯è
get setæ¹æ³
*/
function defineReactive(obj, //对象
key,//对象çkey
val, //çå¬çæ°æ® è¿åçæ°æ®
customSetter, // æ¥å¿å½æ°
shallow //æ¯å¦è¦æ·»å __ob__ 屿§
) {
//å®ä¾åä¸ä¸ªä¸»é¢å¯¹è±¡ï¼å¯¹è±¡ä¸æç©ºçè§å¯è
å表
var dep = new Dep();
//è·åæè¿°å±æ§
var property = Object.getOwnPropertyDescriptor(obj, key);
var _property = Object.getOwnPropertyNames(obj); //è·åå®åå¯¹è±¡å±æ§æè
æ¹æ³ï¼å
æ¬å®ä¹çæè¿°å±æ§
console.log(property);
console.log(_property);
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
var getter = property && property.get;
console.log('arguments.length=' + arguments.length)
if (!getter && arguments.length === 2) {
val = obj[key];
}
var setter = property && property.set;
console.log(val)
//夿value æ¯å¦æ__ob__ å®ä¾å dep对象,è·ådep对象 为 valueæ·»å __ob__ 屿§é彿valæ·»å å°è§å¯è
ä¸ è¿å new Observer å®ä¾åç对象
var childOb = !shallow && observe(val);
//å®ä¹æè¿°
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
var value = getter ? getter.call(obj) : val;
if (Dep.target) { //Dep.target éææ å¿ æ å¿äºDepæ·»å äºWatcher å®ä¾åç对象
//æ·»å ä¸ä¸ªdep
dep.depend();
if (childOb) { //妿åèç¹åå¨ä¹æ·»å ä¸ä¸ªdep
childOb.dep.depend();
if (Array.isArray(value)) { //夿æ¯å¦æ¯æ°ç» å¦ææ¯æ°ç»
dependArray(value); //åæ°ç»ä¹æ·»å dep
}
}
}
return value
},
set: function reactiveSetter(newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare æ°æ§å¼æ¯è¾ 妿æ¯ä¸æ ·å䏿§è¡äº*/
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare
* 䏿¯ç产ç¯å¢çæ
åµä¸
* */
if ("development" !== 'production' && customSetter) {
customSetter();
}
if (setter) {
//set æ¹æ³ 设置æ°çå¼
setter.call(obj, newVal);
} else {
//æ°çå¼ç´æ¥ç»ä»
val = newVal;
}
console.log(newVal)
//observe æ·»å è§å¯è
childOb = !shallow && observe(newVal);
//æ´æ°æ°æ®
dep.notify();
}
});
}
ä¾èµæ¶é Dep
å¨vueæ°æ®getè·åä¸ï¼è°è¯»åäºè¯¥æ°æ®ï¼å°±æå®æ¶éèµ·æ¥ï¼æä»¥depæ¯ä¸ä¸ªéåï¼å¨æ°æ®setæ¶ï¼éè¿éådepå»è§¦åæ¯ä¸ªdepçnotifyæ¹æ³éè¿è§å¾æ´æ° depç主è¦åè½æ¯åªä½ä¸ºæ¶éï¼é£å¨æ¶éäºä¾èµåï¼å¦ä½ä½¿è§å¾æ´æ°å¢ æä»¥éè¦å®ä¹ä¸ä¸ªæ°çWatcherç±»ï¼æ¹ç±»æ¯ä¼å®ç°å¯¹è§å¾çæ´æ° depæ¯æ¶éçä¸ä¸ªä¾èµå®é å°±æ¯ä¸ä¸ªWatcher
//主é¢å¯¹è±¡Depæé 彿° 主è¦ç¨äºæ·»å åå¸äºä»¶åï¼ç¨æ·æ´æ°æ°æ®ç ååºå¼åçä¹ä¸å½æ°
var Dep = function Dep() {
//uid åå§å为0
this.id = uid++;
/* ç¨æ¥åæ¾Watcherå¯¹è±¡çæ°ç» */
this.subs = [];
};
Dep.prototype.addSub = function addSub(sub) {
/* å¨subs䏿·»å ä¸ä¸ªWatcher对象 */
this.subs.push(sub);
};
Dep.prototype.removeSub = function removeSub(sub) {
/*å é¤ å¨subs䏿·»å ä¸ä¸ªWatcher对象 */
remove(this.subs, sub);
};
//this$1.deps[i].depend();
//为Watcher æ·»å 为Watcher.newDeps.push(dep); ä¸ä¸ªdep对象
Dep.prototype.depend = function depend() {
//æ·»å ä¸ä¸ªdep target æ¯Watcher depå°±æ¯dep对象
if (Dep.target) {
//åæä»¤æ·»å ä¾èµé¡¹
Dep.target.addDep(this);
}
};
/* éç¥ææWatcherå¯¹è±¡æ´æ°è§å¾ */
Dep.prototype.notify = function notify() {
// stabilize the subscriber list first
var subs = this.subs.slice();
for (var i = 0, l = subs.length; i < l; i++) {
//æ´æ°æ°æ®
subs[i].update();
}
};
// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
//å½åæ£å¨è¯ä¼°çç®æ çè§ç¨åºã
//è¿å¨å
¨çæ¯ç¬ä¸æ äºçï¼å ä¸ºåªæä¸ä¸ª
//è§å¯è
å¨ä»»ä½æ¶åé½è¢«è¯ä¼°ã
Dep.target = null;
var targetStack = [];
function pushTarget(_target) {
//target æ¯Watcher depå°±æ¯dep对象
if (Dep.target) { //éææ å¿ Depå½åæ¯å¦ææ·»å äºtarget
//æ·»å ä¸ä¸ªpushTarget
targetStack.push(Dep.target);
}
Dep.target = _target;
}
//
function popTarget() {
// åºçä¸ä¸ªpushTarget
Dep.target = targetStack.pop();
}
æ°æ®æ£æµ Watcher
Watcherçåè½ä¸»è¦æ¯æ¥å£å°Depçéç¥ï¼ç¶åè°ç¨updateæ¹æ³æ´æ°è§å¾ å¨updateæ¹æ³ä¸ä¼è§¦ååè°ï¼åè°å½æ°å®é å°±æ¯å·²çærender彿°
å¨è°ç¨render彿°æ¯ï¼å½æ°éçå¼å°±ä¼è·åå°å·²ç»æ´æ¹åå¼ï¼æä»¥å°±ä¼çææ°çvnode æ°çvnodeçæåï¼å°±æ¯patchçè¿ç¨ï¼ç¨æ°çvnode䏿§çvnodeè¿è¡æ¯å¯¹ï¼æç»å°æ¯å¯¹åçvnode转æ¢ä¸ºå®é çdomæ·»å å°æ¨¡æ¿æè½½èç¹ä¸ æ°çæ¨¡æ¿æè½½åï¼å°æ§ç模æ¿å é¤ï¼è¿æ ·è§å¾å°±æ´æ°å®æ
* *è§å¯è
åæè¡¨è¾¾å¼ï¼æ¶éä¾èµé¡¹ï¼
*å¹¶å¨è¡¨è¾¾å¼å¼æ´æ¹æ¶è§¦ååè°ã
*è¿ç¨äº$watch() apiåæä»¤ã
* å½åvueå®ä¾ãupdateComponent彿°ãç©ºå½æ°ã
*/
var Watcher = function Watcher(
vm, //vm dom
expOrFn, //è·åå¼ç彿°ï¼æè
æ¯æ´æ°viweè¯å¾å½æ°
cb, //åè°å½æ°,åè°å¼ç»åè°å½æ°
options, //åæ°
isRenderWatcher//æ¯å¦æ¸²æè¿å¾è§å¯è
) {
console.log('====Watcher====')
this.vm = vm;
//æ¯å¦æ¯å·²ç»æ¸²æè¿å¾è§å¯è
if (isRenderWatcher) { //æå½å Watcher 对象èµå¼ç» vm._watcherä¸
vm._watcher = this;
}
//æè§å¯è
æ·»å å°éåéé¢ å½åWatcheræ·»å å°vueå®ä¾ä¸
vm._watchers.push(this);
// options
if (options) { //妿æåæ°
this.deep = !!options.deep; //å®é
this.user = !!options.user; //ç¨æ·
this.lazy = !!options.lazy; //ææ° ssr 渲æ
this.sync = !!options.sync; //妿æ¯åæ¥
} else {
this.deep = this.user = this.lazy = this.sync = false;
}
this.cb = cb; //åè°å½æ°
this.id = ++uid$1; // uid for batching uid为æ¹å¤ç çå¬è
id
this.active = true; //æ¿æ´»
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
//getterçè§£æè¡¨è¾¾å¼
if (typeof expOrFn === 'function') {
//è·åå¼ç彿°
this.getter = expOrFn;
} else {
//妿æ¯keepAlive ç»ä»¶åä¼èµ°è¿é
//path å 该æ¯è·¯ç±å°å
if (bailRE.test(path)) { // å¹é
ä¸ è¿å true var bailRE = /[^\w.$]/; //å¹é
䏿¯ æ°å忝ä¸å线 $ç¬¦å· å¼å¤´ç为true
return
}
// //å¹é
ä¸ä¸ pathå¨å·²ç¹åå²
// var segments = path.split('.');
// return function (obj) {
//
// for (var i = 0; i < segments.length; i++) {
// //妿æåæ°åè¿åç
// if (!obj) {
// return
// }
// //å°å¯¹è±¡ä¸çä¸ä¸ªkeyå¼ èµå¼ç»è¯¥å¯¹è±¡ ç¸å½äº segments ä»¥ç¹æåçæ°ç»åobj çkey
// obj = obj[segments[i]];
// }
// //å¦åè¿åä¸ä¸ªå¯¹è±¡
// return obj
// }
//å¹é
䏿¯ æ°å忝ä¸å线 $ç¬¦å· å¼å¤´ç为true
this.getter = parsePath(expOrFn);
if (!this.getter) { //妿ä¸åå¨ åç»ä¸ä¸ªç©ºçæ°ç»
this.getter = function () {
};
"development" !== 'production' && warn(
"Failed watching path: \"" + expOrFn + "\" " +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
);
}
}
this.value = this.lazy ? // lazy为çççæ¶åæè½è·åå¼ è¿ä¸ªææ¯ç»ä»¶æä¸ºç
undefined :
this.get(); //计ç®getterï¼å¹¶éæ°æ¶éä¾èµé¡¹ã è·åå¼
};
å¨Watcherå®ä¾æé 彿°æ§è¡æ¶ï¼ä¼è§¦åget 触åäºgetåå°±ä¼è¯¥Watcherå®ä¾è¿è¡æ¶é update为æ¥å°Depéç¥æ¶è§¦åçæ¹æ³ updateå ä¼è°ç¨runæ¹æ³ å¨runæ¹æ³å ä¼è°ç¨cbåè°æ¹æ³ cbåå°æ¹æ³å®é å°±æ¯æ¨¡æ¿ç¼è¯æ¶renderæ¹æ³
èæDOM
vueä¸çèæDOM,å®é å°±æ¯éè¿å®ä¹ä¸ä¸ªVnodeç±»ï¼å¨è¯¥ç±»ä¸æ·»å äºdomçä¸äºå±æ§æ¥æ è¯ä¸ä¸ªdom
主è¦çä½ç¨æ¯éä½å¯¹å®é domçæä½ï¼æ¥å轻对æµè§å¨æ§è½çèè´¹
/*
* å建æ åçvue vnode
*
* */
var VNode = function VNode(
tag, /*å½åèç¹çæ ç¾å*/
data, /*å½åèç¹å¯¹åºç对象ï¼å
å«äºå
·ä½çä¸äºæ°æ®ä¿¡æ¯ï¼æ¯ä¸ä¸ªVNodeDataç±»åï¼å¯ä»¥åèVNodeDataç±»åä¸çæ°æ®ä¿¡æ¯*/
children, //åèç¹
text, //ææ¬
elm, /*å½åèç¹çdom */
context, /*ç¼è¯ä½ç¨å*/
componentOptions, /*ç»ä»¶çoptioné项*/
asyncFactory/*弿¥å·¥å*/) {
/*å½åèç¹çæ ç¾å*/
this.tag = tag;
/*å½åèç¹å¯¹åºç对象ï¼å
å«äºå
·ä½çä¸äºæ°æ®ä¿¡æ¯ï¼æ¯ä¸ä¸ªVNodeDataç±»åï¼å¯ä»¥åèVNodeDataç±»åä¸çæ°æ®ä¿¡æ¯*/
this.data = data;
/*å½åèç¹çåèç¹ï¼æ¯ä¸ä¸ªæ°ç»*/
this.children = children;
/*å½åèç¹çææ¬*/
this.text = text;
/*å½åèæèç¹å¯¹åºççå®domèç¹*/
this.elm = elm;
/*å½åèç¹çåå空é´*/
this.ns = undefined;
/*ç¼è¯ä½ç¨å vm*/
this.context = context;
this.fnContext = undefined;
this.fnOptions = undefined;
this.fnScopeId = undefined;
/*èç¹çkey屿§ï¼è¢«å½ä½èç¹çæ å¿ï¼ç¨ä»¥ä¼å*/
this.key = data && data.key;
/*ç»ä»¶çoptioné项*/
this.componentOptions = componentOptions;
/*å½åèç¹å¯¹åºçç»ä»¶çå®ä¾*/
this.componentInstance = undefined;
/*å½åèç¹çç¶èç¹*/
this.parent = undefined;
/*ç®èè¨ä¹å°±æ¯æ¯å¦ä¸ºåçHTMLæåªæ¯æ®éææ¬ï¼innerHTMLçæ¶å为trueï¼textContentçæ¶å为false*/
this.raw = false;
/*éæèç¹æ å¿*/
this.isStatic = false;
/*æ¯å¦ä½ä¸ºè·èç¹æå
¥*/
this.isRootInsert = true;
/*æ¯å¦ä¸ºæ³¨éèç¹*/
this.isComment = false;
/*æ¯å¦ä¸ºå
éèç¹*/
this.isCloned = false;
/*æ¯å¦æv-onceæä»¤*/
this.isOnce = false;
/*弿¥å·¥å*/
this.asyncFactory = asyncFactory;
this.asyncMeta = undefined;
this.isAsyncPlaceholder = false;
};
diffç®æ³
patch ï¼sameVnodeï¼ patchVnode ï¼updateChildren è¿å ä¸ªæ¹æ³
å ¥å£æ¯patch ç¶åè°ç¨sameVnode
//sameVnode(oldVnode, vnode)2个èç¹çåºæ¬å±æ§ç¸åï¼é£ä¹å°±è¿å
¥äº2个èç¹çdiffè¿ç¨ã
function sameVnode(a, b) {
return (
a.key === b.key && ( //妿açkey çäºbçkey
(
a.tag === b.tag && // 妿açtag çäºbçtag
a.isComment === b.isComment && // 妿aåb 齿¯æ³¨éèç¹
isDef(a.data) === isDef(b.data) && //妿a.data å b.data é½å®ä¹åï¼æ¯ç»ä»¶ï¼æè
æ¯é½å«ætag屿§
sameInputType(a, b) //ç¸åçè¾å
¥ç±»åã夿aåbç屿§æ¯å¦ç¸å
) || (
isTrue(a.isAsyncPlaceholder) && //夿æ¯å¦æ¯å¼æ¥ç
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)
)
)
)
}
妿è°ç¨sameVnode æ¡ä»¶æç« åè¿å ¥patchVnode æ¹æ³,
patchVnode æ¹æ³ä¸»è¦æ¯å¯¹vnode è¿è¡å¢å åå é¤ï¼ä¸»è¦è¿ækeyæ´æ°çãç¶å 夿 两个èædomé½ä¸ä¸ºç©ºï¼å¹¶ä¸ä»ä»¬ä¸ç¸ççæ¶åoldCh !== ch å°±è¿å ¥updateChildren diffæ´æ°ç®æ³ã
// å¯¹æ¯ èædom
function patchVnode(
oldVnode, // æ§çèædom
vnode, // æ°çèædom
insertedVnodeQueue, // å é¤èædoméå
removeOnly
) {
if (oldVnode === vnode) { //妿ä»ä»¬ç¸ç
return
}
var elm = vnode.elm = oldVnode.elm; //è·åçå®çdom
// 夿æ¯å¦æisAsyncPlaceholder 屿§
if (isTrue(oldVnode.isAsyncPlaceholder)) {
//å¤ææ°æ® æ¯å¦ä¸çäº undefinedæè
null
if (isDef(vnode.asyncFactory.resolved)) {
// ssr 渲æ
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.
//ä¸ºéææ éç¨å
ç´ ã
//注æï¼åªæå½vnode被å
éæ¶ï¼æä»¬æè¿æ ·å
//妿æ°èç¹æ²¡æå
éï¼å表示渲æå½æ°å·²ç»å
é
//ç±hot-reload apiéç½®ï¼æä»¬éè¦åä¸ä¸ªéå½çéæ°æ¸²æã
if (isTrue(vnode.isStatic) &&
isTrue(oldVnode.isStatic) &&
vnode.key === oldVnode.key &&
(isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
) {
vnode.componentInstance = oldVnode.componentInstance;
return
}
var i;
var data = vnode.data;
// é©å彿°
if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
i(oldVnode, vnode);
}
var oldCh = oldVnode.children;
var ch = vnode.children;
//循ç¯ç»ä»¶å®ä¾ æ¯å¦å®ä¹æ tagæ ç¾
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);
}
}
//å¦ææ¯ææ¬èædom
if (isUndef(vnode.text)) {
// 两个èædomé½åå¨
if (isDef(oldCh) && isDef(ch)) {
// 妿ä»ä»¬ä¸ç¸ç
if (oldCh !== ch) {
// diffç®æ³æ´æ°
updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly);
}
} else if (isDef(ch)) { // å¦ææ¯ææ°çèædom
// å¦ææ¯ææ¬èædom å 设置 空
if (isDef(oldVnode.text)) {
nodeOps.setTextContent(elm, '');
}
// æ·»å vnode
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) { // 妿æ§çæ æ°çèædom没æåå é¤ èædom
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
} else if (isDef(oldVnode.text)) { // å¦ææ¯ææ¬èædomåè®¾ç½®ææ¬
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);
}
}
}
ddif ç®æ³updateChildren
diifç®æ³ï¼vue2 çdiff ç®æ³æ¯æ·±åº¦ä¼å ç®æ³éåï¼ç¶å对æ¯ç®æ³æ¯éè¿ æ°æ§çvnode对æ¯å 对æ¯ä»ä»¬çåºæ¬å±æ§ï¼æ¯å¦key æ ç¾çï¼å¦ææ¯ç¸ååéè¿diffç®æ³å¯¹æ¯ç¶ådiffç®æ³æ¯æ°æ§çvnode对æ¯ï¼ç¶åæå个æéç´¢å¼ï¼ä¸¤ä¸ªæ°çvnodeå¼å§æéåæ°ç vnode ç»ææéï¼ä¸¤ä¸ªæ§çvnodeå¼å§æéåæ§ç vnode ç»ææéãç¶åå 夿vnodeæ¯å¦ä¸ºç©ºï¼å¦æä¸ºç©ºå°±å¾ä¸é´é æ¢ å¼å§çæé++ ç»æçæé --ãç¶å两头对æ¯ä¹åï¼å¨äº¤å对æ¯ï¼ç´å°æ¾ä¸å°ç¸åçvnodeä¹å妿å¤åºçå°±å é¤ï¼å¦æå°çè¯å°±æ°å¢ï¼ç¶å对æ¯å®ä¹å å¨è°ç¨patchVnodeå»å¢å èædomãç¶å妿ævnodeä¸ç¸åå¨è°ç¨updateChildrenï¼è¿æ ·å°±åå°æ·±å±éå½ï¼ä¹å«æ·±åº¦ä¼å æç´¢ï¼ç¶ååvnode没æäºå¨æ´æ°å°çå®domã
// ddif ç®æ³
function updateChildren(
parentElm, // ç¶äº²dom
oldCh, // æ§çèædom
newCh, // æ°çèædom
insertedVnodeQueue,
removeOnly
) {
var oldStartIdx = 0; // æ§çèædomå¼å§æé
var newStartIdx = 0; // æ°çèædomå¼å§æé
var oldEndIdx = oldCh.length - 1; // æ§çèædomç»ææé
var newEndIdx = newCh.length - 1;// æ°çèædomç»ææé
var oldStartVnode = oldCh[0]; // æ§çèædomå¼å§èç¹
var newStartVnode = newCh[0]; // æ°çèædomå¼å§èç¹
var oldEndVnode = oldCh[oldEndIdx]; // æ§çèædomç»æèç¹
var newEndVnode = newCh[newEndIdx];// æ°çèædomç»æèç¹
var 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
var canMove = !removeOnly;
{
// æ£æ¥åä¸ä¸ªå
å¼èç¹æ¯å¦æéå¤çkeyï¼å¦ææåååºè¦åæ¥å¿
checkDuplicateKeys(newCh);
}
/*
diff ç®æ³å¼å§
è¿édiffç®æ³å
¶å®å°±æ¯
*/
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)) { //sameVnode(oldVnode, vnode)2个èç¹çåºæ¬å±æ§ç¸åï¼é£ä¹å°±è¿å
¥äº2个èç¹çdiffè¿ç¨ã
// å¨å¯¹æ¯ä¸èædom
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue);
//å¼å§æé 两个é½å¾ä¸é´åç§»
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
} else if (sameVnode(oldEndVnode, newEndVnode)) { //sameVnode(oldVnode, vnode)2个èç¹çåºæ¬å±æ§ç¸åï¼é£ä¹å°±è¿å
¥äº2个èç¹çdiffè¿ç¨ã
// å¨å¯¹æ¯ä¸èædom
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue);
// ç»ææé 两个é½å¾ä¸é´åç§»
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right //sameVnode(oldVnode, vnode)2个èç¹çåºæ¬å±æ§ç¸åï¼é£ä¹å°±è¿å
¥äº2个èç¹çdiffè¿ç¨ã
// 交åå¯¹æ¯ æ·±åº¦ä¼å
ç®æ³å
¥å£
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue);
// 交å对æ¯
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);
// 交å对æ¯
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
oldEndVnode = oldCh[--oldEndIdx];
newStartVnode = newCh[++newStartIdx];
} else {
// å¦ææ²¡ækey åç»å¡æ°çkey
if (isUndef(oldKeyToIdx)) {
// å建key å¦ææ²¡ækey åç¨ç´¢å¼ä½ä¸ºkey
oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
}
// è·å æ§çvnode key
idxInOld = isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
// æ¥æ¾æ§çvnode key
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
// 妿æ§ç vnode key æªå®ä¹åå建æ°ççå®dom
if (isUndef(idxInOld)) { // New element
//å建çå® dom èç¹
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
} else {
vnodeToMove = oldCh[idxInOld];
if (sameVnode(vnodeToMove, newStartVnode)) {
// 对æ¯èædom
patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue);
oldCh[idxInOld] = undefined;
// çå®èç¹äº¤æ¢
canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
} else {
// same key but different element. treat as new element
// å建çå®dom
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;
// æ·»å èædom
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
} else if (newStartIdx > newEndIdx) {
// å é¤èædom
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
}
}
å ·ä½çææºç åæµç¨å¾ï¼è¿éæåå°±ä¸æè¿°è¿ä¹å¤äºï¼æµç¨å¾æ¯ä¸é¢è¿ä¸çç½çï¼æºç æ¯vue.js,åºæ¬æ¯ä¸è¡é½ææ³¨é
龿¥ï¼https://pan.baidu.com/s/10IxV6mQ2TIwkRACKu2T0ng æåç ï¼1fnu
ä¸é¢çvue.js å°±æ¯æåºäºvueæºç 䏿¯è¡å ææ³¨éçvue.js, å ¶ä»æä»¶å°±æ¯æçvue.jsæºç çæ¶åæ½åºæ¥çvue.js æºç å°demoã妿大家è§å¾ä¸é请å¨å¨å°ææï¼å¸®æç¹ä¸ä¸ªsatrï¼ä½ ä»¬çæ¯æå°±æ¯æçå¨å
ä½è ï¼å§è§å¯¿
Top Related Projects
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
The Intuitive Vue Framework.
Quasar Framework - Build high-performance VueJS user interfaces in record time
🐉 Vue Component Framework
A Vue.js 2.0 UI Toolkit for Web
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot