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