├── .babelrc ├── .husky ├── commit-msg └── pre-commit ├── .gitignore ├── .prettierignore ├── mine-Vuex ├── package.json ├── src │ └── index.js ├── example │ └── index.html └── lib │ ├── vue.js │ ├── vuex.js │ ├── vue.js.map │ └── vuex.js.map ├── mine-VueRouter ├── src │ ├── create-matcher.js │ ├── components │ │ ├── router-link.js │ │ └── router-view.js │ ├── history │ │ ├── history.js │ │ ├── hash.js │ │ └── base.js │ ├── create-routesMap.js │ ├── install.js │ └── index.js ├── example │ └── index.html └── lib │ ├── VueRouter.js.map │ └── VueRouter.js ├── mine-Vue ├── src │ ├── index.js │ ├── observe │ │ ├── dep.js │ │ ├── array.js │ │ ├── index.js │ │ └── watcher.js │ ├── gloablAPI.js │ ├── utils.js │ ├── init.js │ ├── lifecycle.js │ ├── vdom │ │ ├── index.js │ │ └── patch.js │ ├── compiler │ │ ├── index.js │ │ └── parse.js │ └── state.js ├── mine │ ├── index.html │ └── index.js ├── example │ └── index.html └── lib │ ├── vue.js │ └── vue.js.map ├── commitlint.config.js ├── example └── index.html ├── rollup.config.js ├── package.json └── docs └── essay.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@vue/babel-plugin-jsx"] 4 | } 5 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | # 在提交前格式化项目 4 | npx prettier --write . 5 | 6 | git add . 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | Vue2.6 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | Vue2.6 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln -------------------------------------------------------------------------------- /mine-Vuex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mine-vuex", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack" 9 | }, 10 | "devDependencies": { 11 | "webpack": "^5.70.0", 12 | "webpack-cli": "^4.9.2", 13 | "webpack-dev-server": "^4.7.4" 14 | }, 15 | "author": "", 16 | "license": "ISC" 17 | } 18 | -------------------------------------------------------------------------------- /mine-VueRouter/src/create-matcher.js: -------------------------------------------------------------------------------- 1 | import createRouteMap from "./create-routesMap"; 2 | export default function createMatcher(routes) { 3 | let { pathMap } = createRouteMap(routes); 4 | function addRoutes(routes) { 5 | // 动态添加路由 6 | createRouteMap(routes, pathMap); 7 | } 8 | function addRoute(route) { 9 | createRouteMap([route], pathMap); 10 | } 11 | function match(location) { 12 | return pathMap[location]; 13 | } 14 | return { 15 | addRoutes, //添加多个路由 16 | addRoute, //添加一个路由 17 | match, //给一个路径来返回路由 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /mine-VueRouter/src/components/router-link.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: "router-link", 3 | props: { 4 | to: { type: String }, 5 | tag: { type: String, default: "a" }, 6 | }, 7 | methods: { 8 | handler() { 9 | this.$router.push(this.to); 10 | }, 11 | }, 12 | render(h) { 13 | let tag = this.tag; 14 | return h( 15 | tag, 16 | { 17 | on: { 18 | click: () => { 19 | this.handler(); 20 | }, 21 | }, 22 | }, 23 | [this.$slots.default] 24 | ); 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /mine-VueRouter/src/history/history.js: -------------------------------------------------------------------------------- 1 | import Base from "./base"; 2 | class History extends Base { 3 | constructor(router) { 4 | super(router); 5 | } 6 | setupListener() { 7 | window.addEventListener("popstate", function () { 8 | this.transitionTo(getCurrentLocation()); 9 | }); 10 | } 11 | getCurrentLocation() { 12 | return window.location.pathname; 13 | } 14 | push(location) { 15 | this.transitionTo(location, () => { 16 | window.history.pushState({}, "", location); 17 | }); 18 | } 19 | } 20 | 21 | export default History; 22 | -------------------------------------------------------------------------------- /mine-Vue/src/index.js: -------------------------------------------------------------------------------- 1 | import { initMixin } from "./init"; 2 | import { initLifeCycle } from "./lifecycle"; 3 | import { initStateMixin } from "./state"; 4 | import { complieToFunction } from "./compiler/index"; 5 | import { createElm, patch } from "./vdom/patch"; 6 | import { initGlobalAPI } from "./gloablAPI"; 7 | function Vue(options) { 8 | this._init(options); 9 | } 10 | // 扩展了init方法 11 | initMixin(Vue); 12 | // 提供了_update()和_render两个方法 13 | initLifeCycle(Vue); 14 | // 实现了$nextTick和$watch 15 | initStateMixin(Vue); 16 | // 实现全局API 17 | initGlobalAPI(Vue); 18 | // diff算法是一个平级比较的过程,父亲不能跟儿子进行比对 19 | export default Vue; 20 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // 继承的预设的规则 3 | extends: ["@commitlint/config-conventional"], 4 | // 定义规则类型 5 | rules: { 6 | // type 类型定义,表示 git 提交的 type 必须在以下类型范围内 7 | "type-enum": [ 8 | 2, 9 | "always", 10 | [ 11 | "feat", // 新功能 feature 12 | "fix", // 修复 bug 13 | "docs", // 文档注释 14 | "style", // 代码格式(不影响代码运行的变动) 15 | "refactor", // 重构(既不增加新功能,也不是修复bug) 16 | "perf", // 性能优化 17 | "test", // 增加测试 18 | "chore", // 构建过程或辅助工具的变动 19 | "revert", // 回退 20 | "build", // 打包 21 | ], 22 | ], 23 | // subject 大小写不做校验 24 | "subject-case": [0], 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /mine-VueRouter/src/components/router-view.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: "router-view", 3 | // router-view 不会被计入父子关系,应该被标识为抽象(函数式)组件,避免创建父子关系($parents,$children等) 4 | functional: true, 5 | render(h, { parent, data }) { 6 | data.routerView = true; 7 | let route = parent.$route; 8 | let depth = 0; 9 | // 找到当前渲染的是第几层 10 | while (parent) { 11 | if (parent.$vnode && parent.$vnode.data.routerView) { 12 | depth++; 13 | } 14 | parent = parent.$parent; 15 | } 16 | let record = route.matched[depth]; 17 | if (!record) { 18 | return h(); 19 | } 20 | return h(record.component, data); 21 | // _vnode:渲染函数的虚拟节点;$vnode:代表组件本身,$vnode是_vnode的父亲 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /mine-VueRouter/src/create-routesMap.js: -------------------------------------------------------------------------------- 1 | export default function createRouteMap(routes, pathMap = {}) { 2 | // 根据用户选项扁平化信息,将深度子类转化为扁平层级 3 | routes.forEach((route) => { 4 | addRouteRecord(route, pathMap); 5 | }); 6 | return { 7 | pathMap, 8 | }; 9 | } 10 | function addRouteRecord(route, pathMap, parentRecord) { 11 | let path = parentRecord 12 | ? `${parentRecord.path == "/" ? "" : "/"}${route.path}` 13 | : route.path; 14 | if (!pathMap[path]) { 15 | pathMap[path] = { 16 | path, 17 | component: route.component, 18 | props: route.props, 19 | meta: route.meta, 20 | parent: parentRecord, 21 | }; 22 | } 23 | route.children && 24 | route.children.forEach((children) => { 25 | addRouteRecord(children, pathMap); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /mine-Vue/src/observe/dep.js: -------------------------------------------------------------------------------- 1 | let id = 0; 2 | // 每一个dep都表示一个被依赖的数据,当这个数据变化,跟这些数据关联的视图会同步变化 3 | class Dep { 4 | constructor() { 5 | this.id = id++; 6 | this.subs = []; 7 | } 8 | depend() { 9 | // 不希望放置重复的watcher 10 | // 这里在添加一个watch时,这个watch也会将这个dep添加到自己的观察队列中 11 | Dep.target.addDep(this); 12 | } 13 | // 这个方法是让watcher将自己添加到观察队列的 14 | addSub(watcher) { 15 | this.subs.push(watcher); 16 | } 17 | // 通知所有观察了这个dep的watch更新视图 18 | notify() { 19 | this.subs.forEach((watcher) => { 20 | watcher.update(); 21 | }); 22 | } 23 | } 24 | let stack = []; 25 | export function pushTarget(watcher) { 26 | stack.push(watcher); 27 | Dep.target = watcher; 28 | } 29 | export function popTarget() { 30 | stack.pop(); 31 | Dep.target = stack[stack.length - 1]; 32 | } 33 | export default Dep; 34 | -------------------------------------------------------------------------------- /mine-VueRouter/src/history/hash.js: -------------------------------------------------------------------------------- 1 | import Base from "./base"; 2 | function ensureSlash() { 3 | if (window.location.hash) { 4 | return; 5 | } 6 | window.location.hash = "/"; 7 | } 8 | function getHash() { 9 | // 截取,获取真正的hash值 10 | return window.location.hash.slice(1); 11 | } 12 | class Hash extends Base { 13 | constructor(router) { 14 | super(router); 15 | // 初始化哈希路由的时候要给定默认的哈希路径 16 | ensureSlash(); 17 | } 18 | // 之后需要调用此方法,监控hash值的变化 19 | setupListener() { 20 | // 这里会监听哈希的变化,通过修改url或回退也会触发 21 | window.addEventListener("hashchange", () => { 22 | this.transitionTo(getHash()); 23 | }); 24 | } 25 | getCurrentLocation() { 26 | return getHash(); 27 | } 28 | push(location) { 29 | this.transitionTo(location, () => { 30 | window.location.hash = location; 31 | }); 32 | } 33 | } 34 | export default Hash; 35 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
hello world
11 |
12 |
{{a.b}}
13 |
14 | 15 | 16 | 17 | 34 | 35 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from "rollup-plugin-babel"; 2 | import nodeResolve from "rollup-plugin-node-resolve"; 3 | import commonjs from "rollup-plugin-commonjs"; 4 | const plugins = [ 5 | nodeResolve(), 6 | commonjs(), 7 | babel({ 8 | exclude: ["node_modules/*", "Vue2.6/*"], 9 | }), 10 | ]; 11 | const outputList = ["Vue", "VueRouter"]; 12 | const buildList = outputList.map((name) => { 13 | function getGlobals() { 14 | const listReg = /(VueRouter)/; 15 | return listReg.test(name) 16 | ? { 17 | vue: "vue", // 指明 global.vue 即是外部依赖 vue 18 | } 19 | : void 0; 20 | } 21 | return { 22 | input: `./mine-${name}/src/index.js`, 23 | output: { 24 | file: `./mine-${name}/lib/${name}.js`, 25 | name, 26 | format: "umd", 27 | sourcemap: true, 28 | globals: getGlobals(), 29 | }, 30 | plugins, 31 | }; 32 | }); 33 | export default buildList; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kovue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "prepare": "husky install", 7 | "format": "npx prettier --write .", 8 | "commit": "npx git-cz", 9 | "dev": "rollup -cw" 10 | }, 11 | "dependencies": { 12 | "@babel/core": "^7.18.9", 13 | "@babel/preset-env": "^7.18.9", 14 | "rollup": "^2.77.0", 15 | "rollup-plugin-babel": "^4.4.0" 16 | }, 17 | "devDependencies": { 18 | "@commitlint/config-conventional": "^16.2.1", 19 | "@vue/babel-plugin-jsx": "^1.1.1", 20 | "commitizen": "^4.2.4", 21 | "commitlint": "^16.2.3", 22 | "cz-conventional-changelog": "^3.3.0", 23 | "husky": "^7.0.4", 24 | "prettier": "^2.6.0", 25 | "rollup-plugin-commonjs": "^10.1.0", 26 | "rollup-plugin-node-resolve": "^5.2.0" 27 | }, 28 | "config": { 29 | "commitizen": { 30 | "path": "./node_modules/cz-conventional-changelog" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /mine-Vue/src/observe/array.js: -------------------------------------------------------------------------------- 1 | // 我们希望保留原数组特性并重写部分数组方法 2 | let oldArrayProto = Array.prototype; 3 | export let newArrayProto = Object.create(oldArrayProto); 4 | // 所有变异方法 5 | const methods = [ 6 | "push", 7 | "shift", 8 | "unshift", 9 | "splice", 10 | "pop", 11 | "reverse", 12 | "sort", 13 | ]; 14 | methods.forEach((method) => { 15 | newArrayProto[method] = function (...args) { 16 | // 内部调用原来的方法 17 | const result = oldArrayProto[method].call(this, ...args); 18 | let ob = this.__ob__; 19 | // 将数组中新增的方法进行响应式劫持 20 | let inserted; 21 | switch (method) { 22 | case "push": 23 | case "unshift": 24 | inserted = args; 25 | break; 26 | case "splice": 27 | inserted = args.slice(2); 28 | default: 29 | break; 30 | } 31 | if (inserted) { 32 | ob.observeArray(inserted); 33 | } 34 | // 数组变化后通知对应的 watcher实现更新 35 | ob.dep.notify(); 36 | return result; 37 | }; 38 | }); 39 | -------------------------------------------------------------------------------- /mine-Vue/mine/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |
简易理解Vue的原理
12 |
{{name}}
13 |
{{message}}
14 |
15 | 16 | 17 | 38 | 39 | -------------------------------------------------------------------------------- /mine-Vue/src/gloablAPI.js: -------------------------------------------------------------------------------- 1 | import { mergeOptions } from "./utils"; 2 | export function initGlobalAPI(Vue) { 3 | Vue.options = { 4 | _base: Vue, 5 | }; 6 | Vue.mixin = function (mixin) { 7 | // 期望将用户的选项和全局的options进行合并 8 | // Vue的混入本质是一个订阅发布者模式 9 | this.options = mergeOptions(Vue.options, mixin); 10 | return this; 11 | }; 12 | // 可以手动改创造组件进行挂载 13 | Vue.extend = function (options) { 14 | // 根据用户的参数,返回一个构造函数 15 | // 最终使用一个组件,就是new一个实例 16 | function Sub(options = {}) { 17 | this._init(options); // 默认对子类进行初始化操作 18 | } 19 | Sub.prototype = Object.create(Vue.prototype); 20 | Sub.prototype.constructor = Sub; 21 | // 希望将用户传递的参数和全局的Vue.options合并,使形成类似原型链的查找方式,出现重名优先查找自己 22 | Sub.options = mergeOptions(Vue.options, options); //保存用户传递的选项 23 | return Sub; 24 | // 子组件挂载时也会产生一个watcher 25 | }; 26 | Vue.options.components = {}; 27 | Vue.component = function (id, definition) { 28 | // 如果definition已经是一个函数了,说明用户自己调用了vue.extend 29 | definition = 30 | typeof definition == "function" ? definition : Vue.extend(definition); 31 | Vue.options.components[id] = definition; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /mine-VueRouter/src/install.js: -------------------------------------------------------------------------------- 1 | import routerLink from "./components/router-link"; 2 | import routerView from "./components/router-view"; 3 | export let Vue; 4 | export function install(_Vue) { 5 | Vue = _Vue; 6 | Vue.mixin({ 7 | beforeCreate() { 8 | // 这里不用原型继承的原因是因为会导致所有的Vue类共享路由 9 | if (this.$options.router) { 10 | // 根实例上传递了router 11 | this._routerRoot = this; 12 | this._router = this.$options.router || {}; 13 | this._router.init(this); //this就是我们整个的应用(new Vue) 14 | // 给根实例添加一个属性_router,就是当前的current对象 15 | Vue.util.defineReactive(this, "_route", this._router.history.current); 16 | } else { 17 | // 所有组件上都增加一个routerRoot的指针指向根实例 18 | this._routerRoot = this.$parent?._router || this.$parent._routerRoot; 19 | } 20 | }, 21 | }); 22 | // 劫持$router属性,取$router其实是取了根实例上的router 23 | Object.defineProperty(Vue.prototype, "$router", { 24 | get() { 25 | return this._routerRoot; 26 | }, 27 | }); 28 | Object.defineProperty(Vue.prototype, "$route", { 29 | get() { 30 | return this._routerRoot._route || this._routerRoot.history.current; 31 | }, 32 | }); 33 | // 内部修改的是current 34 | Vue.component("router-link", routerLink); 35 | Vue.component("router-view", routerView); 36 | } 37 | -------------------------------------------------------------------------------- /mine-VueRouter/src/index.js: -------------------------------------------------------------------------------- 1 | import { install, Vue } from "./install"; 2 | import createMatcher from "./create-matcher"; 3 | import History from "./history/history"; 4 | import Hash from "./history/hash"; 5 | class VueRouter { 6 | constructor(options) { 7 | this.install = install; 8 | this.beforeEachHooks = []; 9 | // 对用户传入的路由表进行映射 10 | const routes = options.routes; 11 | this.matcher = createMatcher(routes); 12 | // 根据不用的模式创建不同的路由系统 13 | let mode = options.mode || "hash"; 14 | if (mode == "hash") { 15 | this.history = new Hash(this); 16 | } else if (mode == "history") { 17 | this.history = new History(this); 18 | } 19 | } 20 | beforeEach(cb) { 21 | this.beforeEachHooks.push(cb); 22 | } 23 | match(path) { 24 | return this.matcher.match(path); 25 | } 26 | push(location) { 27 | return this.history.push(location); 28 | } 29 | init(app) { 30 | let history = this.history; 31 | // 根据路径变化,匹配不同的组件进行渲染,路径变化,更新视图,路径需要是响应式的 32 | history.transitionTo(history.getCurrentLocation(), () => { 33 | history.setupListener(); //监听路由变化 34 | }); 35 | // 每次路由需要调用listen中的方法实现更新_route的值,使他能够发生变化,重新渲染视图 36 | history.listen((newRoute) => { 37 | app._route = newRoute; 38 | }); 39 | } 40 | } 41 | export default VueRouter; 42 | -------------------------------------------------------------------------------- /mine-Vue/src/utils.js: -------------------------------------------------------------------------------- 1 | const strats = {}; 2 | const LIFECYCLE = [ 3 | "beforeCreate", 4 | "created", 5 | "mounted", 6 | "beforeUpdate", 7 | "updated", 8 | "beforeDestroy", 9 | "destroy", 10 | ]; 11 | LIFECYCLE.forEach((hook) => { 12 | strats[hook] = function (p, c) { 13 | if (c) { 14 | if (p) { 15 | // 第一次之后,p必定为一个数组 16 | return p.concat(c); 17 | } else { 18 | // 第一次合并p为{} 19 | return [c]; 20 | } 21 | } else { 22 | // 如果儿子没有,直接返回父亲 23 | // c没有的情况下,p可能有,也可能为undefined 24 | return p; 25 | } 26 | }; 27 | }); 28 | strats.components = function (parentVal, childVal) { 29 | const res = Object.create(parentVal); 30 | if (childVal) { 31 | for (let key in childVal) { 32 | // 返回的是构造的对象,可以返回父亲原型上的属性,并将儿子的属性拷贝到自己身上 33 | res[key] = childVal[key]; 34 | } 35 | } 36 | return res; 37 | }; 38 | export function mergeOptions(parent, child) { 39 | const options = {}; 40 | for (let key in parent) { 41 | mergeField(key); 42 | } 43 | for (let key in child) { 44 | if (!parent.hasOwnProperty(key)) { 45 | mergeField(key); 46 | } 47 | } 48 | function mergeField(key) { 49 | // 策略模式减少if-else 50 | if (strats[key]) { 51 | options[key] = strats[key](parent[key], child[key]); 52 | } else { 53 | // 不在策略中则优先采用儿子的,再采用父亲 54 | options[key] = child[key] || parent[key]; 55 | } 56 | } 57 | return options; 58 | } 59 | -------------------------------------------------------------------------------- /mine-VueRouter/src/history/base.js: -------------------------------------------------------------------------------- 1 | function createRoute(record, location) { 2 | let matched = []; 3 | if (record) { 4 | while (record) { 5 | matched.unshift(record); 6 | record = record.parent; 7 | } 8 | } 9 | return { 10 | ...location, 11 | matched, 12 | }; 13 | } 14 | function runQueue(queue, from, to, cb) { 15 | function next(index) { 16 | if (index >= queue.length) { 17 | return cb(); 18 | } 19 | let hook = queue[index]; 20 | hook(from, to, () => next(index + 1)); 21 | } 22 | next(0); 23 | } 24 | export default class Base { 25 | constructor(router) { 26 | this.router = router; 27 | // 每次更新的是current,每次current变化,我们就可以切换页面 28 | this.current = createRoute(null, { 29 | path: "/", 30 | }); 31 | } 32 | // 所有跳转的逻辑都要放在transitionTo中来实现 33 | transitionTo(location, listener) { 34 | // 用之前的匹配方法 35 | let record = this.router.match(location); 36 | let route = createRoute(record, { path: location }); 37 | // 这里需要取消点击进入和路由变化中的两次重复变化,注意path='/'时可能会匹配组件 38 | if ( 39 | location == this.current.path && 40 | route.matched.length == this.current.matched.length 41 | ) { 42 | return; 43 | } 44 | let queue = [].concat(this.router.beforeEachHooks); 45 | // 钩子执行完后再做跳转 46 | runQueue(queue, this.current, route, () => { 47 | this.current = route; 48 | // path:'/',matched:[] 49 | // 当路由切换的时候,也应该调用transitionTo拿到新的记录 50 | listener && listener(); 51 | this.cb && this.cb(route); 52 | }); 53 | } 54 | listen(cb) { 55 | // 用户自定义的钩子 this._route=route 56 | this.cb = cb; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /mine-Vue/src/init.js: -------------------------------------------------------------------------------- 1 | // 给Vue增加初始化方法 2 | import { initState } from "./state"; 3 | import { complieToFunction } from "./compiler/index"; 4 | import { mountComponent } from "./lifecycle"; 5 | import { mergeOptions } from "./utils"; 6 | import { callHook } from "./lifecycle"; 7 | export function initMixin(Vue) { 8 | Vue.prototype._init = function (options) { 9 | const vm = this; 10 | // 将用户传入的选项和全局选项进行合并 11 | vm.$options = mergeOptions(this.constructor.options, options); 12 | console.log(vm.$options); 13 | callHook(vm, "beforeCreated"); 14 | initState(vm); 15 | callHook(vm, "created"); 16 | if (options.el) { 17 | vm.$mount(options.el); 18 | } 19 | }; 20 | Vue.prototype.$mount = function (el) { 21 | const vm = this; 22 | el = document.querySelector(el); 23 | let opts = vm.$options; 24 | // 当没有render函数时 25 | if (!opts?.render) { 26 | let template = null; 27 | // 没有模板但写了el 28 | if (!opts.template && opts.el) { 29 | template = el.outerHTML; 30 | // 存在模板或不存在模板和el 31 | } else { 32 | // 存在模板 33 | if (opts.template) { 34 | template = opts.template; 35 | } else { 36 | // 既没有模板也没有el 37 | template = "
"; 38 | } 39 | } 40 | //拿到模板 41 | // 获取优先级:render=>temple=>el 42 | if (template) { 43 | const render = complieToFunction(template); 44 | opts.render = render; 45 | } 46 | } 47 | mountComponent(vm, el); 48 | }; 49 | } 50 | // script标签引入的vue,编译过程在浏览器 51 | // runtime是不包含编译的,编译时通过loader进行转译.vue文件,用runtime不能使用template(在mian.js中,.vue文件有loader转译,因此不影响) 52 | // 包含main.js中模板编译的版本是runtime-with-compiler 53 | -------------------------------------------------------------------------------- /mine-Vue/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |

{{fullName}}

12 |
world
13 | 14 |
15 |
16 | 17 | 18 | 61 | 62 | -------------------------------------------------------------------------------- /mine-Vuex/src/index.js: -------------------------------------------------------------------------------- 1 | let _Vue = null; 2 | export default class Vuex { 3 | constructor(options) { 4 | const state = options.state || {}; 5 | const mutations = options.mutations || {}; 6 | const actions = options.actions || {}; 7 | const getters = options.getters || {}; 8 | // 直接调用Vue的响应式系统 9 | // state的实现 10 | this.state = _Vue.observable(state); 11 | // getter的实现 12 | this.getters = Object.create(null); 13 | Object.keys(getters).forEach((key) => { 14 | Object.defineProperty(this.getters, key, { 15 | get: () => { 16 | return getters[key].call(this, this.state); 17 | }, 18 | }); 19 | }); 20 | // mutations 21 | this.mutations = Object.create(null); 22 | Object.keys(mutations).forEach((key) => { 23 | this.mutations[key] = (params) => { 24 | // 改变this指向 ,默认是要传入 state 25 | mutations[key].call(this, this.state, params); 26 | }; 27 | }); 28 | //action 29 | this.actions = Object.create(null); 30 | Object.keys(actions).forEach((key) => { 31 | this.actions[key] = (params) => { 32 | // 改变this指向 ,默认是要传入 store也就是 this 33 | actions[key].call(this, this, params); 34 | }; 35 | }); 36 | // commit 37 | this.commit = (eventName, params) => { 38 | this.mutations[eventName](params); 39 | }; 40 | this.dispatch = (eventName, params) => { 41 | this.actions[eventName](params); 42 | }; 43 | } 44 | } 45 | 46 | Vuex.install = function (Vue) { 47 | _Vue = Vue; 48 | _Vue.mixin({ 49 | beforeCreate() { 50 | if (this.$options.store) { 51 | _Vue.prototype.$store = this.$options.store; 52 | } 53 | }, 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /mine-Vuex/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 |
我是 state 测试:{{ this.$store.state.name }}
13 |
我是 getters 测试:{{ this.$store.getters.decorationName }}
14 | 17 | 20 |
21 | 22 | 23 | 24 | 58 | 59 | -------------------------------------------------------------------------------- /mine-Vue/src/lifecycle.js: -------------------------------------------------------------------------------- 1 | import { createElementVNode, createTextVNode } from "./vdom/index"; 2 | import Watcher from "./observe/watcher"; 3 | import { createElm, patch, patchProps } from "./vdom/patch"; 4 | export function initLifeCycle(Vue) { 5 | Vue.prototype._update = function (vnode) { 6 | // patch既有初始化功能,又有更新的功能 7 | const vm = this; 8 | const el = vm.$el; 9 | // 把组件第一次产生的虚拟节点保存到_vnode上 10 | const preVnode = vm._vnode; 11 | vm._vnode = vnode; 12 | if (preVnode) { 13 | // 之前渲染过 14 | vm.$el = patch(preVnode, vnode); 15 | } else { 16 | vm.$el = patch(el, vnode); 17 | } 18 | }; 19 | Vue.prototype._render = function () { 20 | // 渲染时会去实例上取值 21 | const vm = this; 22 | return vm.$options.render.call(this); //转移后生产的 render方法 23 | }; 24 | // 创造虚拟节点 25 | Vue.prototype._c = function () { 26 | return createElementVNode(this, ...arguments); 27 | }; 28 | // 创建文本虚拟节点 29 | Vue.prototype._v = function () { 30 | return createTextVNode(this, ...arguments); 31 | }; 32 | // 创建普通文字节点 33 | Vue.prototype._s = function (value) { 34 | if (typeof value !== "object") return value; 35 | return JSON.stringify(value); 36 | }; 37 | } 38 | export function mountComponent(vm, el) { 39 | vm.$el = el; 40 | const updateComponent = () => { 41 | vm._update(vm._render()); //vm.$options.render,返回虚拟节点 42 | }; 43 | // 注意,子组件挂载时也会调用这个方法,因此每个子组件也都会对应一个Watcher 44 | // 1.调用render方法,产生虚拟dom 45 | const watcher = new Watcher(vm, updateComponent, true); 46 | // 2.根据虚拟dom产生真实dom 47 | 48 | // 3.插入到el元素中 49 | } 50 | 51 | // 将模板转化为ast模板语法树,ast转化为render函数,后续每次数据更新只执行render函数(无需再转化ast) 52 | // render函数会产生虚拟节点,根据创造的虚拟节点创造真实Dom 53 | 54 | export function callHook(vm, hook) { 55 | const handlers = vm.$options[hook]; 56 | if (handlers) { 57 | handlers.forEach((handler) => { 58 | handler.call(vm); 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mine-VueRouter/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
hello world
11 |
12 | 13 |
14 | 15 | 19 | 20 | 74 | 75 | -------------------------------------------------------------------------------- /mine-Vue/src/vdom/index.js: -------------------------------------------------------------------------------- 1 | const isReservedTag = (tag) => { 2 | return [ 3 | "a", 4 | "div", 5 | "span", 6 | "ul", 7 | "li", 8 | "ol", 9 | "button", 10 | "input", 11 | "h1", 12 | "h2", 13 | "h3", 14 | "p", 15 | "br", 16 | ].includes(tag); 17 | }; 18 | export function createElementVNode(vm, tag, data, ...children) { 19 | if (data == null) { 20 | data = {}; 21 | } 22 | let key = data.key; 23 | if (key) { 24 | delete data.key; 25 | } 26 | // 判断是否是原生标签 27 | if (isReservedTag(tag)) { 28 | return vnode(vm, tag, key, data, children); 29 | } else { 30 | // 创造一个组件的虚拟节点,包含组件的构造函数 31 | let Ctor = vm.$options.components[tag]; //组件的构造函数 32 | // Ctor是组件的定义,可能是配置对象(模板选项)或者是Sub(Vue的子类) 33 | //全局组件是构造函数,否则是对象 34 | return createComponentVNode(vm, tag, key, data, children, Ctor); 35 | // 调用完这个方法之后,vnode.componentInstance上 36 | } 37 | } 38 | function createComponentVNode(vm, tag, key, data, children, Ctor) { 39 | if (typeof Ctor == "object") { 40 | // 确保Ctor一定是构造函数 41 | Ctor = vm.$options._base.extend(Ctor); 42 | } 43 | data.hook = { 44 | // 用于创建真实节点的时候,如果是组件则调用此方法 45 | init(vnode) { 46 | // 保存组件的实例到虚拟节点上 47 | let instance = (vnode.componentInstance = 48 | new vnode.componentOptions.Ctor()); 49 | instance.$mount(); 50 | // 执行后instance上增加了$el 51 | }, 52 | }; 53 | return vnode(vm, tag, key, data, children, null, { Ctor }); 54 | } 55 | export function createTextVNode(vm, text) { 56 | return vnode(vm, undefined, undefined, undefined, undefined, text); 57 | } 58 | // ast是描述JS,css,等语言本身的情况的 59 | // 虚拟dom是描述dom节点的 60 | function vnode(vm, tag, key, data, children, text, componentOptions) { 61 | return { 62 | vm, 63 | tag, 64 | key, 65 | data, 66 | children, 67 | text, 68 | // 包含了组件的构造函数 69 | componentOptions, 70 | }; 71 | } 72 | export function isSameVnode(vnode1, vnode2) { 73 | return vnode1.tag === vnode2.tag && vnode1.key === vnode2.key; 74 | } 75 | -------------------------------------------------------------------------------- /mine-Vuex/lib/vue.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === "object" && typeof module !== "undefined" 3 | ? (module.exports = factory()) 4 | : typeof define === "function" && define.amd 5 | ? define(factory) 6 | : ((global = 7 | typeof globalThis !== "undefined" ? globalThis : global || self), 8 | (global.Vuex = factory())); 9 | })(this, function () { 10 | "use strict"; 11 | 12 | let _Vue = null; 13 | class Vuex { 14 | constructor(options) { 15 | const state = options.state || {}; 16 | const mutations = options.mutations || {}; 17 | const actions = options.actions || {}; 18 | const getters = options.getters || {}; // 直接调用Vue的响应式系统 19 | // state的实现 20 | 21 | this.state = _Vue.observable(state); // getter的实现 22 | 23 | this.getters = Object.create(null); 24 | Object.keys(getters).forEach((key) => { 25 | Object.defineProperty(this.getters, key, { 26 | get: () => { 27 | return getters[key].call(this, this.state); 28 | }, 29 | }); 30 | }); // mutations 31 | 32 | this.mutations = Object.create(null); 33 | Object.keys(mutations).forEach((key) => { 34 | this.mutations[key] = (params) => { 35 | // 改变this指向 ,默认是要传入 state 36 | mutations[key].call(this, this.state, params); 37 | }; 38 | }); //action 39 | 40 | this.actions = Object.create(null); 41 | Object.keys(actions).forEach((key) => { 42 | this.actions[key] = (params) => { 43 | // 改变this指向 ,默认是要传入 store也就是 this 44 | actions[key].call(this, this, params); 45 | }; 46 | }); // commit 47 | 48 | this.commit = (eventName, params) => { 49 | this.mutations[eventName](params); 50 | }; 51 | 52 | this.dispatch = (eventName, params) => { 53 | this.actions[eventName](params); 54 | }; 55 | } 56 | } 57 | 58 | Vuex.install = function (Vue) { 59 | _Vue = Vue; 60 | 61 | _Vue.mixin({ 62 | beforeCreate() { 63 | if (this.$options.store) { 64 | _Vue.prototype.$store = this.$options.store; 65 | } 66 | }, 67 | }); 68 | }; 69 | 70 | return Vuex; 71 | }); 72 | //# sourceMappingURL=vue.js.map 73 | -------------------------------------------------------------------------------- /mine-Vuex/lib/vuex.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === "object" && typeof module !== "undefined" 3 | ? (module.exports = factory()) 4 | : typeof define === "function" && define.amd 5 | ? define(factory) 6 | : ((global = 7 | typeof globalThis !== "undefined" ? globalThis : global || self), 8 | (global.Vuex = factory())); 9 | })(this, function () { 10 | "use strict"; 11 | 12 | let _Vue = null; 13 | class Vuex { 14 | constructor(options) { 15 | const state = options.state || {}; 16 | const mutations = options.mutations || {}; 17 | const actions = options.actions || {}; 18 | const getters = options.getters || {}; // 直接调用Vue的响应式系统 19 | // state的实现 20 | 21 | this.state = _Vue.observable(state); // getter的实现 22 | 23 | this.getters = Object.create(null); 24 | Object.keys(getters).forEach((key) => { 25 | Object.defineProperty(this.getters, key, { 26 | get: () => { 27 | return getters[key].call(this, this.state); 28 | }, 29 | }); 30 | }); // mutations 31 | 32 | this.mutations = Object.create(null); 33 | Object.keys(mutations).forEach((key) => { 34 | this.mutations[key] = (params) => { 35 | // 改变this指向 ,默认是要传入 state 36 | mutations[key].call(this, this.state, params); 37 | }; 38 | }); //action 39 | 40 | this.actions = Object.create(null); 41 | Object.keys(actions).forEach((key) => { 42 | this.actions[key] = (params) => { 43 | // 改变this指向 ,默认是要传入 store也就是 this 44 | actions[key].call(this, this, params); 45 | }; 46 | }); // commit 47 | 48 | this.commit = (eventName, params) => { 49 | this.mutations[eventName](params); 50 | }; 51 | 52 | this.dispatch = (eventName, params) => { 53 | this.actions[eventName](params); 54 | }; 55 | } 56 | } 57 | 58 | Vuex.install = function (Vue) { 59 | _Vue = Vue; 60 | 61 | _Vue.mixin({ 62 | beforeCreate() { 63 | if (this.$options.store) { 64 | _Vue.prototype.$store = this.$options.store; 65 | } 66 | }, 67 | }); 68 | }; 69 | 70 | return Vuex; 71 | }); 72 | //# sourceMappingURL=vuex.js.map 73 | -------------------------------------------------------------------------------- /mine-Vue/mine/index.js: -------------------------------------------------------------------------------- 1 | class Vue { 2 | constructor(options) { 3 | this.$options = options; 4 | this.$el = document.querySelector(options.el); 5 | this.$template = this.$el.innerHTML; 6 | this.initMethods(); 7 | // 初始化数据前调用'beforeCreated'生命周期 8 | this.dispatchLifeCiryle("beforeCreated"); 9 | this.initData(); 10 | // 初始化数据后调用'created'生命周期 11 | this.dispatchLifeCiryle("created"); 12 | this.patch(); 13 | //挂载dom后调用mounted的生命周期 14 | this.dispatchLifeCiryle("mounted"); 15 | } 16 | // 初始化data,进行响应式处理和数据劫持 17 | initData() { 18 | const vm = this; 19 | if (typeof vm.$options.data == "function") { 20 | this.$data = this.$options.data(); 21 | } else { 22 | this.$data = this.$options.data; 23 | } 24 | Object.keys(this.$data).forEach((data) => { 25 | // 这里仅考虑了一般对象的情况,实际上vue会考虑数组(重写原型方法)和深度递归(遍历进行响应式处理)的情况 26 | Object.defineProperty(vm, data, { 27 | get() { 28 | return vm["$data"][data]; 29 | }, 30 | set(newValue) { 31 | vm["$data"][data] = newValue; 32 | vm.patch(); 33 | }, 34 | }); 35 | }); 36 | } 37 | // 调用生命周期方法 38 | dispatchLifeCiryle(name) { 39 | const fun = this.$options[name]; 40 | if (fun) { 41 | fun.call(this); 42 | } 43 | } 44 | // 对methods进行初始化 45 | initMethods() { 46 | const methods = this.$options.methods || {}; 47 | const vm = this; 48 | Object.keys(methods).forEach((method) => { 49 | if (typeof methods[method] === "function") { 50 | methods[method].bind(vm); 51 | Object.defineProperty(vm, method, { 52 | get() { 53 | return methods[method]; 54 | }, 55 | }); 56 | } 57 | }); 58 | } 59 | patch() { 60 | // 这里的patch方法仅为了便于理解更新的操作,实际完全不是这样渲染的 61 | // 真实的vue会将模板转化为虚拟dom,走diff算法对比并最终编译为render函数进行渲染 62 | const getAllBracketConetent = /\{\{([0-1a-zA-Z]+)\}\}/g; 63 | const resultList = this.$template.replaceAll( 64 | getAllBracketConetent, 65 | (current) => { 66 | const key = current.slice(2, -2); 67 | return this.$data[key]; 68 | } 69 | ); 70 | this.dispatchLifeCiryle("beforeUpdated"); 71 | this.$el.innerHTML = resultList; 72 | this.dispatchLifeCiryle("updated"); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /mine-Vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | import { parseHTML } from "./parse"; 2 | // 匹配{{}} 3 | const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; 4 | function genProps(attrs) { 5 | let str = ""; 6 | for (let i = 0; i < attrs.length; i++) { 7 | let attr = attrs[i]; 8 | // style要做特殊处理 9 | if (attr.name == "style") { 10 | let obj = {}; 11 | attr.value.split(";").forEach((item) => { 12 | let [key, value] = item.split(":"); 13 | obj[key] = value; 14 | }); 15 | attr.value = obj; 16 | } 17 | str += `${attr.name}:${JSON.stringify(attr.value)},`; 18 | } 19 | return `{${str.slice(0, -1)}}`; 20 | } 21 | // 将children生成代码 22 | function genChildren(children) { 23 | if (children) { 24 | return children 25 | .map((child) => { 26 | return gen(child); 27 | }) 28 | .join(","); 29 | } 30 | } 31 | function gen(node) { 32 | // 如果有子节点就递归生成 33 | if (node.type === 1) { 34 | return codegen(node); 35 | } else { 36 | let text = node.text; 37 | if (!defaultTagRE.test(text)) { 38 | // 文本节点直接格式化处理 39 | return `_v(${JSON.stringify(text)})`; 40 | } else { 41 | // 操作模板语法,将模板语法替换为变量 42 | let tokens = []; 43 | let match; 44 | // 注意这里将正则的lastIndex重置为0,每次的行为一致 45 | defaultTagRE.lastIndex = 0; 46 | let lastIndex = 0; 47 | while ((match = defaultTagRE.exec(text))) { 48 | let index = match.index; 49 | if (index > lastIndex) { 50 | // 添加模板引擎之前/之后的内容 51 | tokens.push(JSON.stringify(text.slice(lastIndex, index))); 52 | } 53 | // 将模板中的变量添加进去 54 | tokens.push(`_s(${match[1].trim()})`); 55 | lastIndex = index + match[0].length; 56 | } 57 | if (lastIndex < text.length) { 58 | // 添加一般的文本 59 | tokens.push(JSON.stringify(text.slice(lastIndex))); 60 | } 61 | return `_v(${tokens.join("+")})`; 62 | } 63 | } 64 | } 65 | // 将ast语法树生成render函数 66 | function codegen(ast) { 67 | let children = genChildren(ast.children); 68 | let code = `_c('${ast.tag}',${ 69 | ast.attrs.length > 0 ? genProps(ast.attrs) : "null" 70 | }${ast.children.length ? `,${children}` : ""})`; 71 | return code; 72 | } 73 | export function complieToFunction(template) { 74 | let ast = parseHTML(template); 75 | let code = codegen(ast); 76 | // 绑定this并利用Function生成函数 77 | code = `with(this){return ${code}}`; 78 | let render = new Function(code); 79 | return render; 80 | } 81 | -------------------------------------------------------------------------------- /mine-Vue/src/observe/index.js: -------------------------------------------------------------------------------- 1 | import { newArrayProto } from "./array"; 2 | import Dep from "./dep"; 3 | class Observe { 4 | // 给每个对象都增加收集功能 5 | // 要给数组和对象本身也增加dep,如果用户增添了属性或数组新增了一项,都会触发dep 6 | constructor(data) { 7 | // 给数据添加一个表示__ob__,被标识的数据标识已经被观测过了 8 | //data.__ob__=this 直接将this添加到__ob__后,会导致遍历可观测对象时遍历到this,形成死循环 9 | // 添加属性__ob__并将这个属性设置为不可枚举,使其在遍历时无法被遍历 10 | this.dep = new Dep(); 11 | Object.defineProperty(data, "__ob__", { 12 | value: this, 13 | enumerable: false, 14 | }); 15 | if (Array.isArray(data)) { 16 | // 用户一般不会通过索引调用数组的值,直接遍历又会导致性能问题 17 | //因此我们可以通过重写数组7个变异方法的方式来监控数据变化 18 | //同时应该考虑数组中对象的劫持 19 | data.__proto__ = newArrayProto; 20 | this.observeArray(data); //监控数组中的对象,只将数组中的对象进行挂载 21 | } else { 22 | this.walk(data); 23 | } 24 | // Object.defineProperty只能劫持已经存在的属性 25 | } 26 | walk(data) { 27 | //循环对象,对属性依次劫持,重新定义属性 28 | Object.keys(data).forEach((key) => { 29 | defineReactive(data, key, data[key]); 30 | }); 31 | } 32 | observeArray(data) { 33 | data.forEach((item) => { 34 | observe(item); 35 | }); 36 | } 37 | } 38 | function dependArray(value) { 39 | // 对数组的每一个元素进行观察 40 | for (let i = 0; i < value.length; i++) { 41 | // 如果数组中有对象(有__ob__表示是对象且被标记过),那么需要将数组中的所有对象进行观测 42 | value[i].__ob__ && value[i].__ob__.dep.depend(); 43 | // 如果数组中的子元素还是数组,则继续递归 44 | if (Array.isArray(value[i])) { 45 | dependArray(value[i]); 46 | } 47 | } 48 | } 49 | export function defineReactive(target, key, value) { 50 | // 闭包,从外部拿到value 51 | // 如果劫持到的属性依然是一个对象,就应该递归劫持所有属性,深度属性劫持 52 | let childOb = observe(value); 53 | // 每一个属性都有一个dep,这里是闭包,因此变量不会销毁 54 | let dep = new Dep(); 55 | Object.defineProperty(target, key, { 56 | get() { 57 | // 如果Dep.target不为null,证明这个属性被某个watch依赖 58 | if (Dep.target) { 59 | dep.depend(); 60 | if (childOb) { 61 | // 让数组和对象也实现依赖收集 62 | // 如果出现对象套对象的情况,就将这个属性继续放入dep队列观察,深度遍历 63 | childOb.dep.depend(); 64 | // 当出现数组套数组的情况时,进行深度遍历 65 | if (Array.isArray(value)) { 66 | dependArray(value); 67 | } 68 | } 69 | } 70 | return value; 71 | }, 72 | set(newValue) { 73 | if (newValue == value) return; 74 | value = newValue; 75 | // 通知所有依赖这个属性的watch更新视图 76 | dep.notify(); 77 | }, 78 | }); 79 | } 80 | export function observe(data) { 81 | if (typeof data != "object" || data == null) { 82 | return; //只对对象进行劫持 83 | } 84 | //判断对象是否被劫持过,需要用一个实例来观测判断 85 | 86 | return new Observe(data); 87 | } 88 | -------------------------------------------------------------------------------- /mine-Vue/src/state.js: -------------------------------------------------------------------------------- 1 | import Dep from "./observe/dep"; 2 | import { observe } from "./observe/index"; 3 | import Watcher from "./observe/watcher"; 4 | import { nextTick } from "./observe/watcher"; 5 | export function initState(vm) { 6 | const opts = vm.$options; 7 | if (opts.data) { 8 | initData(vm); 9 | } 10 | if (opts.computed) { 11 | initComputed(vm); 12 | } 13 | if (opts.watch) { 14 | initWatch(vm); 15 | } 16 | } 17 | function initWatch(vm) { 18 | let { watch } = vm.$options; 19 | for (let key in watch) { 20 | const handler = watch[key]; 21 | if (Array.isArray(handler)) { 22 | for (let i = 0; i < handler.length; i++) { 23 | createWatcher(vm, key, handler[i]); 24 | } 25 | } else { 26 | createWatcher(vm, key, handler); 27 | } 28 | } 29 | } 30 | 31 | function createWatcher(vm, key, handler) { 32 | if (typeof handler === "string") { 33 | handler = vm[handler]; 34 | } 35 | return vm.$watch(key, handler); 36 | } 37 | function proxy(vm, target, key) { 38 | Object.defineProperty(vm, key, { 39 | get() { 40 | return vm[target][key]; 41 | }, 42 | set(newValue) { 43 | vm[target][key] = newValue; 44 | }, 45 | }); 46 | } 47 | function initData(vm) { 48 | let { data } = vm.$options; 49 | data = typeof data == "function" ? data.call(vm) : data; 50 | vm._data = data; 51 | observe(data); 52 | for (let key in data) { 53 | proxy(vm, "_data", key); 54 | } 55 | } 56 | 57 | function initComputed(vm) { 58 | const computed = vm.$options.computed; 59 | const watchers = (vm._computedWatchers = {}); 60 | for (let key in computed) { 61 | let userDef = computed[key]; 62 | // 我们需要监控计算属性中get的变化 63 | let fn = typeof userDef === "function" ? userDef : userDef.get; 64 | // 如果直接new watcher,默认立即执行fn 65 | watchers[key] = new Watcher(vm, fn, { lazy: true }); 66 | defineComputed(vm, key, userDef); 67 | } 68 | } 69 | 70 | function defineComputed(target, key, userDef) { 71 | const getter = typeof userDef === "function" ? userDef : userDef.get; 72 | const setter = userDef.set || (() => {}); 73 | Object.defineProperty(target, key, { 74 | get: createComputedGatter(key), 75 | set: setter, 76 | }); 77 | } 78 | // 计算属性不会手收集依赖,只会让自己的依赖属性去收集依赖 79 | function createComputedGatter(key) { 80 | // 检测是否执行gatter 81 | return function () { 82 | // 获取到对应属性的watcher 83 | const watcher = this._computedWatchers[key]; 84 | if (watcher.dirty) { 85 | // 如果是脏的,就去执行用户传入的函数 86 | watcher.evalute(); 87 | // 求值后dirty变为false,下次就不求值了 88 | } 89 | if (Dep.target) { 90 | // 计算属性出栈后还有渲染watcher,应该让计算属性watcher里的属性也去收集渲染watcher 91 | watcher.depend(); 92 | } 93 | // 最后返回的是watch上的值 94 | return watcher.value; 95 | }; 96 | } 97 | 98 | export function initStateMixin(Vue) { 99 | Vue.prototype.$nextTick = nextTick; 100 | // 所有watch方法的底层都是在调用$watch 101 | Vue.prototype.$watch = function (exprOrFn, cb, options = {}) { 102 | // expOrFn可能是一个变量,也可能是函数 103 | new Watcher(this, exprOrFn, { user: true }, cb); 104 | }; 105 | } 106 | -------------------------------------------------------------------------------- /mine-Vue/src/compiler/parse.js: -------------------------------------------------------------------------------- 1 | const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`; 2 | // 下面的这个正则中的:表示匹配命名空间: 3 | const qnameCapture = `((?:${ncname}\\:)?${ncname})`; 4 | // 匹配前标签开始
]>*>`); 8 | // 匹配属性,第一个分组是属性的key,属性的值是分组3/4/5 9 | const attribute = 10 | /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>']+)))?/; 11 | //匹配前标签结束 12 | const startTagClose = /^\s*(\/?)>/; 13 | // 匹配{{}} 14 | const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; 15 | // 转化为ast模板语法树 16 | export function parseHTML(html) { 17 | const ELEMENT_TYPE = 1; 18 | const TEXT_TYPE = 3; 19 | const stack = []; 20 | let currentParent; 21 | let root; 22 | // 创建节点 23 | function createASTElement(tag, attrs) { 24 | return { 25 | tag, 26 | type: ELEMENT_TYPE, 27 | children: [], 28 | attrs, 29 | parent: null, 30 | }; 31 | } 32 | function advance(n) { 33 | html = html.substring(n); 34 | } 35 | // 在解析的各个阶段建立一颗ast语法树 36 | function start(tag, attrs) { 37 | let node = createASTElement(tag, attrs); 38 | if (!root) { 39 | root = node; 40 | } 41 | // 如果有栈中有值,就将栈中最后一个元素作为parent 42 | if (currentParent) { 43 | // 这里要同时建立节点的父子关系 44 | node.parent = currentParent; 45 | currentParent.children.push(node); 46 | } 47 | // 将当前的节点推入栈中,并更新当前的父节点 48 | stack.push(node); 49 | currentParent = node; 50 | } 51 | function end(tag) { 52 | // 出栈并更新当前父节点 53 | stack.pop(); 54 | currentParent = stack[stack.length - 1]; 55 | } 56 | function char(text) { 57 | // 处理文本节点 58 | text = text.replace(/\s/g, ""); 59 | text && 60 | currentParent.children.push({ 61 | type: TEXT_TYPE, 62 | text, 63 | parent: currentParent, 64 | }); 65 | } 66 | // 解析开始标签,收集属性 67 | function parseStartTag() { 68 | const start = html.match(startTagOpen); 69 | if (start) { 70 | const match = { 71 | tagName: [start[1]], //标签名 72 | attrs: [], 73 | }; 74 | advance(start[0].length); 75 | // 如果不是开始标签的结束,就一直匹配下去 76 | let attr, end; 77 | while ( 78 | !(end = html.match(startTagClose)) && 79 | (attr = html.match(attribute)) 80 | ) { 81 | advance(attr[0].length); 82 | match.attrs.push({ 83 | name: attr[1], 84 | value: attr[3] || attr[4] || attr[5] || true, 85 | }); 86 | } 87 | if (end) { 88 | advance(end[0].length); 89 | } 90 | return match; 91 | } 92 | return false; 93 | } 94 | while (html) { 95 | // textEnd如果为0,就是一个开始标签或结束标签 96 | //textEnd>0,说明是一个文本 97 | let textEnd = html.indexOf("<"); //如果indexOf中的索引是0,就是一个标签 98 | if (textEnd == 0) { 99 | const startTagMatch = parseStartTag(); 100 | if (startTagMatch) { 101 | // 解析到开始标签 102 | start(startTagMatch.tagName, startTagMatch.attrs); 103 | continue; 104 | } 105 | let endTagMatch = html.match(endTag); 106 | if (endTagMatch) { 107 | advance(endTagMatch[0].length); 108 | end(endTagMatch[1]); 109 | continue; 110 | } 111 | } 112 | if (textEnd > 0) { 113 | let text = html.substring(0, textEnd); //文本内容 114 | if (text) { 115 | char(text); 116 | advance(text.length); 117 | } 118 | continue; 119 | } 120 | } 121 | return root; 122 | } 123 | -------------------------------------------------------------------------------- /mine-Vuex/lib/vue.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vue.js","sources":["../src/index.js"],"sourcesContent":["let _Vue = null;\nexport default class Vuex {\n constructor(options) {\n const state = options.state || {};\n const mutations = options.mutations || {};\n const actions = options.actions || {};\n const getters = options.getters || {};\n // 直接调用Vue的响应式系统\n // state的实现\n this.state = _Vue.observable(state);\n // getter的实现\n this.getters = Object.create(null);\n Object.keys(getters).forEach((key) => {\n Object.defineProperty(this.getters, key, {\n get: () => {\n return getters[key].call(this, this.state);\n },\n });\n });\n // mutations\n this.mutations = Object.create(null);\n Object.keys(mutations).forEach((key) => {\n this.mutations[key] = (params) => {\n // 改变this指向 ,默认是要传入 state\n mutations[key].call(this, this.state, params);\n };\n });\n //action\n this.actions = Object.create(null);\n Object.keys(actions).forEach((key) => {\n this.actions[key] = (params) => {\n // 改变this指向 ,默认是要传入 store也就是 this\n actions[key].call(this, this, params);\n };\n });\n // commit\n this.commit = (eventName, params) => {\n this.mutations[eventName](params);\n };\n this.dispatch = (eventName, params) => {\n this.actions[eventName](params);\n };\n }\n}\n\nVuex.install = function (Vue) {\n _Vue = Vue;\n _Vue.mixin({\n beforeCreate() {\n if (this.$options.store) {\n _Vue.prototype.$store = this.$options.store;\n }\n },\n });\n};\n"],"names":["_Vue","Vuex","constructor","options","state","mutations","actions","getters","observable","Object","create","keys","forEach","key","defineProperty","get","call","params","commit","eventName","dispatch","install","Vue","mixin","beforeCreate","$options","store","prototype","$store"],"mappings":"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"} -------------------------------------------------------------------------------- /mine-Vuex/lib/vuex.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vuex.js","sources":["../src/index.js"],"sourcesContent":["let _Vue = null;\nexport default class Vuex {\n constructor(options) {\n const state = options.state || {};\n const mutations = options.mutations || {};\n const actions = options.actions || {};\n const getters = options.getters || {};\n // 直接调用Vue的响应式系统\n // state的实现\n this.state = _Vue.observable(state);\n // getter的实现\n this.getters = Object.create(null);\n Object.keys(getters).forEach((key) => {\n Object.defineProperty(this.getters, key, {\n get: () => {\n return getters[key].call(this, this.state);\n },\n });\n });\n // mutations\n this.mutations = Object.create(null);\n Object.keys(mutations).forEach((key) => {\n this.mutations[key] = (params) => {\n // 改变this指向 ,默认是要传入 state\n mutations[key].call(this, this.state, params);\n };\n });\n //action\n this.actions = Object.create(null);\n Object.keys(actions).forEach((key) => {\n this.actions[key] = (params) => {\n // 改变this指向 ,默认是要传入 store也就是 this\n actions[key].call(this, this, params);\n };\n });\n // commit\n this.commit = (eventName, params) => {\n this.mutations[eventName](params);\n };\n this.dispatch = (eventName, params) => {\n this.actions[eventName](params);\n };\n }\n}\n\nVuex.install = function (Vue) {\n _Vue = Vue;\n _Vue.mixin({\n beforeCreate() {\n if (this.$options.store) {\n _Vue.prototype.$store = this.$options.store;\n }\n },\n });\n};\n"],"names":["_Vue","Vuex","constructor","options","state","mutations","actions","getters","observable","Object","create","keys","forEach","key","defineProperty","get","call","params","commit","eventName","dispatch","install","Vue","mixin","beforeCreate","$options","store","prototype","$store"],"mappings":"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"} -------------------------------------------------------------------------------- /mine-Vue/src/observe/watcher.js: -------------------------------------------------------------------------------- 1 | import Dep from "./dep"; 2 | import { pushTarget, popTarget } from "./dep"; 3 | let id = 0; 4 | // 解析一般data时只会创建一个渲染watcher,当解析计算属性时,会按栈结构去创建计算属性watcher 5 | // watcher的作用时:当依赖的dep发生更新时,对应地触发某些操作(比如重新渲染) 6 | class Watcher { 7 | constructor(vm, exprOrFn, options, cb) { 8 | this.id = id++; 9 | this.renderWatcher = vm.options; 10 | // getter意味着调用这个函数会发生取值 11 | if (typeof exprOrFn === "string") { 12 | this.getter = function () { 13 | return vm[exprOrFn]; 14 | }; 15 | } else { 16 | this.getter = exprOrFn; 17 | } 18 | // 让watcher去记住所有dep,后续实现计算属性和清理工作需要使用 19 | this.deps = []; 20 | this.depsId = new Set(); 21 | this.lazy = options.lazy; 22 | this.dirty = this.lazy; 23 | this.vm = vm; 24 | // 标识是否是用户自己的watcher 25 | this.user = options.user; 26 | this.cb = cb; 27 | // 计算属性第一次并不执行 28 | this.value = this.lazy ? undefined : this.get(); 29 | } 30 | evalute() { 31 | // 获取到用户函数的返回值,并标识为脏 32 | this.value = this.get(); 33 | this.dirty = false; 34 | } 35 | get() { 36 | // 将自己添加到Dep的静态属性上,让之后每个dep都可以添加到这个watch 37 | pushTarget(this); 38 | // 这个getter就是更新函数 39 | let value = this.getter.call(this.vm); 40 | // 将这个静态属性置为空 41 | popTarget(); 42 | return value; 43 | } 44 | update() { 45 | // 当dep是计算属性 46 | // 当依赖的值发生变化时dirty是脏值 47 | if (this.lazy) { 48 | this.dirty = true; 49 | } 50 | // 重新渲染,这里为了防止多次更新视图,采用了事件环的方式合并多次操作 51 | queueWatcher(this); 52 | } 53 | depend() { 54 | let i = this.deps.length; 55 | while (i--) { 56 | this.deps[i].depend(); //让计算属性watcher也收集渲染watcher 57 | } 58 | } 59 | addDep(dep) { 60 | // 一个组件对应着多个属性,重复的属性也不用记录 61 | let id = dep.id; 62 | if (!this.depsId.has(id)) { 63 | this.deps.push(dep); 64 | this.depsId.add(id); 65 | dep.addSub(this); 66 | } 67 | } 68 | run() { 69 | let oldValue = this.value; 70 | let newValue = this.get(); 71 | // user标识用户自定义的watcher 72 | if (this.user) { 73 | // 监控的值(dep)会收集watcher,如果监控的值(dep)发生了改变,就会执行对应的回调 74 | this.cb.call(this.vm, newValue, oldValue); 75 | } 76 | } 77 | } 78 | let queue = []; 79 | let has = {}; 80 | let pending = false; 81 | function flushSchedulerQueue() { 82 | let flushQueue = queue.slice(0); 83 | flushQueue.forEach((q) => { 84 | q.run(); 85 | }); 86 | queue = []; 87 | has = {}; 88 | pending = false; 89 | } 90 | function queueWatcher(watcher) { 91 | const id = watcher.id; 92 | if (!has[id]) { 93 | queue.push(watcher); 94 | has[id] = true; 95 | // 不论update执行多少次,只执行一轮刷新操作 96 | // 多次操作只走第一次,后面的操作都会被放到队列里,等第一次执行完后下一个事件环执行 97 | if (!pending) { 98 | timerFunc(flushSchedulerQueue); 99 | pending = true; 100 | } 101 | } 102 | } 103 | let callbacks = []; 104 | let waiting = false; 105 | function flushCallbacks() { 106 | let cbs = callbacks.slice(0); 107 | cbs.forEach((cb) => cb()); 108 | waiting = false; 109 | callbacks = []; 110 | } 111 | // nextTick不是创建了一个异步任务,而是将这个任务维护到了队列中 112 | // nextTick内部采用优雅降级:promise->MutationObserver->setImmediate->setTimeout 113 | let timerFunc; 114 | if (Promise) { 115 | timerFunc = (fn) => { 116 | Promise.resolve().then(fn); 117 | }; 118 | } else if (MutationObserver) { 119 | // 这里传入的回调是异步任务 120 | timerFunc = (fn) => { 121 | let observe = new MutationObserver(fn); 122 | let textNode = document.createElement(1); 123 | observe.observe(textNode, { 124 | characterData: true, 125 | }); 126 | textNode.textContent = 2; 127 | }; 128 | } else if (setImmediate) { 129 | timerFunc = (fn) => { 130 | setImmediate(fn); 131 | }; 132 | } else { 133 | timerFunc = (fn) => { 134 | setTimeout(fn, 0); 135 | }; 136 | } 137 | export const nextTick = function (cb) { 138 | callbacks.push(cb); 139 | if (!waiting) { 140 | timerFunc(flushCallbacks); 141 | waiting = true; 142 | } 143 | }; 144 | // 需要给每个属性增加dep, 145 | // n个属性对应一个视图,n个dep对应一个watcher 146 | // 一个属性对应多个视图 1个dep对应多个watcher 147 | // 多对多关系 148 | export default Watcher; 149 | -------------------------------------------------------------------------------- /docs/essay.md: -------------------------------------------------------------------------------- 1 | ## 入口文件 2 | 3 | 构建出来的入口文件路径:src/platforms/web/entry-runtime-with-compiler.js: 4 | 5 | 其中 Vue 的路径:src/platforms/web/runtime/index.js 6 | 7 | 初始化 Vue 的路径:src/core/index.js 8 | 9 | Vue 是一个构造函数,它可以传入到其他函数中扩展 Vue 的功能,相比于 class 更具可扩展性 10 | 11 | Vue 在初始化的过程中会在它的原型链和 Vue 本身上挂载方法和属性 12 | 13 | 被挂载在 Vue 上的静态方法: 14 | 15 | ```js 16 | config; 17 | Vue.util = { 18 | warn, 19 | extend, 20 | mergeOptions, 21 | defineReactive, 22 | }; 23 | Vue.set = set; 24 | Vue.delete = del; 25 | Vue.nextTick = nextTick; 26 | // ASSET_TYPES是component,directive,filter 27 | Vue.options = Object.create(null); 28 | ASSET_TYPES.forEach((type) => { 29 | Vue.options[type + "s"] = Object.create(null); 30 | }); 31 | ``` 32 | 33 | 属于内置自定义指令的只有 v-show 和 v-model 34 | 35 | ## 数据驱动 36 | 37 | ### Vue 初始化 38 | 39 | 在 new Vue 时会调用\_init 方法,而这个方法是在 initMixin 这个方法中被挂载到 Vue 的原型链上的 40 | 41 | vue 初始化做的几件事: 42 | 43 | 合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。 44 | 45 | ```js 46 | initLifecycle(vm); 47 | initEvents(vm); 48 | initRender(vm); 49 | callHook(vm, "beforeCreate"); 50 | initInjections(vm); // resolve injections before data/props 51 | initState(vm); 52 | initProvide(vm); // resolve provide after data/props 53 | callHook(vm, "created"); 54 | ``` 55 | 56 | ### mount 57 | 58 | mount 是通过原型链上$mount 这个方法实现的,Vue 会先缓存原先的方法,再重新实现这个方法,这样做的目的是原先的方法可以被 runtime only 直接复用,而新实现的方法可以支持模板语法和挂载点的语法 59 | 原先原型上的 $mount 方法在 src/platform/web/runtime/index.js 60 | 61 | 这个方法做了限制,Vue 不能挂载在 body、html 这样的根节点上;Vue 始终会调用 render 方法去渲染视图,如果没有这个方法,Vue 会调用 compileToFunctions 方法将 el 或模板转化为 render 方法,最终这个方法会去调用 mountComponent(src/core/instance/lifecycle.js)这个方法,这个方法会生成虚拟 DOM 并更新节点,同时执行生命周期 62 | 63 | v-if 编译时会变成三元表达式(编译时进行) 64 | 65 | v-for 编译时会变成\_l 函数 66 | 67 | v-show 编译时会变成自定义指令(运行时进行) 68 | 69 | v-show 会根据原先的 display 属性作为原始 display(不会出现块元素转变的问题) 70 | 71 | v-model 会在内部用 compsing 去优化输入(不会在打字时监听),他包括模板语法和自定义指令两个部分组成,会根据 input 的值去更改绑定方法 72 | 73 | v-model 可以绑定组件,该组件传入一个 model 对象,自定义 props 和 emit,可以手动触发绑定,如果没有传入则为 value 和 input 事件 74 | 75 | vue .sync 修饰符的作用:跟 v-model 一样,实现状态同步(解决重名问题),在绑定的组件内部可以用 update:xx 触发事件调用,(跟 v-model 类似) 76 | 77 | Vue.ues:会进行缓存,如果已经注册过直接返回 this 78 | 79 | 组件中写 name 的作用:在 Vue 中,有 name 属性的组件可以被递归调用(递归调用需要用 v-if=false 来显示终止),在声明组件的时候如果有 name,则有 Sub.options.components[name]=Sub,将自己的构造函数放在了选项上 80 | 81 | 普通的插槽在父组件当中渲染数据,并注入到子组件,编译时组件的孩子变成插槽,放到 compentOptions 上;元素的孩子编译成子元素 82 | 83 | 获取到插槽后会进行转化成具名对象(映射表)(默认为 default),对象值是插槽的虚拟节点(数组)。这个对象会被挂载在在 vm.$slot上,之后会合并到$scopeSlots 84 | 85 | 当模板编译解析到 slot 时,会编译成\_t 函数,这个函数的参数是需要插槽的名称,\_t 执行时会返回名称对应插槽虚拟节点 86 | 87 | 作用域插槽不会作为 children,而是会转化成 scopedSlots 88 | 89 | 作用域插槽会编译\_u 函数,利用映射表将 slot 和父元素进行对应,稍后渲染组件模板的时候,会通过 name 找到对应的函数,将数据传入对应的函数后,才用虚拟节点替换真实节点,实现使用子作用域的数据 90 | 91 | keep-alive 是一个虚拟组件,通过获取插槽($slot)来获取渲染的内容,其会寻找第一个组件,在判断是否有缓存后缓存其实例,内部维护的缓存表是通过组件的 cid+tag 生成 key 来进行判断的,内部维护缓存的算法是 lru 算法 92 | 93 | 缓存直接通过组件实例对应挂载的 el,因此切换组件时不会走挂载的生命周期,相当于走了更新的流程 94 | 95 | vue 修饰符会修改模板编译时,自动生成一些代码,比如 prevent 编译为 vent.preventDefault(),也有一部分会编译为特殊的事件(增加前缀),比如 once,capture,来在运行时生效 96 | 97 | Vue.$set 方法:vm.age.**ob**.dep.notify(),如果通过索引给数组对象添加则调用 splice 方法,如果给对象添加最后要调用 defineReactive 方法 98 | 99 | diff 算法是评级比较,双方一方有儿子,一方没有则增删,如果都有儿子则进行双端对比(头头,尾尾,交叉对比),如果双端对比失败则开始维护映射表, 100 | 用新的去映射表中查找该元素是否存在,如果存在则移动,不存在则插入,最后删除多余的节点 101 | 102 | vue3 增加了最长子序列算法,来降低无效的节点移动(保留相对位置) 103 | 104 | 虚拟 dom 的优势:跨平台,底层不受限制,无需考虑兼容性问题,同时可以跟 diff 算法配合减小更新幅度 105 | 106 | inject/provide:在孙子组件中注入属性(非响应式) 107 | 108 | - provide:在当前组件上提供了一个 provide 属性(增加了一个对象) 109 | - inject 会将设置的 inject 在上层的 provide 中进行递归查找,找到后将其用 defineReactive 定义在当前组件实例上(递归向上层的$parent 中进行查找,找到一个就停止) 110 | 111 | $attrs:所有组件上的属性,不包括 props。配置上有属性 inheritAttrs 来标识组件的属性是否都要放在组件的根元素上 112 | 113 | $listeners:组件上所有绑定的事件 114 | 115 | 这两个属性都是用 defineReactive 进行定义的,因此都是响应式的 116 | 117 | 组件的渲染流程: 118 | 119 | * 利用vue.extend生成组件构造函数((Ctor)解析到非内置标签,去options中寻找注册的组件,尝试走缓存,extend生成子类,子类继承Vue的原型并合并配置), 120 | * 根据组件产生虚拟节点,(添加生命周期钩子,添加事件,vnode上会挂载componentInstance和componentOptions,组件实例上有$el真实节点,$el会在vm._update的时候获取patch创建的真实节点) 121 | * 组件初始化,将虚拟节点转化为真实节点,new Sub().$mount()(调用挂载方法,生成render函数并调用,创建watcher)(createCompent->组件的init方法($mount),所有组件(children)循环创建真实节点并替换组件节点) 122 | * 当组件的渲染流程走完(真实节点替换了组件标签),组件的父组件会执行插入流程 123 | 124 | 组件更新的几种情况: 125 | 126 | * data数据更新,依赖收集 127 | * 属性更新,可以给组件传入属性,属性变化后更新 128 | * 插槽变化更新 129 | 130 | 组件更新时会复用实例,并调用 updateChildComponent 方法,传入 props,插槽,事件进行比较(prepatch 方法) 131 | 132 | 之后,组件会: 133 | _ 执行 toggleObserving(false),如果不是根组件,那么将可观测性暂时切换为 false,不再对其进行观测(props 已经被观测且是响应式了,防止重复响应式处理) 134 | _ 更新属性,拿到新的 props 后用 validate 进行验证(类型和合法性,是否有对应的属性) 135 | _ 更新 listners 和 attrs 136 | _ 组件更新后会重新给 props 赋值,赋值完成后触发 watcher 更新(由于直接是父组件的响应式数据,因此父组件数据更新后子组件会同步更新) 137 | 138 | vue 中的异步组件,主要用作比较大的组件进行异步加载。原理是先渲染一个注释标签,等组件加载完毕后重新渲染(forceUpdate 方法),类似于图片懒加载 139 | 使用异步组件会配合 webpack 140 | 141 | 组件渲染会确认 Ctor 实例是对象才会渲染,而异步组件的返回值是函数,因此第一次不会渲染 142 | 143 | 另外,由于异步组件的 Ctor 是函数,默认不会执行 Vue.extend 方法,,因此 Ctor 上没有 cid 属性,没有 cid 属性的就是异步组件,此时就会将 Ctor 赋值给 asyncFactory 144 | 145 | 解析异步组件时,会调用 resolveAsyncComonpent 方法并传入 asyncFactory 和 Vue,如果解析完返回值是 undefined,那么会创建一个异步组件的占位符(vnode)进行渲染,同时,组件的内部会组装出 Promise 的 resolve 和 reject 方法并向参数中的 Promise 中传入执行,如果返回值是 promise,就会调用 promsie.then,默认渲染 loading,如果状态为 resolve(更改 sync 状态)就渲染重新执行解析方法并生成虚拟节点 146 | 147 | 组件重新渲染后,factory 上的 resolved/error 已经被挂载实例,就会直接渲染,否则如果返回的依旧是 promise 的话,会递归执行,继续渲染 loading 148 | 149 | 函数式组件的好处:没有 watcher,性能更好。直接调用 render 创建 vnode,没有事件,data,生命周期等。更适合来做纯渲染的组件 150 | 151 | 由 prop 定义的属性才叫 prop,其余的属性会被收集在$attrs,生成组件实例时,会在组件的虚拟节点上增加componentOptions.propsData属性,最终这个属性会在实例化(虚拟dom转真实dom)时被挂载到vm.$options.propsData,最后在初始化(initProps)时挂载到 vm.\_props 上 152 | 153 | 初始化 prop 的过程中会将\_props 用 defineReactive 定义成响应式的,且会将 vm.\_props 的值代理到 vm 上(这里定义成响应式是保证修改 props 会更新视图,与 prop 传入时不会被重新观测不冲突) 154 | 155 | 组件更新会调用子组件的 prepatch,子组件就会对收到的 props 进行更新(修改 vm.\_props 触发响应式,data 更新同理) 156 | 157 | 总而言之,父组件中绑定的值是根据父组件的 data 进行响应式的,而在子组件中,prop 是重新定义的子组件内部的响应式,这两者是通过重新赋值(组件的 DataProp 和 vm.\_props 之间的转化)进行关联的,第一次渲染时\_props 会被定义响应式,之后每次父组件的属性变更,子组件的\_props 会被重新赋值而触发响应式 158 | 159 | data 和 props 或 methods 重名时,会在初始化 data 时进行校验并抛出警告,但 props 的优先级更高 160 | 161 | 事件的实现: 162 | 163 | vue 可以类似于 react 那样,通过 props 传递函数进行数据传递,但要将函数写在 data 中去防止绑定 this 164 | 165 | 如果使用自定义事件进行传参。那么就是基于发布订阅模式进行通信,使用@事件的写法,在模板编译时会被转译为 on:{事件:function}的模式,在子组件中可以通过$emit 触发对应的函数,如果希望原生事件触发,则可以通过.native 修饰符对事件进行修饰,编译时会编译出 nativeOn 事件 166 | 167 | 在之后的处理过程(编译 Vnode)中,data.on 会被放在 listener 上,而 nativeOn 会被真正挂载在 on 上,在初始化组件的过程中,listener 上的事件会通过中介 opts。\_parentListeners,被放入 updateListeners 中更新或初始化事件,这个过程也就是发布订阅模式添加和更新的过程(利用$on,$off,$emit 维护 vm.\_event 这个事件发布订阅中心) 168 | 169 | methods:methods 在处理事件时会绑定当前组件实例的 this 170 | 171 | ref:可以获取真实节点或组件实例,虚拟 dom 无法拿到实例和组件,因此不会对 ref 做处理 172 | 173 | ref 是在创建真实节点(patch 方法)时进行处理的 174 | 175 | 虚拟 dom 与平台无关,在创建真实 dom 前会走 createPatchFunction 的方法,将平台的节点操作和属性(包括 ref,指令,事件,样式的实现)操作方法传入来创建 patch 方法(相当于提供适配各个平台的接口),在创建节点时会执行创建节点的所有方法 176 | 177 | ref 会通过判断当前节点是否为组件来返回组件实例或 dom(Elm),之后会获取 vm 上的$ref 对象,通过判断 ref 是否在 v-for 循环中来决定是否将结果包装成数组 178 | -------------------------------------------------------------------------------- /mine-Vue/src/vdom/patch.js: -------------------------------------------------------------------------------- 1 | import { isSameVnode } from "./index"; 2 | function createComponent(vnode) { 3 | let i = vnode.data; 4 | if ((i = i.hook) && (i = i.init)) { 5 | i(vnode); //使用init方法初始化组件,调用$mount() 6 | } 7 | if (vnode.componentInstance) { 8 | return true; //说明是组件 9 | } 10 | } 11 | export function createElm(vnode) { 12 | let { tag, data, children, text } = vnode; 13 | if (typeof tag == "string") { 14 | // 创建真实节点需要知道是组件还是真实元素 15 | 16 | if (createComponent(vnode)) { 17 | // 这里的$el是在执行$mount后产生的虚拟节点对应的真实节点 18 | return vnode.componentInstance.$el; 19 | } 20 | // 将真实节点和虚拟节点进行对应,为后续diff算法做准备 21 | vnode.el = document.createElement(tag); 22 | patchProps(vnode.el, {}, data); 23 | children.forEach((child) => { 24 | vnode.el.appendChild(createElm(child)); 25 | }); 26 | } else { 27 | vnode.el = document.createTextNode(text); 28 | } 29 | return vnode.el; 30 | } 31 | export function patchProps(el, oldProps = {}, props = {}) { 32 | // 老的属性中有,新的没有,要删除老的 33 | let oldStyles = oldProps.style || {}; 34 | let newStyle = props.style; 35 | // 对于style 36 | for (let key in oldProps) { 37 | if (!newStyle[key]) { 38 | el.style[key] = ""; 39 | } 40 | } 41 | // 对于一般属性 42 | for (let key in oldProps) { 43 | if (!props[key]) { 44 | el.removeAttribute(key); 45 | } 46 | } 47 | // 用新的覆盖掉老的 48 | for (let key in props) { 49 | if (key == "style") { 50 | for (let styleName in props.style) { 51 | el.style[styleName] = props.style[styleName]; 52 | } 53 | } else { 54 | el.setAttribute(key, props[key]); 55 | } 56 | } 57 | } 58 | export function patch(oldVNode, vnode) { 59 | if (!oldVNode) { 60 | // 没有el,表示是组件的挂载 61 | //注意这里要修改init中的挂载方法,没有el也可以挂载 62 | //vm.$el就是渲染的结果 63 | return createElm(vnode); 64 | } 65 | const isRealElement = oldVNode.nodeType; 66 | if (isRealElement) { 67 | // 获取真实元素 68 | const elm = oldVNode; 69 | // 拿到父元素 70 | const parentElm = elm.parentNode; 71 | let newElm = createElm(vnode); 72 | parentElm.insertBefore(newElm, elm.nextSibiling); 73 | parentElm.removeChild(elm); 74 | return newElm; 75 | } else { 76 | // diff算法 77 | return patchVnode(oldVNode, vnode); 78 | } 79 | } 80 | // 利用diff算法更新两个节点 81 | function patchVnode(oldVNode, vnode) { 82 | // 两个节点不是同一个节点,直接删除老的,换上新的(没有对比) 83 | 84 | // 两个节点是同一个节点,判断节点的tag和key,tag和key一样是同一个节点,此时去比较两个节点的属性是否有差异(复用老的节点,将差异的属性更新) 85 | // 节点比较完成后,比较两个节点的子节点 86 | // 如果不是同一节点,用新节点替换老节点 87 | if (!isSameVnode(oldVNode, vnode)) { 88 | // 用老节点的父亲进行替换 89 | //这里的el属性就是虚拟节点对应的真实节点 90 | let el = createElm(vnode); 91 | oldVNode.el.parentNode.replaceChild(el, oldVNode); 92 | return el; 93 | } 94 | // 如果是文本节点,就比对一下文本的内容 95 | let el = (vnode.el = oldVNode.el); //复用老节点的元素 96 | if (!oldVNode.tag) { 97 | // 文本的情况 98 | if (oldVNode.text !== vnode.text) { 99 | el.textContent = vnode.text; 100 | } 101 | } 102 | //是标签,需要比对标签的属性 103 | patchProps(el, oldVNode.data, vnode.data); 104 | // 比较子节点: 105 | // 1.一方有儿子,一方没儿子 106 | // 2.两方都有儿子 107 | let oldChildren = oldVNode.children || []; 108 | let newChildren = vnode.children || []; 109 | if (oldChildren.length > 0 && newChildren.length > 0) { 110 | // 完整的diff算法 111 | updateChild(el, oldChildren, newChildren); 112 | } else if (newChildren > 0) { 113 | // 老的没有新的有 114 | mountChildren(el, newChildren); 115 | } else if (oldChildren > 0) { 116 | // 新的没有老的有 117 | unmountChild(el, oldChildren); 118 | } 119 | return el; 120 | } 121 | 122 | function mountChildren(el, children) { 123 | for (let i = 0; i < children.length; i++) { 124 | let child = newChildren[i]; 125 | el.appendChild(createElm(child)); 126 | } 127 | } 128 | 129 | function unmountChild(el, children) { 130 | el.innerHTML = ""; 131 | } 132 | 133 | function updateChild(el, oldChildren, newChildren) { 134 | // 为了增高性能,会有一些优化手段 135 | // vue2中采用双指针的方式比较两个节点 136 | let oldStartIndex = 0; 137 | let newStartIndex = 0; 138 | let oldEndIndex = oldChildren.length - 1; 139 | let newEndIndex = newChildren.length - 1; 140 | 141 | let oldStartVnode = oldChildren[0]; 142 | let newStartVnode = newChildren[0]; 143 | 144 | let oldEndVnode = oldChildren[oldEndIndex]; 145 | let newEndVnode = newChildren[newEndIndex]; 146 | function makeIndexByKey(children) { 147 | let map = {}; 148 | children.forEach((child, index) => { 149 | map[child.key] = index; 150 | }); 151 | return map; 152 | } 153 | let map = makeIndexByKey(oldChildren); 154 | while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) { 155 | // 有一方的头指针大于尾部指针,则停止循环 156 | // 如果是相同节点,则递归比较子节点 157 | if (!oldStartVnode) { 158 | // 处理置空节点产生的undefind的问题 159 | oldStartVnode = oldChildren[++oldStartIndex]; 160 | } else if (!oldEndVnode) { 161 | // 处理置空节点产生的undefind的问题 162 | oldEndVnode = oldChildren[--oldEndIndex]; 163 | } else if (isSameVnode(oldStartVnode, newStartVnode)) { 164 | patchVnode(oldStartVnode, newStartVnode); 165 | // 指针移动 166 | oldStartVnode = oldChildren[++oldStartIndex]; 167 | newStartVnode = newChildren[++newStartIndex]; 168 | } 169 | // 当首个元素不同时反向比对 170 | else if (isSameVnode(oldEndVnode, newEndVnode)) { 171 | patchVnode(oldEndVnode, newEndVnode); 172 | oldEndVnode = oldChildren[--oldEndIndex]; 173 | newEndVnode = newChildren[--newEndIndex]; 174 | } 175 | // 交叉比对,优化reverse方法 abcd__>dabc,处理了倒叙和排序的情况 176 | else if (isSameVnode(oldEndVnode, newStartVnode)) { 177 | patchVnode(oldEndVnode, newStartVnode); 178 | // 将老的尾部移动到老的前面去(变为了新前对旧前) 179 | // insertBefore具有移动性,会将原来的元素移动走 180 | el.insertBefore(oldEndVnode.el, oldStartVnode.el); 181 | oldEndVnode = oldChildren[--oldEndIndex]; 182 | newStartVnode = newChildren[++newStartIndex]; 183 | } else if (isSameVnode(oldStartVnode, newEndVnode)) { 184 | patchVnode(oldStartVnode, newEndVnode); 185 | // 将老的尾部移动到老的前面去(变为了新前对旧前) 186 | // insertBefore具有移动性,会将原来的元素移动走 187 | el.insertBefore(oldStartVnode.el, oldEndVnode.el.nextSibiling); 188 | oldStartVnode = oldChildren[++oldStartIndex]; 189 | newEndVnode = newChildren[--newEndIndex]; 190 | } else { 191 | // 给动态列表添加key时,尽量避免使用索引,可能导致错误复用 192 | // 乱序比对:根据老的列表做一个映射关系,用新的逐个比对查找,找到移动,找不到添加,多出的删除 193 | // 如果拿到说明是要移动的索引 194 | let moveIndex = map[newStartVnode?.key]; 195 | if (moveIndex !== undefined) { 196 | // 找到对应的虚拟节点进行复用 197 | let moveVnode = oldChildren[moveIndex]; 198 | el.insertBefore(moveVnode.el, oldStartVnode.el); 199 | oldChildren[moveIndex] = undefined; //表示这个节点已经被移走了 200 | // 递归比较属性和子节点 201 | patchVnode(moveVnode, newStartVnode); 202 | } else { 203 | // 无法找到老节点 204 | el.insertBefore(createElm(newStartVnode), oldStartVnode.el); 205 | } 206 | newStartVnode = newChildren[++newStartIndex]; 207 | } 208 | } 209 | 210 | // 多出元素删除,缺少元素添加 211 | // 相比于原有的数组有新增元素,尾部对新增元素进行添加 212 | if (newStartIndex <= newEndIndex) { 213 | for (let i = newStartIndex; i <= newEndIndex; i++) { 214 | let childEl = createElm(newChildren[i]); 215 | // 这里也有可能向前追加 216 | let anchor = newChildren[newEndIndex + 1] 217 | ? newChildren[newEndIndex + 1].el 218 | : null; 219 | el.insertBefore(childEl, anchor); 220 | // anchor为null时,则等价于appendChild 221 | } 222 | } 223 | // 相比于原有数组尾部减少元素,对被减少的元素进行删除 224 | if (oldStartIndex <= oldEndIndex) { 225 | for (let i = oldStartIndex; i <= oldEndIndex; i++) { 226 | if (oldChildren[i]) { 227 | let childEl = oldChildren[i].el; 228 | el.removeChild(childEl); 229 | } 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /mine-VueRouter/lib/VueRouter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"VueRouter.js","sources":["../src/components/router-link.js","../src/components/router-view.js","../src/install.js","../src/create-routesMap.js","../src/create-matcher.js","../src/history/base.js","../src/history/history.js","../src/history/hash.js","../src/index.js"],"sourcesContent":["export default {\n name: \"router-link\",\n props: {\n to: { type: String },\n tag: { type: String, default: \"a\" },\n },\n methods: {\n handler() {\n this.$router.push(this.to);\n },\n },\n render(h) {\n let tag = this.tag;\n return h(\n tag,\n {\n on: {\n click: () => {\n this.handler();\n },\n },\n },\n [this.$slots.default]\n );\n },\n};\n","export default {\n name: \"router-view\",\n // router-view 不会被计入父子关系,应该被标识为抽象(函数式)组件,避免创建父子关系($parents,$children等)\n functional: true,\n render(h, { parent, data }) {\n data.routerView = true;\n let route = parent.$route;\n let depth = 0;\n // 找到当前渲染的是第几层\n while (parent) {\n if (parent.$vnode && parent.$vnode.data.routerView) {\n depth++;\n }\n parent = parent.$parent;\n }\n let record = route.matched[depth];\n if (!record) {\n return h();\n }\n return h(record.component, data);\n // _vnode:渲染函数的虚拟节点;$vnode:代表组件本身,$vnode是_vnode的父亲\n },\n};\n","import routerLink from \"./components/router-link\";\nimport routerView from \"./components/router-view\";\nexport let Vue;\nexport function install(_Vue) {\n Vue = _Vue;\n Vue.mixin({\n beforeCreate() {\n // 这里不用原型继承的原因是因为会导致所有的Vue类共享路由\n if (this.$options.router) {\n // 根实例上传递了router\n this._routerRoot = this;\n this._router = this.$options.router || {};\n this._router.init(this); //this就是我们整个的应用(new Vue)\n // 给根实例添加一个属性_router,就是当前的current对象\n Vue.util.defineReactive(this, \"_route\", this._router.history.current);\n } else {\n // 所有组件上都增加一个routerRoot的指针指向根实例\n this._routerRoot = this.$parent?._router || this.$parent._routerRoot;\n }\n },\n });\n // 劫持$router属性,取$router其实是取了根实例上的router\n Object.defineProperty(Vue.prototype, \"$router\", {\n get() {\n return this._routerRoot;\n },\n });\n Object.defineProperty(Vue.prototype, \"$route\", {\n get() {\n return this._routerRoot._route || this._routerRoot.history.current;\n },\n });\n // 内部修改的是current\n Vue.component(\"router-link\", routerLink);\n Vue.component(\"router-view\", routerView);\n}\n","export default function createRouteMap(routes, pathMap = {}) {\n // 根据用户选项扁平化信息,将深度子类转化为扁平层级\n routes.forEach((route) => {\n addRouteRecord(route, pathMap);\n });\n return {\n pathMap,\n };\n}\nfunction addRouteRecord(route, pathMap, parentRecord) {\n let path = parentRecord\n ? `${parentRecord.path == \"/\" ? \"\" : \"/\"}${route.path}`\n : route.path;\n if (!pathMap[path]) {\n pathMap[path] = {\n path,\n component: route.component,\n props: route.props,\n meta: route.meta,\n parent: parentRecord,\n };\n }\n route.children &&\n route.children.forEach((children) => {\n addRouteRecord(children, pathMap);\n });\n}\n","import createRouteMap from \"./create-routesMap\";\nexport default function createMatcher(routes) {\n let { pathMap } = createRouteMap(routes);\n function addRoutes(routes) {\n // 动态添加路由\n createRouteMap(routes, pathMap);\n }\n function addRoute(route) {\n createRouteMap([route], pathMap);\n }\n function match(location) {\n return pathMap[location];\n }\n return {\n addRoutes, //添加多个路由\n addRoute, //添加一个路由\n match, //给一个路径来返回路由\n };\n}\n","function createRoute(record, location) {\n let matched = [];\n if (record) {\n while (record) {\n matched.unshift(record);\n record = record.parent;\n }\n }\n return {\n ...location,\n matched,\n };\n}\nfunction runQueue(queue, from, to, cb) {\n function next(index) {\n if (index >= queue.length) {\n return cb();\n }\n let hook = queue[index];\n hook(from, to, () => next(index + 1));\n }\n next(0);\n}\nexport default class Base {\n constructor(router) {\n this.router = router;\n // 每次更新的是current,每次current变化,我们就可以切换页面\n this.current = createRoute(null, {\n path: \"/\",\n });\n }\n // 所有跳转的逻辑都要放在transitionTo中来实现\n transitionTo(location, listener) {\n // 用之前的匹配方法\n let record = this.router.match(location);\n let route = createRoute(record, { path: location });\n // 这里需要取消点击进入和路由变化中的两次重复变化,注意path='/'时可能会匹配组件\n if (\n location == this.current.path &&\n route.matched.length == this.current.matched.length\n ) {\n return;\n }\n let queue = [].concat(this.router.beforeEachHooks);\n // 钩子执行完后再做跳转\n runQueue(queue, this.current, route, () => {\n this.current = route;\n // path:'/',matched:[]\n // 当路由切换的时候,也应该调用transitionTo拿到新的记录\n listener && listener();\n this.cb && this.cb(route);\n });\n }\n listen(cb) {\n // 用户自定义的钩子 this._route=route\n this.cb = cb;\n }\n}\n","import Base from \"./base\";\nclass History extends Base {\n constructor(router) {\n super(router);\n }\n setupListener() {\n window.addEventListener(\"popstate\", function () {\n this.transitionTo(getCurrentLocation());\n });\n }\n getCurrentLocation() {\n return window.location.pathname;\n }\n push(location) {\n this.transitionTo(location, () => {\n window.history.pushState({}, \"\", location);\n });\n }\n}\n\nexport default History;\n","import Base from \"./base\";\nfunction ensureSlash() {\n if (window.location.hash) {\n return;\n }\n window.location.hash = \"/\";\n}\nfunction getHash() {\n // 截取,获取真正的hash值\n return window.location.hash.slice(1);\n}\nclass Hash extends Base {\n constructor(router) {\n super(router);\n // 初始化哈希路由的时候要给定默认的哈希路径\n ensureSlash();\n }\n // 之后需要调用此方法,监控hash值的变化\n setupListener() {\n // 这里会监听哈希的变化,通过修改url或回退也会触发\n window.addEventListener(\"hashchange\", () => {\n this.transitionTo(getHash());\n });\n }\n getCurrentLocation() {\n return getHash();\n }\n push(location) {\n this.transitionTo(location, () => {\n window.location.hash = location;\n });\n }\n}\nexport default Hash;\n","import { install, Vue } from \"./install\";\nimport createMatcher from \"./create-matcher\";\nimport History from \"./history/history\";\nimport Hash from \"./history/hash\";\nclass VueRouter {\n constructor(options) {\n this.install = install;\n this.beforeEachHooks = [];\n // 对用户传入的路由表进行映射\n const routes = options.routes;\n this.matcher = createMatcher(routes);\n // 根据不用的模式创建不同的路由系统\n let mode = options.mode || \"hash\";\n if (mode == \"hash\") {\n this.history = new Hash(this);\n } else if (mode == \"history\") {\n this.history = new History(this);\n }\n }\n beforeEach(cb) {\n this.beforeEachHooks.push(cb);\n }\n match(path) {\n return this.matcher.match(path);\n }\n push(location) {\n return this.history.push(location);\n }\n init(app) {\n let history = this.history;\n // 根据路径变化,匹配不同的组件进行渲染,路径变化,更新视图,路径需要是响应式的\n history.transitionTo(history.getCurrentLocation(), () => {\n history.setupListener(); //监听路由变化\n });\n // 每次路由需要调用listen中的方法实现更新_route的值,使他能够发生变化,重新渲染视图\n history.listen((newRoute) => {\n app._route = newRoute;\n });\n }\n}\nexport default VueRouter;\n"],"names":["name","props","to","type","String","tag","methods","handler","$router","push","render","h","on","click","$slots","functional","parent","data","routerView","route","$route","depth","$vnode","$parent","record","matched","component","Vue","install","_Vue","mixin","beforeCreate","$options","router","_routerRoot","_router","init","util","defineReactive","history","current","Object","defineProperty","prototype","get","_route","routerLink","createRouteMap","routes","pathMap","forEach","addRouteRecord","parentRecord","path","meta","children","createMatcher","addRoutes","addRoute","match","location","createRoute","unshift","_objectSpread","runQueue","queue","from","cb","next","index","length","hook","Base","listener","concat","beforeEachHooks","History","window","addEventListener","transitionTo","getCurrentLocation","pathname","pushState","ensureSlash","hash","getHash","slice","Hash","VueRouter","options","matcher","mode","app","setupListener","listen","newRoute"],"mappings":"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"} -------------------------------------------------------------------------------- /mine-VueRouter/lib/VueRouter.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === "object" && typeof module !== "undefined" 3 | ? (module.exports = factory()) 4 | : typeof define === "function" && define.amd 5 | ? define(factory) 6 | : ((global = 7 | typeof globalThis !== "undefined" ? globalThis : global || self), 8 | (global.VueRouter = factory())); 9 | })(this, function () { 10 | "use strict"; 11 | 12 | function ownKeys(object, enumerableOnly) { 13 | var keys = Object.keys(object); 14 | 15 | if (Object.getOwnPropertySymbols) { 16 | var symbols = Object.getOwnPropertySymbols(object); 17 | enumerableOnly && 18 | (symbols = symbols.filter(function (sym) { 19 | return Object.getOwnPropertyDescriptor(object, sym).enumerable; 20 | })), 21 | keys.push.apply(keys, symbols); 22 | } 23 | 24 | return keys; 25 | } 26 | 27 | function _objectSpread2(target) { 28 | for (var i = 1; i < arguments.length; i++) { 29 | var source = null != arguments[i] ? arguments[i] : {}; 30 | i % 2 31 | ? ownKeys(Object(source), !0).forEach(function (key) { 32 | _defineProperty(target, key, source[key]); 33 | }) 34 | : Object.getOwnPropertyDescriptors 35 | ? Object.defineProperties( 36 | target, 37 | Object.getOwnPropertyDescriptors(source) 38 | ) 39 | : ownKeys(Object(source)).forEach(function (key) { 40 | Object.defineProperty( 41 | target, 42 | key, 43 | Object.getOwnPropertyDescriptor(source, key) 44 | ); 45 | }); 46 | } 47 | 48 | return target; 49 | } 50 | 51 | function _classCallCheck(instance, Constructor) { 52 | if (!(instance instanceof Constructor)) { 53 | throw new TypeError("Cannot call a class as a function"); 54 | } 55 | } 56 | 57 | function _defineProperties(target, props) { 58 | for (var i = 0; i < props.length; i++) { 59 | var descriptor = props[i]; 60 | descriptor.enumerable = descriptor.enumerable || false; 61 | descriptor.configurable = true; 62 | if ("value" in descriptor) descriptor.writable = true; 63 | Object.defineProperty(target, descriptor.key, descriptor); 64 | } 65 | } 66 | 67 | function _createClass(Constructor, protoProps, staticProps) { 68 | if (protoProps) _defineProperties(Constructor.prototype, protoProps); 69 | if (staticProps) _defineProperties(Constructor, staticProps); 70 | Object.defineProperty(Constructor, "prototype", { 71 | writable: false, 72 | }); 73 | return Constructor; 74 | } 75 | 76 | function _defineProperty(obj, key, value) { 77 | if (key in obj) { 78 | Object.defineProperty(obj, key, { 79 | value: value, 80 | enumerable: true, 81 | configurable: true, 82 | writable: true, 83 | }); 84 | } else { 85 | obj[key] = value; 86 | } 87 | 88 | return obj; 89 | } 90 | 91 | function _inherits(subClass, superClass) { 92 | if (typeof superClass !== "function" && superClass !== null) { 93 | throw new TypeError("Super expression must either be null or a function"); 94 | } 95 | 96 | subClass.prototype = Object.create(superClass && superClass.prototype, { 97 | constructor: { 98 | value: subClass, 99 | writable: true, 100 | configurable: true, 101 | }, 102 | }); 103 | Object.defineProperty(subClass, "prototype", { 104 | writable: false, 105 | }); 106 | if (superClass) _setPrototypeOf(subClass, superClass); 107 | } 108 | 109 | function _getPrototypeOf(o) { 110 | _getPrototypeOf = Object.setPrototypeOf 111 | ? Object.getPrototypeOf.bind() 112 | : function _getPrototypeOf(o) { 113 | return o.__proto__ || Object.getPrototypeOf(o); 114 | }; 115 | return _getPrototypeOf(o); 116 | } 117 | 118 | function _setPrototypeOf(o, p) { 119 | _setPrototypeOf = Object.setPrototypeOf 120 | ? Object.setPrototypeOf.bind() 121 | : function _setPrototypeOf(o, p) { 122 | o.__proto__ = p; 123 | return o; 124 | }; 125 | return _setPrototypeOf(o, p); 126 | } 127 | 128 | function _isNativeReflectConstruct() { 129 | if (typeof Reflect === "undefined" || !Reflect.construct) return false; 130 | if (Reflect.construct.sham) return false; 131 | if (typeof Proxy === "function") return true; 132 | 133 | try { 134 | Boolean.prototype.valueOf.call( 135 | Reflect.construct(Boolean, [], function () {}) 136 | ); 137 | return true; 138 | } catch (e) { 139 | return false; 140 | } 141 | } 142 | 143 | function _assertThisInitialized(self) { 144 | if (self === void 0) { 145 | throw new ReferenceError( 146 | "this hasn't been initialised - super() hasn't been called" 147 | ); 148 | } 149 | 150 | return self; 151 | } 152 | 153 | function _possibleConstructorReturn(self, call) { 154 | if (call && (typeof call === "object" || typeof call === "function")) { 155 | return call; 156 | } else if (call !== void 0) { 157 | throw new TypeError( 158 | "Derived constructors may only return object or undefined" 159 | ); 160 | } 161 | 162 | return _assertThisInitialized(self); 163 | } 164 | 165 | function _createSuper(Derived) { 166 | var hasNativeReflectConstruct = _isNativeReflectConstruct(); 167 | 168 | return function _createSuperInternal() { 169 | var Super = _getPrototypeOf(Derived), 170 | result; 171 | 172 | if (hasNativeReflectConstruct) { 173 | var NewTarget = _getPrototypeOf(this).constructor; 174 | 175 | result = Reflect.construct(Super, arguments, NewTarget); 176 | } else { 177 | result = Super.apply(this, arguments); 178 | } 179 | 180 | return _possibleConstructorReturn(this, result); 181 | }; 182 | } 183 | 184 | var routerLink = { 185 | name: "router-link", 186 | props: { 187 | to: { 188 | type: String, 189 | }, 190 | tag: { 191 | type: String, 192 | default: "a", 193 | }, 194 | }, 195 | methods: { 196 | handler: function handler() { 197 | this.$router.push(this.to); 198 | }, 199 | }, 200 | render: function render(h) { 201 | var _this = this; 202 | 203 | var tag = this.tag; 204 | return h( 205 | tag, 206 | { 207 | on: { 208 | click: function click() { 209 | _this.handler(); 210 | }, 211 | }, 212 | }, 213 | [this.$slots["default"]] 214 | ); 215 | }, 216 | }; 217 | 218 | var routerView = { 219 | name: "router-view", 220 | // router-view 不会被计入父子关系,应该被标识为抽象(函数式)组件,避免创建父子关系($parents,$children等) 221 | functional: true, 222 | render: function render(h, _ref) { 223 | var parent = _ref.parent, 224 | data = _ref.data; 225 | data.routerView = true; 226 | var route = parent.$route; 227 | var depth = 0; // 找到当前渲染的是第几层 228 | 229 | while (parent) { 230 | if (parent.$vnode && parent.$vnode.data.routerView) { 231 | depth++; 232 | } 233 | 234 | parent = parent.$parent; 235 | } 236 | 237 | var record = route.matched[depth]; 238 | 239 | if (!record) { 240 | return h(); 241 | } 242 | 243 | return h(record.component, data); // _vnode:渲染函数的虚拟节点;$vnode:代表组件本身,$vnode是_vnode的父亲 244 | }, 245 | }; 246 | 247 | var Vue; 248 | function install(_Vue) { 249 | Vue = _Vue; 250 | Vue.mixin({ 251 | beforeCreate: function beforeCreate() { 252 | // 这里不用原型继承的原因是因为会导致所有的Vue类共享路由 253 | if (this.$options.router) { 254 | // 根实例上传递了router 255 | this._routerRoot = this; 256 | this._router = this.$options.router || {}; 257 | 258 | this._router.init(this); //this就是我们整个的应用(new Vue) 259 | // 给根实例添加一个属性_router,就是当前的current对象 260 | 261 | Vue.util.defineReactive(this, "_route", this._router.history.current); 262 | } else { 263 | var _this$$parent; 264 | 265 | // 所有组件上都增加一个routerRoot的指针指向根实例 266 | this._routerRoot = 267 | ((_this$$parent = this.$parent) === null || _this$$parent === void 0 268 | ? void 0 269 | : _this$$parent._router) || this.$parent._routerRoot; 270 | } 271 | }, 272 | }); // 劫持$router属性,取$router其实是取了根实例上的router 273 | 274 | Object.defineProperty(Vue.prototype, "$router", { 275 | get: function get() { 276 | return this._routerRoot; 277 | }, 278 | }); 279 | Object.defineProperty(Vue.prototype, "$route", { 280 | get: function get() { 281 | return this._routerRoot._route || this._routerRoot.history.current; 282 | }, 283 | }); // 内部修改的是current 284 | 285 | Vue.component("router-link", routerLink); 286 | Vue.component("router-view", routerView); 287 | } 288 | 289 | function createRouteMap(routes) { 290 | var pathMap = 291 | arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 292 | // 根据用户选项扁平化信息,将深度子类转化为扁平层级 293 | routes.forEach(function (route) { 294 | addRouteRecord(route, pathMap); 295 | }); 296 | return { 297 | pathMap: pathMap, 298 | }; 299 | } 300 | 301 | function addRouteRecord(route, pathMap, parentRecord) { 302 | var path = parentRecord 303 | ? "".concat(parentRecord.path == "/" ? "" : "/").concat(route.path) 304 | : route.path; 305 | 306 | if (!pathMap[path]) { 307 | pathMap[path] = { 308 | path: path, 309 | component: route.component, 310 | props: route.props, 311 | meta: route.meta, 312 | parent: parentRecord, 313 | }; 314 | } 315 | 316 | route.children && 317 | route.children.forEach(function (children) { 318 | addRouteRecord(children, pathMap); 319 | }); 320 | } 321 | 322 | function createMatcher(routes) { 323 | var _createRouteMap = createRouteMap(routes), 324 | pathMap = _createRouteMap.pathMap; 325 | 326 | function addRoutes(routes) { 327 | // 动态添加路由 328 | createRouteMap(routes, pathMap); 329 | } 330 | 331 | function addRoute(route) { 332 | createRouteMap([route], pathMap); 333 | } 334 | 335 | function match(location) { 336 | return pathMap[location]; 337 | } 338 | 339 | return { 340 | addRoutes: addRoutes, 341 | //添加多个路由 342 | addRoute: addRoute, 343 | //添加一个路由 344 | match: match, //给一个路径来返回路由 345 | }; 346 | } 347 | 348 | function createRoute(record, location) { 349 | var matched = []; 350 | 351 | if (record) { 352 | while (record) { 353 | matched.unshift(record); 354 | record = record.parent; 355 | } 356 | } 357 | 358 | return _objectSpread2( 359 | _objectSpread2({}, location), 360 | {}, 361 | { 362 | matched: matched, 363 | } 364 | ); 365 | } 366 | 367 | function runQueue(queue, from, to, cb) { 368 | function next(index) { 369 | if (index >= queue.length) { 370 | return cb(); 371 | } 372 | 373 | var hook = queue[index]; 374 | hook(from, to, function () { 375 | return next(index + 1); 376 | }); 377 | } 378 | 379 | next(0); 380 | } 381 | 382 | var Base = /*#__PURE__*/ (function () { 383 | function Base(router) { 384 | _classCallCheck(this, Base); 385 | 386 | this.router = router; // 每次更新的是current,每次current变化,我们就可以切换页面 387 | 388 | this.current = createRoute(null, { 389 | path: "/", 390 | }); 391 | } // 所有跳转的逻辑都要放在transitionTo中来实现 392 | 393 | _createClass(Base, [ 394 | { 395 | key: "transitionTo", 396 | value: function transitionTo(location, listener) { 397 | var _this = this; 398 | 399 | // 用之前的匹配方法 400 | var record = this.router.match(location); 401 | var route = createRoute(record, { 402 | path: location, 403 | }); // 这里需要取消点击进入和路由变化中的两次重复变化,注意path='/'时可能会匹配组件 404 | 405 | if ( 406 | location == this.current.path && 407 | route.matched.length == this.current.matched.length 408 | ) { 409 | return; 410 | } 411 | 412 | var queue = [].concat(this.router.beforeEachHooks); // 钩子执行完后再做跳转 413 | 414 | runQueue(queue, this.current, route, function () { 415 | _this.current = route; // path:'/',matched:[] 416 | // 当路由切换的时候,也应该调用transitionTo拿到新的记录 417 | 418 | listener && listener(); 419 | _this.cb && _this.cb(route); 420 | }); 421 | }, 422 | }, 423 | { 424 | key: "listen", 425 | value: function listen(cb) { 426 | // 用户自定义的钩子 this._route=route 427 | this.cb = cb; 428 | }, 429 | }, 430 | ]); 431 | 432 | return Base; 433 | })(); 434 | 435 | var History = /*#__PURE__*/ (function (_Base) { 436 | _inherits(History, _Base); 437 | 438 | var _super = _createSuper(History); 439 | 440 | function History(router) { 441 | _classCallCheck(this, History); 442 | 443 | return _super.call(this, router); 444 | } 445 | 446 | _createClass(History, [ 447 | { 448 | key: "setupListener", 449 | value: function setupListener() { 450 | window.addEventListener("popstate", function () { 451 | this.transitionTo(getCurrentLocation()); 452 | }); 453 | }, 454 | }, 455 | { 456 | key: "getCurrentLocation", 457 | value: function getCurrentLocation() { 458 | return window.location.pathname; 459 | }, 460 | }, 461 | { 462 | key: "push", 463 | value: function push(location) { 464 | this.transitionTo(location, function () { 465 | window.history.pushState({}, "", location); 466 | }); 467 | }, 468 | }, 469 | ]); 470 | 471 | return History; 472 | })(Base); 473 | 474 | function ensureSlash() { 475 | if (window.location.hash) { 476 | return; 477 | } 478 | 479 | window.location.hash = "/"; 480 | } 481 | 482 | function getHash() { 483 | // 截取,获取真正的hash值 484 | return window.location.hash.slice(1); 485 | } 486 | 487 | var Hash = /*#__PURE__*/ (function (_Base) { 488 | _inherits(Hash, _Base); 489 | 490 | var _super = _createSuper(Hash); 491 | 492 | function Hash(router) { 493 | var _this; 494 | 495 | _classCallCheck(this, Hash); 496 | 497 | _this = _super.call(this, router); // 初始化哈希路由的时候要给定默认的哈希路径 498 | 499 | ensureSlash(); 500 | return _this; 501 | } // 之后需要调用此方法,监控hash值的变化 502 | 503 | _createClass(Hash, [ 504 | { 505 | key: "setupListener", 506 | value: function setupListener() { 507 | var _this2 = this; 508 | 509 | // 这里会监听哈希的变化,通过修改url或回退也会触发 510 | window.addEventListener("hashchange", function () { 511 | _this2.transitionTo(getHash()); 512 | }); 513 | }, 514 | }, 515 | { 516 | key: "getCurrentLocation", 517 | value: function getCurrentLocation() { 518 | return getHash(); 519 | }, 520 | }, 521 | { 522 | key: "push", 523 | value: function push(location) { 524 | this.transitionTo(location, function () { 525 | window.location.hash = location; 526 | }); 527 | }, 528 | }, 529 | ]); 530 | 531 | return Hash; 532 | })(Base); 533 | 534 | var VueRouter = /*#__PURE__*/ (function () { 535 | function VueRouter(options) { 536 | _classCallCheck(this, VueRouter); 537 | 538 | this.install = install; 539 | this.beforeEachHooks = []; // 对用户传入的路由表进行映射 540 | 541 | var routes = options.routes; 542 | this.matcher = createMatcher(routes); // 根据不用的模式创建不同的路由系统 543 | 544 | var mode = options.mode || "hash"; 545 | 546 | if (mode == "hash") { 547 | this.history = new Hash(this); 548 | } else if (mode == "history") { 549 | this.history = new History(this); 550 | } 551 | } 552 | 553 | _createClass(VueRouter, [ 554 | { 555 | key: "beforeEach", 556 | value: function beforeEach(cb) { 557 | this.beforeEachHooks.push(cb); 558 | }, 559 | }, 560 | { 561 | key: "match", 562 | value: function match(path) { 563 | return this.matcher.match(path); 564 | }, 565 | }, 566 | { 567 | key: "push", 568 | value: function push(location) { 569 | return this.history.push(location); 570 | }, 571 | }, 572 | { 573 | key: "init", 574 | value: function init(app) { 575 | var history = this.history; // 根据路径变化,匹配不同的组件进行渲染,路径变化,更新视图,路径需要是响应式的 576 | 577 | history.transitionTo(history.getCurrentLocation(), function () { 578 | history.setupListener(); //监听路由变化 579 | }); // 每次路由需要调用listen中的方法实现更新_route的值,使他能够发生变化,重新渲染视图 580 | 581 | history.listen(function (newRoute) { 582 | app._route = newRoute; 583 | }); 584 | }, 585 | }, 586 | ]); 587 | 588 | return VueRouter; 589 | })(); 590 | 591 | return VueRouter; 592 | }); 593 | //# sourceMappingURL=VueRouter.js.map 594 | -------------------------------------------------------------------------------- /mine-Vue/lib/vue.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === "object" && typeof module !== "undefined" 3 | ? (module.exports = factory()) 4 | : typeof define === "function" && define.amd 5 | ? define(factory) 6 | : ((global = 7 | typeof globalThis !== "undefined" ? globalThis : global || self), 8 | (global.Vue = factory())); 9 | })(this, function () { 10 | "use strict"; 11 | 12 | function _typeof(obj) { 13 | "@babel/helpers - typeof"; 14 | 15 | return ( 16 | (_typeof = 17 | "function" == typeof Symbol && "symbol" == typeof Symbol.iterator 18 | ? function (obj) { 19 | return typeof obj; 20 | } 21 | : function (obj) { 22 | return obj && 23 | "function" == typeof Symbol && 24 | obj.constructor === Symbol && 25 | obj !== Symbol.prototype 26 | ? "symbol" 27 | : typeof obj; 28 | }), 29 | _typeof(obj) 30 | ); 31 | } 32 | 33 | function _classCallCheck(instance, Constructor) { 34 | if (!(instance instanceof Constructor)) { 35 | throw new TypeError("Cannot call a class as a function"); 36 | } 37 | } 38 | 39 | function _defineProperties(target, props) { 40 | for (var i = 0; i < props.length; i++) { 41 | var descriptor = props[i]; 42 | descriptor.enumerable = descriptor.enumerable || false; 43 | descriptor.configurable = true; 44 | if ("value" in descriptor) descriptor.writable = true; 45 | Object.defineProperty(target, descriptor.key, descriptor); 46 | } 47 | } 48 | 49 | function _createClass(Constructor, protoProps, staticProps) { 50 | if (protoProps) _defineProperties(Constructor.prototype, protoProps); 51 | if (staticProps) _defineProperties(Constructor, staticProps); 52 | Object.defineProperty(Constructor, "prototype", { 53 | writable: false, 54 | }); 55 | return Constructor; 56 | } 57 | 58 | function _slicedToArray(arr, i) { 59 | return ( 60 | _arrayWithHoles(arr) || 61 | _iterableToArrayLimit(arr, i) || 62 | _unsupportedIterableToArray(arr, i) || 63 | _nonIterableRest() 64 | ); 65 | } 66 | 67 | function _arrayWithHoles(arr) { 68 | if (Array.isArray(arr)) return arr; 69 | } 70 | 71 | function _iterableToArrayLimit(arr, i) { 72 | var _i = 73 | arr == null 74 | ? null 75 | : (typeof Symbol !== "undefined" && arr[Symbol.iterator]) || 76 | arr["@@iterator"]; 77 | 78 | if (_i == null) return; 79 | var _arr = []; 80 | var _n = true; 81 | var _d = false; 82 | 83 | var _s, _e; 84 | 85 | try { 86 | for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { 87 | _arr.push(_s.value); 88 | 89 | if (i && _arr.length === i) break; 90 | } 91 | } catch (err) { 92 | _d = true; 93 | _e = err; 94 | } finally { 95 | try { 96 | if (!_n && _i["return"] != null) _i["return"](); 97 | } finally { 98 | if (_d) throw _e; 99 | } 100 | } 101 | 102 | return _arr; 103 | } 104 | 105 | function _unsupportedIterableToArray(o, minLen) { 106 | if (!o) return; 107 | if (typeof o === "string") return _arrayLikeToArray(o, minLen); 108 | var n = Object.prototype.toString.call(o).slice(8, -1); 109 | if (n === "Object" && o.constructor) n = o.constructor.name; 110 | if (n === "Map" || n === "Set") return Array.from(o); 111 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) 112 | return _arrayLikeToArray(o, minLen); 113 | } 114 | 115 | function _arrayLikeToArray(arr, len) { 116 | if (len == null || len > arr.length) len = arr.length; 117 | 118 | for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; 119 | 120 | return arr2; 121 | } 122 | 123 | function _nonIterableRest() { 124 | throw new TypeError( 125 | "Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method." 126 | ); 127 | } 128 | 129 | var id$1 = 0; // 每一个dep都表示一个被依赖的数据,当这个数据变化,跟这些数据关联的视图会同步变化 130 | 131 | var Dep = /*#__PURE__*/ (function () { 132 | function Dep() { 133 | _classCallCheck(this, Dep); 134 | 135 | this.id = id$1++; 136 | this.subs = []; 137 | } 138 | 139 | _createClass(Dep, [ 140 | { 141 | key: "depend", 142 | value: function depend() { 143 | // 不希望放置重复的watcher 144 | // 这里在添加一个watch时,这个watch也会将这个dep添加到自己的观察队列中 145 | Dep.target.addDep(this); 146 | }, // 这个方法是让watcher将自己添加到观察队列的 147 | }, 148 | { 149 | key: "addSub", 150 | value: function addSub(watcher) { 151 | this.subs.push(watcher); 152 | }, // 通知所有观察了这个dep的watch更新视图 153 | }, 154 | { 155 | key: "notify", 156 | value: function notify() { 157 | this.subs.forEach(function (watcher) { 158 | watcher.update(); 159 | }); 160 | }, 161 | }, 162 | ]); 163 | 164 | return Dep; 165 | })(); 166 | 167 | var stack = []; 168 | function pushTarget(watcher) { 169 | stack.push(watcher); 170 | Dep.target = watcher; 171 | } 172 | function popTarget() { 173 | stack.pop(); 174 | Dep.target = stack[stack.length - 1]; 175 | } 176 | 177 | // 我们希望保留原数组特性并重写部分数组方法 178 | var oldArrayProto = Array.prototype; 179 | var newArrayProto = Object.create(oldArrayProto); // 所有变异方法 180 | 181 | var methods = [ 182 | "push", 183 | "shift", 184 | "unshift", 185 | "splice", 186 | "pop", 187 | "reverse", 188 | "sort", 189 | ]; 190 | methods.forEach(function (method) { 191 | newArrayProto[method] = function () { 192 | var _oldArrayProto$method; 193 | 194 | for ( 195 | var _len = arguments.length, args = new Array(_len), _key = 0; 196 | _key < _len; 197 | _key++ 198 | ) { 199 | args[_key] = arguments[_key]; 200 | } 201 | 202 | // 内部调用原来的方法 203 | var result = (_oldArrayProto$method = oldArrayProto[method]).call.apply( 204 | _oldArrayProto$method, 205 | [this].concat(args) 206 | ); 207 | 208 | var ob = this.__ob__; // 将数组中新增的方法进行响应式劫持 209 | 210 | var inserted; 211 | 212 | switch (method) { 213 | case "push": 214 | case "unshift": 215 | inserted = args; 216 | break; 217 | 218 | case "splice": 219 | inserted = args.slice(2); 220 | } 221 | 222 | if (inserted) { 223 | ob.observeArray(inserted); 224 | } // 数组变化后通知对应的 watcher实现更新 225 | 226 | ob.dep.notify(); 227 | return result; 228 | }; 229 | }); 230 | 231 | var Observe = /*#__PURE__*/ (function () { 232 | // 给每个对象都增加收集功能 233 | // 要给数组和对象本身也增加dep,如果用户增添了属性或数组新增了一项,都会触发dep 234 | function Observe(data) { 235 | _classCallCheck(this, Observe); 236 | 237 | // 给数据添加一个表示__ob__,被标识的数据标识已经被观测过了 238 | //data.__ob__=this 直接将this添加到__ob__后,会导致遍历可观测对象时遍历到this,形成死循环 239 | // 添加属性__ob__并将这个属性设置为不可枚举,使其在遍历时无法被遍历 240 | this.dep = new Dep(); 241 | Object.defineProperty(data, "__ob__", { 242 | value: this, 243 | enumerable: false, 244 | }); 245 | 246 | if (Array.isArray(data)) { 247 | // 用户一般不会通过索引调用数组的值,直接遍历又会导致性能问题 248 | //因此我们可以通过重写数组7个变异方法的方式来监控数据变化 249 | //同时应该考虑数组中对象的劫持 250 | data.__proto__ = newArrayProto; 251 | this.observeArray(data); //监控数组中的对象,只将数组中的对象进行挂载 252 | } else { 253 | this.walk(data); 254 | } // Object.defineProperty只能劫持已经存在的属性 255 | } 256 | 257 | _createClass(Observe, [ 258 | { 259 | key: "walk", 260 | value: function walk(data) { 261 | //循环对象,对属性依次劫持,重新定义属性 262 | Object.keys(data).forEach(function (key) { 263 | defineReactive(data, key, data[key]); 264 | }); 265 | }, 266 | }, 267 | { 268 | key: "observeArray", 269 | value: function observeArray(data) { 270 | data.forEach(function (item) { 271 | observe(item); 272 | }); 273 | }, 274 | }, 275 | ]); 276 | 277 | return Observe; 278 | })(); 279 | 280 | function dependArray(value) { 281 | // 对数组的每一个元素进行观察 282 | for (var i = 0; i < value.length; i++) { 283 | // 如果数组中有对象(有__ob__表示是对象且被标记过),那么需要将数组中的所有对象进行观测 284 | value[i].__ob__ && value[i].__ob__.dep.depend(); // 如果数组中的子元素还是数组,则继续递归 285 | 286 | if (Array.isArray(value[i])) { 287 | dependArray(value[i]); 288 | } 289 | } 290 | } 291 | 292 | function defineReactive(target, key, value) { 293 | // 闭包,从外部拿到value 294 | // 如果劫持到的属性依然是一个对象,就应该递归劫持所有属性,深度属性劫持 295 | var childOb = observe(value); // 每一个属性都有一个dep,这里是闭包,因此变量不会销毁 296 | 297 | var dep = new Dep(); 298 | Object.defineProperty(target, key, { 299 | get: function get() { 300 | // 如果Dep.target不为null,证明这个属性被某个watch依赖 301 | if (Dep.target) { 302 | dep.depend(); 303 | 304 | if (childOb) { 305 | // 让数组和对象也实现依赖收集 306 | // 如果出现对象套对象的情况,就将这个属性继续放入dep队列观察,深度遍历 307 | childOb.dep.depend(); // 当出现数组套数组的情况时,进行深度遍历 308 | 309 | if (Array.isArray(value)) { 310 | dependArray(value); 311 | } 312 | } 313 | } 314 | 315 | return value; 316 | }, 317 | set: function set(newValue) { 318 | if (newValue == value) return; 319 | value = newValue; // 通知所有依赖这个属性的watch更新视图 320 | 321 | dep.notify(); 322 | }, 323 | }); 324 | } 325 | function observe(data) { 326 | if (_typeof(data) != "object" || data == null) { 327 | return; //只对对象进行劫持 328 | } //判断对象是否被劫持过,需要用一个实例来观测判断 329 | 330 | return new Observe(data); 331 | } 332 | 333 | var id = 0; // 解析一般data时只会创建一个渲染watcher,当解析计算属性时,会按栈结构去创建计算属性watcher 334 | // watcher的作用时:当依赖的dep发生更新时,对应地触发某些操作(比如重新渲染) 335 | 336 | var Watcher = /*#__PURE__*/ (function () { 337 | function Watcher(vm, exprOrFn, options, cb) { 338 | _classCallCheck(this, Watcher); 339 | 340 | this.id = id++; 341 | this.renderWatcher = vm.options; // getter意味着调用这个函数会发生取值 342 | 343 | if (typeof exprOrFn === "string") { 344 | this.getter = function () { 345 | return vm[exprOrFn]; 346 | }; 347 | } else { 348 | this.getter = exprOrFn; 349 | } // 让watcher去记住所有dep,后续实现计算属性和清理工作需要使用 350 | 351 | this.deps = []; 352 | this.depsId = new Set(); 353 | this.lazy = options.lazy; 354 | this.dirty = this.lazy; 355 | this.vm = vm; // 标识是否是用户自己的watcher 356 | 357 | this.user = options.user; 358 | this.cb = cb; // 计算属性第一次并不执行 359 | 360 | this.value = this.lazy ? undefined : this.get(); 361 | } 362 | 363 | _createClass(Watcher, [ 364 | { 365 | key: "evalute", 366 | value: function evalute() { 367 | // 获取到用户函数的返回值,并标识为脏 368 | this.value = this.get(); 369 | this.dirty = false; 370 | }, 371 | }, 372 | { 373 | key: "get", 374 | value: function get() { 375 | // 将自己添加到Dep的静态属性上,让之后每个dep都可以添加到这个watch 376 | pushTarget(this); // 这个getter就是更新函数 377 | 378 | var value = this.getter.call(this.vm); // 将这个静态属性置为空 379 | 380 | popTarget(); 381 | return value; 382 | }, 383 | }, 384 | { 385 | key: "update", 386 | value: function update() { 387 | // 当dep是计算属性 388 | // 当依赖的值发生变化时dirty是脏值 389 | if (this.lazy) { 390 | this.dirty = true; 391 | } // 重新渲染,这里为了防止多次更新视图,采用了事件环的方式合并多次操作 392 | 393 | queueWatcher(this); 394 | }, 395 | }, 396 | { 397 | key: "depend", 398 | value: function depend() { 399 | var i = this.deps.length; 400 | 401 | while (i--) { 402 | this.deps[i].depend(); //让计算属性watcher也收集渲染watcher 403 | } 404 | }, 405 | }, 406 | { 407 | key: "addDep", 408 | value: function addDep(dep) { 409 | // 一个组件对应着多个属性,重复的属性也不用记录 410 | var id = dep.id; 411 | 412 | if (!this.depsId.has(id)) { 413 | this.deps.push(dep); 414 | this.depsId.add(id); 415 | dep.addSub(this); 416 | } 417 | }, 418 | }, 419 | { 420 | key: "run", 421 | value: function run() { 422 | var oldValue = this.value; 423 | var newValue = this.get(); // user标识用户自定义的watcher 424 | 425 | if (this.user) { 426 | // 监控的值(dep)会收集watcher,如果监控的值(dep)发生了改变,就会执行对应的回调 427 | this.cb.call(this.vm, newValue, oldValue); 428 | } 429 | }, 430 | }, 431 | ]); 432 | 433 | return Watcher; 434 | })(); 435 | 436 | var queue = []; 437 | var has = {}; 438 | var pending = false; 439 | 440 | function flushSchedulerQueue() { 441 | var flushQueue = queue.slice(0); 442 | flushQueue.forEach(function (q) { 443 | q.run(); 444 | }); 445 | queue = []; 446 | has = {}; 447 | pending = false; 448 | } 449 | 450 | function queueWatcher(watcher) { 451 | var id = watcher.id; 452 | 453 | if (!has[id]) { 454 | queue.push(watcher); 455 | has[id] = true; // 不论update执行多少次,只执行一轮刷新操作 456 | // 多次操作只走第一次,后面的操作都会被放到队列里,等第一次执行完后下一个事件环执行 457 | 458 | if (!pending) { 459 | timerFunc(flushSchedulerQueue); 460 | pending = true; 461 | } 462 | } 463 | } 464 | 465 | var callbacks = []; 466 | var waiting = false; 467 | 468 | function flushCallbacks() { 469 | var cbs = callbacks.slice(0); 470 | cbs.forEach(function (cb) { 471 | return cb(); 472 | }); 473 | waiting = false; 474 | callbacks = []; 475 | } // nextTick不是创建了一个异步任务,而是将这个任务维护到了队列中 476 | // nextTick内部采用优雅降级:promise->MutationObserver->setImmediate->setTimeout 477 | 478 | var timerFunc; 479 | 480 | if (Promise) { 481 | timerFunc = function timerFunc(fn) { 482 | Promise.resolve().then(fn); 483 | }; 484 | } else if (MutationObserver) { 485 | // 这里传入的回调是异步任务 486 | timerFunc = function timerFunc(fn) { 487 | var observe = new MutationObserver(fn); 488 | var textNode = document.createElement(1); 489 | observe.observe(textNode, { 490 | characterData: true, 491 | }); 492 | textNode.textContent = 2; 493 | }; 494 | } else if (setImmediate) { 495 | timerFunc = function timerFunc(fn) { 496 | setImmediate(fn); 497 | }; 498 | } else { 499 | timerFunc = function timerFunc(fn) { 500 | setTimeout(fn, 0); 501 | }; 502 | } 503 | 504 | var nextTick = function nextTick(cb) { 505 | callbacks.push(cb); 506 | 507 | if (!waiting) { 508 | timerFunc(flushCallbacks); 509 | waiting = true; 510 | } 511 | }; // 需要给每个属性增加dep, 512 | 513 | function initState(vm) { 514 | var opts = vm.$options; 515 | 516 | if (opts.data) { 517 | initData(vm); 518 | } 519 | 520 | if (opts.computed) { 521 | initComputed(vm); 522 | } 523 | 524 | if (opts.watch) { 525 | initWatch(vm); 526 | } 527 | } 528 | 529 | function initWatch(vm) { 530 | var watch = vm.$options.watch; 531 | 532 | for (var key in watch) { 533 | var handler = watch[key]; 534 | 535 | if (Array.isArray(handler)) { 536 | for (var i = 0; i < handler.length; i++) { 537 | createWatcher(vm, key, handler[i]); 538 | } 539 | } else { 540 | createWatcher(vm, key, handler); 541 | } 542 | } 543 | } 544 | 545 | function createWatcher(vm, key, handler) { 546 | if (typeof handler === "string") { 547 | handler = vm[handler]; 548 | } 549 | 550 | return vm.$watch(key, handler); 551 | } 552 | 553 | function proxy(vm, target, key) { 554 | Object.defineProperty(vm, key, { 555 | get: function get() { 556 | return vm[target][key]; 557 | }, 558 | set: function set(newValue) { 559 | vm[target][key] = newValue; 560 | }, 561 | }); 562 | } 563 | 564 | function initData(vm) { 565 | var data = vm.$options.data; 566 | data = typeof data == "function" ? data.call(vm) : data; 567 | vm._data = data; 568 | observe(data); 569 | 570 | for (var key in data) { 571 | proxy(vm, "_data", key); 572 | } 573 | } 574 | 575 | function initComputed(vm) { 576 | var computed = vm.$options.computed; 577 | var watchers = (vm._computedWatchers = {}); 578 | 579 | for (var key in computed) { 580 | var userDef = computed[key]; // 我们需要监控计算属性中get的变化 581 | 582 | var fn = typeof userDef === "function" ? userDef : userDef.get; // 如果直接new watcher,默认立即执行fn 583 | 584 | watchers[key] = new Watcher(vm, fn, { 585 | lazy: true, 586 | }); 587 | defineComputed(vm, key, userDef); 588 | } 589 | } 590 | 591 | function defineComputed(target, key, userDef) { 592 | typeof userDef === "function" ? userDef : userDef.get; 593 | 594 | var setter = userDef.set || function () {}; 595 | 596 | Object.defineProperty(target, key, { 597 | get: createComputedGatter(key), 598 | set: setter, 599 | }); 600 | } // 计算属性不会手收集依赖,只会让自己的依赖属性去收集依赖 601 | 602 | function createComputedGatter(key) { 603 | // 检测是否执行gatter 604 | return function () { 605 | // 获取到对应属性的watcher 606 | var watcher = this._computedWatchers[key]; 607 | 608 | if (watcher.dirty) { 609 | // 如果是脏的,就去执行用户传入的函数 610 | watcher.evalute(); // 求值后dirty变为false,下次就不求值了 611 | } 612 | 613 | if (Dep.target) { 614 | // 计算属性出栈后还有渲染watcher,应该让计算属性watcher里的属性也去收集渲染watcher 615 | watcher.depend(); 616 | } // 最后返回的是watch上的值 617 | 618 | return watcher.value; 619 | }; 620 | } 621 | 622 | function initStateMixin(Vue) { 623 | Vue.prototype.$nextTick = nextTick; // 所有watch方法的底层都是在调用$watch 624 | 625 | Vue.prototype.$watch = function (exprOrFn, cb) { 626 | // expOrFn可能是一个变量,也可能是函数 627 | new Watcher( 628 | this, 629 | exprOrFn, 630 | { 631 | user: true, 632 | }, 633 | cb 634 | ); 635 | }; 636 | } 637 | 638 | var ncname = "[a-zA-Z_][\\-\\.0-9_a-zA-Z]*"; // 下面的这个正则中的:表示匹配命名空间: 639 | 640 | var qnameCapture = "((?:".concat(ncname, "\\:)?").concat(ncname, ")"); // 匹配前标签开始
]>*>")); // 匹配属性,第一个分组是属性的key,属性的值是分组3/4/5 645 | 646 | var attribute = 647 | /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>']+)))?/; //匹配前标签结束 648 | 649 | var startTagClose = /^\s*(\/?)>/; // 匹配{{}} 650 | 651 | function parseHTML(html) { 652 | var ELEMENT_TYPE = 1; 653 | var TEXT_TYPE = 3; 654 | var stack = []; 655 | var currentParent; 656 | var root; // 创建节点 657 | 658 | function createASTElement(tag, attrs) { 659 | return { 660 | tag: tag, 661 | type: ELEMENT_TYPE, 662 | children: [], 663 | attrs: attrs, 664 | parent: null, 665 | }; 666 | } 667 | 668 | function advance(n) { 669 | html = html.substring(n); 670 | } // 在解析的各个阶段建立一颗ast语法树 671 | 672 | function start(tag, attrs) { 673 | var node = createASTElement(tag, attrs); 674 | 675 | if (!root) { 676 | root = node; 677 | } // 如果有栈中有值,就将栈中最后一个元素作为parent 678 | 679 | if (currentParent) { 680 | // 这里要同时建立节点的父子关系 681 | node.parent = currentParent; 682 | currentParent.children.push(node); 683 | } // 将当前的节点推入栈中,并更新当前的父节点 684 | 685 | stack.push(node); 686 | currentParent = node; 687 | } 688 | 689 | function end(tag) { 690 | // 出栈并更新当前父节点 691 | stack.pop(); 692 | currentParent = stack[stack.length - 1]; 693 | } 694 | 695 | function _char(text) { 696 | // 处理文本节点 697 | text = text.replace(/\s/g, ""); 698 | text && 699 | currentParent.children.push({ 700 | type: TEXT_TYPE, 701 | text: text, 702 | parent: currentParent, 703 | }); 704 | } // 解析开始标签,收集属性 705 | 706 | function parseStartTag() { 707 | var start = html.match(startTagOpen); 708 | 709 | if (start) { 710 | var match = { 711 | tagName: [start[1]], 712 | //标签名 713 | attrs: [], 714 | }; 715 | advance(start[0].length); // 如果不是开始标签的结束,就一直匹配下去 716 | 717 | var attr, _end; 718 | 719 | while ( 720 | !(_end = html.match(startTagClose)) && 721 | (attr = html.match(attribute)) 722 | ) { 723 | advance(attr[0].length); 724 | match.attrs.push({ 725 | name: attr[1], 726 | value: attr[3] || attr[4] || attr[5] || true, 727 | }); 728 | } 729 | 730 | if (_end) { 731 | advance(_end[0].length); 732 | } 733 | 734 | return match; 735 | } 736 | 737 | return false; 738 | } 739 | 740 | while (html) { 741 | // textEnd如果为0,就是一个开始标签或结束标签 742 | //textEnd>0,说明是一个文本 743 | var textEnd = html.indexOf("<"); //如果indexOf中的索引是0,就是一个标签 744 | 745 | if (textEnd == 0) { 746 | var startTagMatch = parseStartTag(); 747 | 748 | if (startTagMatch) { 749 | // 解析到开始标签 750 | start(startTagMatch.tagName, startTagMatch.attrs); 751 | continue; 752 | } 753 | 754 | var endTagMatch = html.match(endTag); 755 | 756 | if (endTagMatch) { 757 | advance(endTagMatch[0].length); 758 | end(endTagMatch[1]); 759 | continue; 760 | } 761 | } 762 | 763 | if (textEnd > 0) { 764 | var text = html.substring(0, textEnd); //文本内容 765 | 766 | if (text) { 767 | _char(text); 768 | 769 | advance(text.length); 770 | } 771 | 772 | continue; 773 | } 774 | } 775 | 776 | return root; 777 | } 778 | 779 | var defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; 780 | 781 | function genProps(attrs) { 782 | var str = ""; 783 | 784 | for (var i = 0; i < attrs.length; i++) { 785 | var attr = attrs[i]; // style要做特殊处理 786 | 787 | if (attr.name == "style") { 788 | (function () { 789 | var obj = {}; 790 | attr.value.split(";").forEach(function (item) { 791 | var _item$split = item.split(":"), 792 | _item$split2 = _slicedToArray(_item$split, 2), 793 | key = _item$split2[0], 794 | value = _item$split2[1]; 795 | 796 | obj[key] = value; 797 | }); 798 | attr.value = obj; 799 | })(); 800 | } 801 | 802 | str += "".concat(attr.name, ":").concat(JSON.stringify(attr.value), ","); 803 | } 804 | 805 | return "{".concat(str.slice(0, -1), "}"); 806 | } // 将children生成代码 807 | 808 | function genChildren(children) { 809 | if (children) { 810 | return children 811 | .map(function (child) { 812 | return gen(child); 813 | }) 814 | .join(","); 815 | } 816 | } 817 | 818 | function gen(node) { 819 | // 如果有子节点就递归生成 820 | if (node.type === 1) { 821 | return codegen(node); 822 | } else { 823 | var text = node.text; 824 | 825 | if (!defaultTagRE.test(text)) { 826 | // 文本节点直接格式化处理 827 | return "_v(".concat(JSON.stringify(text), ")"); 828 | } else { 829 | // 操作模板语法,将模板语法替换为变量 830 | var tokens = []; 831 | var match; // 注意这里将正则的lastIndex重置为0,每次的行为一致 832 | 833 | defaultTagRE.lastIndex = 0; 834 | var lastIndex = 0; 835 | 836 | while ((match = defaultTagRE.exec(text))) { 837 | var index = match.index; 838 | 839 | if (index > lastIndex) { 840 | // 添加模板引擎之前/之后的内容 841 | tokens.push(JSON.stringify(text.slice(lastIndex, index))); 842 | } // 将模板中的变量添加进去 843 | 844 | tokens.push("_s(".concat(match[1].trim(), ")")); 845 | lastIndex = index + match[0].length; 846 | } 847 | 848 | if (lastIndex < text.length) { 849 | // 添加一般的文本 850 | tokens.push(JSON.stringify(text.slice(lastIndex))); 851 | } 852 | 853 | return "_v(".concat(tokens.join("+"), ")"); 854 | } 855 | } 856 | } // 将ast语法树生成render函数 857 | 858 | function codegen(ast) { 859 | var children = genChildren(ast.children); 860 | var code = "_c('" 861 | .concat(ast.tag, "',") 862 | .concat(ast.attrs.length > 0 ? genProps(ast.attrs) : "null") 863 | .concat(ast.children.length ? ",".concat(children) : "", ")"); 864 | return code; 865 | } 866 | 867 | function complieToFunction(template) { 868 | var ast = parseHTML(template); 869 | var code = codegen(ast); // 绑定this并利用Function生成函数 870 | 871 | code = "with(this){return ".concat(code, "}"); 872 | var render = new Function(code); 873 | return render; 874 | } 875 | 876 | var isReservedTag = function isReservedTag(tag) { 877 | return [ 878 | "a", 879 | "div", 880 | "span", 881 | "ul", 882 | "li", 883 | "ol", 884 | "button", 885 | "input", 886 | "h1", 887 | "h2", 888 | "h3", 889 | "p", 890 | "br", 891 | ].includes(tag); 892 | }; 893 | 894 | function createElementVNode(vm, tag, data) { 895 | if (data == null) { 896 | data = {}; 897 | } 898 | 899 | var key = data.key; 900 | 901 | if (key) { 902 | delete data.key; 903 | } // 判断是否是原生标签 904 | 905 | for ( 906 | var _len = arguments.length, 907 | children = new Array(_len > 3 ? _len - 3 : 0), 908 | _key = 3; 909 | _key < _len; 910 | _key++ 911 | ) { 912 | children[_key - 3] = arguments[_key]; 913 | } 914 | 915 | if (isReservedTag(tag)) { 916 | return vnode(vm, tag, key, data, children); 917 | } else { 918 | // 创造一个组件的虚拟节点,包含组件的构造函数 919 | var Ctor = vm.$options.components[tag]; //组件的构造函数 920 | // Ctor是组件的定义,可能是配置对象(模板选项)或者是Sub(Vue的子类) 921 | //全局组件是构造函数,否则是对象 922 | 923 | return createComponentVNode(vm, tag, key, data, children, Ctor); // 调用完这个方法之后,vnode.componentInstance上 924 | } 925 | } 926 | 927 | function createComponentVNode(vm, tag, key, data, children, Ctor) { 928 | if (_typeof(Ctor) == "object") { 929 | // 确保Ctor一定是构造函数 930 | Ctor = vm.$options._base.extend(Ctor); 931 | } 932 | 933 | data.hook = { 934 | // 用于创建真实节点的时候,如果是组件则调用此方法 935 | init: function init(vnode) { 936 | // 保存组件的实例到虚拟节点上 937 | var instance = (vnode.componentInstance = 938 | new vnode.componentOptions.Ctor()); 939 | instance.$mount(); // 执行后instance上增加了$el 940 | }, 941 | }; 942 | return vnode(vm, tag, key, data, children, null, { 943 | Ctor: Ctor, 944 | }); 945 | } 946 | 947 | function createTextVNode(vm, text) { 948 | return vnode(vm, undefined, undefined, undefined, undefined, text); 949 | } // ast是描述JS,css,等语言本身的情况的 950 | // 虚拟dom是描述dom节点的 951 | 952 | function vnode(vm, tag, key, data, children, text, componentOptions) { 953 | return { 954 | vm: vm, 955 | tag: tag, 956 | key: key, 957 | data: data, 958 | children: children, 959 | text: text, 960 | // 包含了组件的构造函数 961 | componentOptions: componentOptions, 962 | }; 963 | } 964 | 965 | function isSameVnode(vnode1, vnode2) { 966 | return vnode1.tag === vnode2.tag && vnode1.key === vnode2.key; 967 | } 968 | 969 | function createComponent(vnode) { 970 | var i = vnode.data; 971 | 972 | if ((i = i.hook) && (i = i.init)) { 973 | i(vnode); //使用init方法初始化组件,调用$mount() 974 | } 975 | 976 | if (vnode.componentInstance) { 977 | return true; //说明是组件 978 | } 979 | } 980 | 981 | function createElm(vnode) { 982 | var tag = vnode.tag, 983 | data = vnode.data, 984 | children = vnode.children, 985 | text = vnode.text; 986 | 987 | if (typeof tag == "string") { 988 | // 创建真实节点需要知道是组件还是真实元素 989 | if (createComponent(vnode)) { 990 | // 这里的$el是在执行$mount后产生的虚拟节点对应的真实节点 991 | return vnode.componentInstance.$el; 992 | } // 将真实节点和虚拟节点进行对应,为后续diff算法做准备 993 | 994 | vnode.el = document.createElement(tag); 995 | patchProps(vnode.el, {}, data); 996 | children.forEach(function (child) { 997 | vnode.el.appendChild(createElm(child)); 998 | }); 999 | } else { 1000 | vnode.el = document.createTextNode(text); 1001 | } 1002 | 1003 | return vnode.el; 1004 | } 1005 | function patchProps(el) { 1006 | var oldProps = 1007 | arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 1008 | var props = 1009 | arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; 1010 | // 老的属性中有,新的没有,要删除老的 1011 | oldProps.style || {}; 1012 | var newStyle = props.style; // 对于style 1013 | 1014 | for (var key in oldProps) { 1015 | if (!newStyle[key]) { 1016 | el.style[key] = ""; 1017 | } 1018 | } // 对于一般属性 1019 | 1020 | for (var _key in oldProps) { 1021 | if (!props[_key]) { 1022 | el.removeAttribute(_key); 1023 | } 1024 | } // 用新的覆盖掉老的 1025 | 1026 | for (var _key2 in props) { 1027 | if (_key2 == "style") { 1028 | for (var styleName in props.style) { 1029 | el.style[styleName] = props.style[styleName]; 1030 | } 1031 | } else { 1032 | el.setAttribute(_key2, props[_key2]); 1033 | } 1034 | } 1035 | } 1036 | function patch(oldVNode, vnode) { 1037 | if (!oldVNode) { 1038 | // 没有el,表示是组件的挂载 1039 | //注意这里要修改init中的挂载方法,没有el也可以挂载 1040 | //vm.$el就是渲染的结果 1041 | return createElm(vnode); 1042 | } 1043 | 1044 | var isRealElement = oldVNode.nodeType; 1045 | 1046 | if (isRealElement) { 1047 | // 获取真实元素 1048 | var elm = oldVNode; // 拿到父元素 1049 | 1050 | var parentElm = elm.parentNode; 1051 | var newElm = createElm(vnode); 1052 | parentElm.insertBefore(newElm, elm.nextSibiling); 1053 | parentElm.removeChild(elm); 1054 | return newElm; 1055 | } else { 1056 | // diff算法 1057 | return patchVnode(oldVNode, vnode); 1058 | } 1059 | } // 利用diff算法更新两个节点 1060 | 1061 | function patchVnode(oldVNode, vnode) { 1062 | // 两个节点不是同一个节点,直接删除老的,换上新的(没有对比) 1063 | // 两个节点是同一个节点,判断节点的tag和key,tag和key一样是同一个节点,此时去比较两个节点的属性是否有差异(复用老的节点,将差异的属性更新) 1064 | // 节点比较完成后,比较两个节点的子节点 1065 | // 如果不是同一节点,用新节点替换老节点 1066 | if (!isSameVnode(oldVNode, vnode)) { 1067 | // 用老节点的父亲进行替换 1068 | //这里的el属性就是虚拟节点对应的真实节点 1069 | var _el = createElm(vnode); 1070 | 1071 | oldVNode.el.parentNode.replaceChild(_el, oldVNode); 1072 | return _el; 1073 | } // 如果是文本节点,就比对一下文本的内容 1074 | 1075 | var el = (vnode.el = oldVNode.el); //复用老节点的元素 1076 | 1077 | if (!oldVNode.tag) { 1078 | // 文本的情况 1079 | if (oldVNode.text !== vnode.text) { 1080 | el.textContent = vnode.text; 1081 | } 1082 | } //是标签,需要比对标签的属性 1083 | 1084 | patchProps(el, oldVNode.data, vnode.data); // 比较子节点: 1085 | // 1.一方有儿子,一方没儿子 1086 | // 2.两方都有儿子 1087 | 1088 | var oldChildren = oldVNode.children || []; 1089 | var newChildren = vnode.children || []; 1090 | 1091 | if (oldChildren.length > 0 && newChildren.length > 0) { 1092 | // 完整的diff算法 1093 | updateChild(el, oldChildren, newChildren); 1094 | } else if (newChildren > 0) { 1095 | // 老的没有新的有 1096 | mountChildren(el, newChildren); 1097 | } else if (oldChildren > 0) { 1098 | // 新的没有老的有 1099 | unmountChild(el); 1100 | } 1101 | 1102 | return el; 1103 | } 1104 | 1105 | function mountChildren(el, children) { 1106 | for (var i = 0; i < children.length; i++) { 1107 | var child = newChildren[i]; 1108 | el.appendChild(createElm(child)); 1109 | } 1110 | } 1111 | 1112 | function unmountChild(el, children) { 1113 | el.innerHTML = ""; 1114 | } 1115 | 1116 | function updateChild(el, oldChildren, newChildren) { 1117 | // 为了增高性能,会有一些优化手段 1118 | // vue2中采用双指针的方式比较两个节点 1119 | var oldStartIndex = 0; 1120 | var newStartIndex = 0; 1121 | var oldEndIndex = oldChildren.length - 1; 1122 | var newEndIndex = newChildren.length - 1; 1123 | var oldStartVnode = oldChildren[0]; 1124 | var newStartVnode = newChildren[0]; 1125 | var oldEndVnode = oldChildren[oldEndIndex]; 1126 | var newEndVnode = newChildren[newEndIndex]; 1127 | 1128 | function makeIndexByKey(children) { 1129 | var map = {}; 1130 | children.forEach(function (child, index) { 1131 | map[child.key] = index; 1132 | }); 1133 | return map; 1134 | } 1135 | 1136 | var map = makeIndexByKey(oldChildren); 1137 | 1138 | while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) { 1139 | // 有一方的头指针大于尾部指针,则停止循环 1140 | // 如果是相同节点,则递归比较子节点 1141 | if (!oldStartVnode) { 1142 | // 处理置空节点产生的undefind的问题 1143 | oldStartVnode = oldChildren[++oldStartIndex]; 1144 | } else if (!oldEndVnode) { 1145 | // 处理置空节点产生的undefind的问题 1146 | oldEndVnode = oldChildren[--oldEndIndex]; 1147 | } else if (isSameVnode(oldStartVnode, newStartVnode)) { 1148 | patchVnode(oldStartVnode, newStartVnode); // 指针移动 1149 | 1150 | oldStartVnode = oldChildren[++oldStartIndex]; 1151 | newStartVnode = newChildren[++newStartIndex]; 1152 | } // 当首个元素不同时反向比对 1153 | else if (isSameVnode(oldEndVnode, newEndVnode)) { 1154 | patchVnode(oldEndVnode, newEndVnode); 1155 | oldEndVnode = oldChildren[--oldEndIndex]; 1156 | newEndVnode = newChildren[--newEndIndex]; 1157 | } // 交叉比对,优化reverse方法 abcd__>dabc,处理了倒叙和排序的情况 1158 | else if (isSameVnode(oldEndVnode, newStartVnode)) { 1159 | patchVnode(oldEndVnode, newStartVnode); // 将老的尾部移动到老的前面去(变为了新前对旧前) 1160 | // insertBefore具有移动性,会将原来的元素移动走 1161 | 1162 | el.insertBefore(oldEndVnode.el, oldStartVnode.el); 1163 | oldEndVnode = oldChildren[--oldEndIndex]; 1164 | newStartVnode = newChildren[++newStartIndex]; 1165 | } else if (isSameVnode(oldStartVnode, newEndVnode)) { 1166 | patchVnode(oldStartVnode, newEndVnode); // 将老的尾部移动到老的前面去(变为了新前对旧前) 1167 | // insertBefore具有移动性,会将原来的元素移动走 1168 | 1169 | el.insertBefore(oldStartVnode.el, oldEndVnode.el.nextSibiling); 1170 | oldStartVnode = oldChildren[++oldStartIndex]; 1171 | newEndVnode = newChildren[--newEndIndex]; 1172 | } else { 1173 | var _newStartVnode; 1174 | 1175 | // 给动态列表添加key时,尽量避免使用索引,可能导致错误复用 1176 | // 乱序比对:根据老的列表做一个映射关系,用新的逐个比对查找,找到移动,找不到添加,多出的删除 1177 | // 如果拿到说明是要移动的索引 1178 | var moveIndex = 1179 | map[ 1180 | (_newStartVnode = newStartVnode) === null || 1181 | _newStartVnode === void 0 1182 | ? void 0 1183 | : _newStartVnode.key 1184 | ]; 1185 | 1186 | if (moveIndex !== undefined) { 1187 | // 找到对应的虚拟节点进行复用 1188 | var moveVnode = oldChildren[moveIndex]; 1189 | el.insertBefore(moveVnode.el, oldStartVnode.el); 1190 | oldChildren[moveIndex] = undefined; //表示这个节点已经被移走了 1191 | // 递归比较属性和子节点 1192 | 1193 | patchVnode(moveVnode, newStartVnode); 1194 | } else { 1195 | // 无法找到老节点 1196 | el.insertBefore(createElm(newStartVnode), oldStartVnode.el); 1197 | } 1198 | 1199 | newStartVnode = newChildren[++newStartIndex]; 1200 | } 1201 | } // 多出元素删除,缺少元素添加 1202 | // 相比于原有的数组有新增元素,尾部对新增元素进行添加 1203 | 1204 | if (newStartIndex <= newEndIndex) { 1205 | for (var i = newStartIndex; i <= newEndIndex; i++) { 1206 | var childEl = createElm(newChildren[i]); // 这里也有可能向前追加 1207 | 1208 | var anchor = newChildren[newEndIndex + 1] 1209 | ? newChildren[newEndIndex + 1].el 1210 | : null; 1211 | el.insertBefore(childEl, anchor); // anchor为null时,则等价于appendChild 1212 | } 1213 | } // 相比于原有数组尾部减少元素,对被减少的元素进行删除 1214 | 1215 | if (oldStartIndex <= oldEndIndex) { 1216 | for (var _i = oldStartIndex; _i <= oldEndIndex; _i++) { 1217 | if (oldChildren[_i]) { 1218 | var _childEl = oldChildren[_i].el; 1219 | el.removeChild(_childEl); 1220 | } 1221 | } 1222 | } 1223 | } 1224 | 1225 | function initLifeCycle(Vue) { 1226 | Vue.prototype._update = function (vnode) { 1227 | // patch既有初始化功能,又有更新的功能 1228 | var vm = this; 1229 | var el = vm.$el; // 把组件第一次产生的虚拟节点保存到_vnode上 1230 | 1231 | var preVnode = vm._vnode; 1232 | vm._vnode = vnode; 1233 | 1234 | if (preVnode) { 1235 | // 之前渲染过 1236 | vm.$el = patch(preVnode, vnode); 1237 | } else { 1238 | vm.$el = patch(el, vnode); 1239 | } 1240 | }; 1241 | 1242 | Vue.prototype._render = function () { 1243 | // 渲染时会去实例上取值 1244 | var vm = this; 1245 | return vm.$options.render.call(this); //转移后生产的 render方法 1246 | }; // 创造虚拟节点 1247 | 1248 | Vue.prototype._c = function () { 1249 | return createElementVNode.apply( 1250 | void 0, 1251 | [this].concat(Array.prototype.slice.call(arguments)) 1252 | ); 1253 | }; // 创建文本虚拟节点 1254 | 1255 | Vue.prototype._v = function () { 1256 | return createTextVNode.apply( 1257 | void 0, 1258 | [this].concat(Array.prototype.slice.call(arguments)) 1259 | ); 1260 | }; // 创建普通文字节点 1261 | 1262 | Vue.prototype._s = function (value) { 1263 | if (_typeof(value) !== "object") return value; 1264 | return JSON.stringify(value); 1265 | }; 1266 | } 1267 | function mountComponent(vm, el) { 1268 | vm.$el = el; 1269 | 1270 | var updateComponent = function updateComponent() { 1271 | vm._update(vm._render()); //vm.$options.render,返回虚拟节点 1272 | }; // 注意,子组件挂载时也会调用这个方法,因此每个子组件也都会对应一个Watcher 1273 | // 1.调用render方法,产生虚拟dom 1274 | 1275 | new Watcher(vm, updateComponent, true); // 2.根据虚拟dom产生真实dom 1276 | // 3.插入到el元素中 1277 | } // 将模板转化为ast模板语法树,ast转化为render函数,后续每次数据更新只执行render函数(无需再转化ast) 1278 | // render函数会产生虚拟节点,根据创造的虚拟节点创造真实Dom 1279 | 1280 | function callHook(vm, hook) { 1281 | var handlers = vm.$options[hook]; 1282 | 1283 | if (handlers) { 1284 | handlers.forEach(function (handler) { 1285 | handler.call(vm); 1286 | }); 1287 | } 1288 | } 1289 | 1290 | var strats = {}; 1291 | var LIFECYCLE = [ 1292 | "beforeCreate", 1293 | "created", 1294 | "mounted", 1295 | "beforeUpdate", 1296 | "updated", 1297 | "beforeDestroy", 1298 | "destroy", 1299 | ]; 1300 | LIFECYCLE.forEach(function (hook) { 1301 | strats[hook] = function (p, c) { 1302 | if (c) { 1303 | if (p) { 1304 | // 第一次之后,p必定为一个数组 1305 | return p.concat(c); 1306 | } else { 1307 | // 第一次合并p为{} 1308 | return [c]; 1309 | } 1310 | } else { 1311 | // 如果儿子没有,直接返回父亲 1312 | // c没有的情况下,p可能有,也可能为undefined 1313 | return p; 1314 | } 1315 | }; 1316 | }); 1317 | 1318 | strats.components = function (parentVal, childVal) { 1319 | var res = Object.create(parentVal); 1320 | 1321 | if (childVal) { 1322 | for (var key in childVal) { 1323 | // 返回的是构造的对象,可以返回父亲原型上的属性,并将儿子的属性拷贝到自己身上 1324 | res[key] = childVal[key]; 1325 | } 1326 | } 1327 | 1328 | return res; 1329 | }; 1330 | 1331 | function mergeOptions(parent, child) { 1332 | var options = {}; 1333 | 1334 | for (var key in parent) { 1335 | mergeField(key); 1336 | } 1337 | 1338 | for (var _key in child) { 1339 | if (!parent.hasOwnProperty(_key)) { 1340 | mergeField(_key); 1341 | } 1342 | } 1343 | 1344 | function mergeField(key) { 1345 | // 策略模式减少if-else 1346 | if (strats[key]) { 1347 | options[key] = strats[key](parent[key], child[key]); 1348 | } else { 1349 | // 不在策略中则优先采用儿子的,再采用父亲 1350 | options[key] = child[key] || parent[key]; 1351 | } 1352 | } 1353 | 1354 | return options; 1355 | } 1356 | 1357 | // 给Vue增加初始化方法 1358 | function initMixin(Vue) { 1359 | Vue.prototype._init = function (options) { 1360 | var vm = this; // 将用户传入的选项和全局选项进行合并 1361 | 1362 | vm.$options = mergeOptions(this.constructor.options, options); 1363 | console.log(vm.$options); 1364 | callHook(vm, "beforeCreated"); 1365 | initState(vm); 1366 | callHook(vm, "created"); 1367 | 1368 | if (options.el) { 1369 | vm.$mount(options.el); 1370 | } 1371 | }; 1372 | 1373 | Vue.prototype.$mount = function (el) { 1374 | var vm = this; 1375 | el = document.querySelector(el); 1376 | var opts = vm.$options; // 当没有render函数时 1377 | 1378 | if (!(opts !== null && opts !== void 0 && opts.render)) { 1379 | var template = null; // 没有模板但写了el 1380 | 1381 | if (!opts.template && opts.el) { 1382 | template = el.outerHTML; // 存在模板或不存在模板和el 1383 | } else { 1384 | // 存在模板 1385 | if (opts.template) { 1386 | template = opts.template; 1387 | } else { 1388 | // 既没有模板也没有el 1389 | template = "
"; 1390 | } 1391 | } //拿到模板 1392 | // 获取优先级:render=>temple=>el 1393 | 1394 | if (template) { 1395 | var render = complieToFunction(template); 1396 | opts.render = render; 1397 | } 1398 | } 1399 | 1400 | mountComponent(vm, el); 1401 | }; 1402 | } // script标签引入的vue,编译过程在浏览器 1403 | // runtime是不包含编译的,编译时通过loader进行转译.vue文件,用runtime不能使用template(在mian.js中,.vue文件有loader转译,因此不影响) 1404 | // 包含main.js中模板编译的版本是runtime-with-compiler 1405 | 1406 | function initGlobalAPI(Vue) { 1407 | Vue.options = { 1408 | _base: Vue, 1409 | }; 1410 | 1411 | Vue.mixin = function (mixin) { 1412 | // 期望将用户的选项和全局的options进行合并 1413 | // Vue的混入本质是一个订阅发布者模式 1414 | this.options = mergeOptions(Vue.options, mixin); 1415 | return this; 1416 | }; // 可以手动改创造组件进行挂载 1417 | 1418 | Vue.extend = function (options) { 1419 | // 根据用户的参数,返回一个构造函数 1420 | // 最终使用一个组件,就是new一个实例 1421 | function Sub() { 1422 | var options = 1423 | arguments.length > 0 && arguments[0] !== undefined 1424 | ? arguments[0] 1425 | : {}; 1426 | 1427 | this._init(options); // 默认对子类进行初始化操作 1428 | } 1429 | 1430 | Sub.prototype = Object.create(Vue.prototype); 1431 | Sub.prototype.constructor = Sub; // 希望将用户传递的参数和全局的Vue.options合并,使形成类似原型链的查找方式,出现重名优先查找自己 1432 | 1433 | Sub.options = mergeOptions(Vue.options, options); //保存用户传递的选项 1434 | 1435 | return Sub; // 子组件挂载时也会产生一个watcher 1436 | }; 1437 | 1438 | Vue.options.components = {}; 1439 | 1440 | Vue.component = function (id, definition) { 1441 | // 如果definition已经是一个函数了,说明用户自己调用了vue.extend 1442 | definition = 1443 | typeof definition == "function" ? definition : Vue.extend(definition); 1444 | Vue.options.components[id] = definition; 1445 | }; 1446 | } 1447 | 1448 | function Vue(options) { 1449 | this._init(options); 1450 | } // 扩展了init方法 1451 | 1452 | initMixin(Vue); // 提供了_update()和_render两个方法 1453 | 1454 | initLifeCycle(Vue); // 实现了$nextTick和$watch 1455 | 1456 | initStateMixin(Vue); // 实现全局API 1457 | 1458 | initGlobalAPI(Vue); // diff算法是一个平级比较的过程,父亲不能跟儿子进行比对 1459 | 1460 | return Vue; 1461 | }); 1462 | //# sourceMappingURL=Vue.js.map 1463 | -------------------------------------------------------------------------------- /mine-Vue/lib/vue.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Vue.js","sources":["../src/observe/dep.js","../src/observe/array.js","../src/observe/index.js","../src/observe/watcher.js","../src/state.js","../src/compiler/parse.js","../src/compiler/index.js","../src/vdom/index.js","../src/vdom/patch.js","../src/lifecycle.js","../src/utils.js","../src/init.js","../src/gloablAPI.js","../src/index.js"],"sourcesContent":["let id = 0;\n// 每一个dep都表示一个被依赖的数据,当这个数据变化,跟这些数据关联的视图会同步变化\nclass Dep {\n constructor() {\n this.id = id++;\n this.subs = [];\n }\n depend() {\n // 不希望放置重复的watcher\n // 这里在添加一个watch时,这个watch也会将这个dep添加到自己的观察队列中\n Dep.target.addDep(this);\n }\n // 这个方法是让watcher将自己添加到观察队列的\n addSub(watcher) {\n this.subs.push(watcher);\n }\n // 通知所有观察了这个dep的watch更新视图\n notify() {\n this.subs.forEach((watcher) => {\n watcher.update();\n });\n }\n}\nlet stack = [];\nexport function pushTarget(watcher) {\n stack.push(watcher);\n Dep.target = watcher;\n}\nexport function popTarget() {\n stack.pop();\n Dep.target = stack[stack.length - 1];\n}\nexport default Dep;\n","// 我们希望保留原数组特性并重写部分数组方法\nlet oldArrayProto = Array.prototype;\nexport let newArrayProto = Object.create(oldArrayProto);\n// 所有变异方法\nconst methods = [\n \"push\",\n \"shift\",\n \"unshift\",\n \"splice\",\n \"pop\",\n \"reverse\",\n \"sort\",\n];\nmethods.forEach((method) => {\n newArrayProto[method] = function (...args) {\n // 内部调用原来的方法\n const result = oldArrayProto[method].call(this, ...args);\n let ob = this.__ob__;\n // 将数组中新增的方法进行响应式劫持\n let inserted;\n switch (method) {\n case \"push\":\n case \"unshift\":\n inserted = args;\n break;\n case \"splice\":\n inserted = args.slice(2);\n default:\n break;\n }\n if (inserted) {\n ob.observeArray(inserted);\n }\n // 数组变化后通知对应的 watcher实现更新\n ob.dep.notify();\n return result;\n };\n});\n","import { newArrayProto } from \"./array\";\nimport Dep from \"./dep\";\nclass Observe {\n // 给每个对象都增加收集功能\n // 要给数组和对象本身也增加dep,如果用户增添了属性或数组新增了一项,都会触发dep\n constructor(data) {\n // 给数据添加一个表示__ob__,被标识的数据标识已经被观测过了\n //data.__ob__=this 直接将this添加到__ob__后,会导致遍历可观测对象时遍历到this,形成死循环\n // 添加属性__ob__并将这个属性设置为不可枚举,使其在遍历时无法被遍历\n this.dep = new Dep();\n Object.defineProperty(data, \"__ob__\", {\n value: this,\n enumerable: false,\n });\n if (Array.isArray(data)) {\n // 用户一般不会通过索引调用数组的值,直接遍历又会导致性能问题\n //因此我们可以通过重写数组7个变异方法的方式来监控数据变化\n //同时应该考虑数组中对象的劫持\n data.__proto__ = newArrayProto;\n this.observeArray(data); //监控数组中的对象,只将数组中的对象进行挂载\n } else {\n this.walk(data);\n }\n // Object.defineProperty只能劫持已经存在的属性\n }\n walk(data) {\n //循环对象,对属性依次劫持,重新定义属性\n Object.keys(data).forEach((key) => {\n defineReactive(data, key, data[key]);\n });\n }\n observeArray(data) {\n data.forEach((item) => {\n observe(item);\n });\n }\n}\nfunction dependArray(value) {\n // 对数组的每一个元素进行观察\n for (let i = 0; i < value.length; i++) {\n // 如果数组中有对象(有__ob__表示是对象且被标记过),那么需要将数组中的所有对象进行观测\n value[i].__ob__ && value[i].__ob__.dep.depend();\n // 如果数组中的子元素还是数组,则继续递归\n if (Array.isArray(value[i])) {\n dependArray(value[i]);\n }\n }\n}\nexport function defineReactive(target, key, value) {\n // 闭包,从外部拿到value\n // 如果劫持到的属性依然是一个对象,就应该递归劫持所有属性,深度属性劫持\n let childOb = observe(value);\n // 每一个属性都有一个dep,这里是闭包,因此变量不会销毁\n let dep = new Dep();\n Object.defineProperty(target, key, {\n get() {\n // 如果Dep.target不为null,证明这个属性被某个watch依赖\n if (Dep.target) {\n dep.depend();\n if (childOb) {\n // 让数组和对象也实现依赖收集\n // 如果出现对象套对象的情况,就将这个属性继续放入dep队列观察,深度遍历\n childOb.dep.depend();\n // 当出现数组套数组的情况时,进行深度遍历\n if (Array.isArray(value)) {\n dependArray(value);\n }\n }\n }\n return value;\n },\n set(newValue) {\n if (newValue == value) return;\n value = newValue;\n // 通知所有依赖这个属性的watch更新视图\n dep.notify();\n },\n });\n}\nexport function observe(data) {\n if (typeof data != \"object\" || data == null) {\n return; //只对对象进行劫持\n }\n //判断对象是否被劫持过,需要用一个实例来观测判断\n\n return new Observe(data);\n}\n","import Dep from \"./dep\";\nimport { pushTarget, popTarget } from \"./dep\";\nlet id = 0;\n// 解析一般data时只会创建一个渲染watcher,当解析计算属性时,会按栈结构去创建计算属性watcher\n// watcher的作用时:当依赖的dep发生更新时,对应地触发某些操作(比如重新渲染)\nclass Watcher {\n constructor(vm, exprOrFn, options, cb) {\n this.id = id++;\n this.renderWatcher = vm.options;\n // getter意味着调用这个函数会发生取值\n if (typeof exprOrFn === \"string\") {\n this.getter = function () {\n return vm[exprOrFn];\n };\n } else {\n this.getter = exprOrFn;\n }\n // 让watcher去记住所有dep,后续实现计算属性和清理工作需要使用\n this.deps = [];\n this.depsId = new Set();\n this.lazy = options.lazy;\n this.dirty = this.lazy;\n this.vm = vm;\n // 标识是否是用户自己的watcher\n this.user = options.user;\n this.cb = cb;\n // 计算属性第一次并不执行\n this.value = this.lazy ? undefined : this.get();\n }\n evalute() {\n // 获取到用户函数的返回值,并标识为脏\n this.value = this.get();\n this.dirty = false;\n }\n get() {\n // 将自己添加到Dep的静态属性上,让之后每个dep都可以添加到这个watch\n pushTarget(this);\n // 这个getter就是更新函数\n let value = this.getter.call(this.vm);\n // 将这个静态属性置为空\n popTarget();\n return value;\n }\n update() {\n // 当dep是计算属性\n // 当依赖的值发生变化时dirty是脏值\n if (this.lazy) {\n this.dirty = true;\n }\n // 重新渲染,这里为了防止多次更新视图,采用了事件环的方式合并多次操作\n queueWatcher(this);\n }\n depend() {\n let i = this.deps.length;\n while (i--) {\n this.deps[i].depend(); //让计算属性watcher也收集渲染watcher\n }\n }\n addDep(dep) {\n // 一个组件对应着多个属性,重复的属性也不用记录\n let id = dep.id;\n if (!this.depsId.has(id)) {\n this.deps.push(dep);\n this.depsId.add(id);\n dep.addSub(this);\n }\n }\n run() {\n let oldValue = this.value;\n let newValue = this.get();\n // user标识用户自定义的watcher\n if (this.user) {\n // 监控的值(dep)会收集watcher,如果监控的值(dep)发生了改变,就会执行对应的回调\n this.cb.call(this.vm, newValue, oldValue);\n }\n }\n}\nlet queue = [];\nlet has = {};\nlet pending = false;\nfunction flushSchedulerQueue() {\n let flushQueue = queue.slice(0);\n flushQueue.forEach((q) => {\n q.run();\n });\n queue = [];\n has = {};\n pending = false;\n}\nfunction queueWatcher(watcher) {\n const id = watcher.id;\n if (!has[id]) {\n queue.push(watcher);\n has[id] = true;\n // 不论update执行多少次,只执行一轮刷新操作\n // 多次操作只走第一次,后面的操作都会被放到队列里,等第一次执行完后下一个事件环执行\n if (!pending) {\n timerFunc(flushSchedulerQueue);\n pending = true;\n }\n }\n}\nlet callbacks = [];\nlet waiting = false;\nfunction flushCallbacks() {\n let cbs = callbacks.slice(0);\n cbs.forEach((cb) => cb());\n waiting = false;\n callbacks = [];\n}\n// nextTick不是创建了一个异步任务,而是将这个任务维护到了队列中\n// nextTick内部采用优雅降级:promise->MutationObserver->setImmediate->setTimeout\nlet timerFunc;\nif (Promise) {\n timerFunc = (fn) => {\n Promise.resolve().then(fn);\n };\n} else if (MutationObserver) {\n // 这里传入的回调是异步任务\n timerFunc = (fn) => {\n let observe = new MutationObserver(fn);\n let textNode = document.createElement(1);\n observe.observe(textNode, {\n characterData: true,\n });\n textNode.textContent = 2;\n };\n} else if (setImmediate) {\n timerFunc = (fn) => {\n setImmediate(fn);\n };\n} else {\n timerFunc = (fn) => {\n setTimeout(fn, 0);\n };\n}\nexport const nextTick = function (cb) {\n callbacks.push(cb);\n if (!waiting) {\n timerFunc(flushCallbacks);\n waiting = true;\n }\n};\n// 需要给每个属性增加dep,\n// n个属性对应一个视图,n个dep对应一个watcher\n// 一个属性对应多个视图 1个dep对应多个watcher\n// 多对多关系\nexport default Watcher;\n","import Dep from \"./observe/dep\";\nimport { observe } from \"./observe/index\";\nimport Watcher from \"./observe/watcher\";\nimport { nextTick } from \"./observe/watcher\";\nexport function initState(vm) {\n const opts = vm.$options;\n if (opts.data) {\n initData(vm);\n }\n if (opts.computed) {\n initComputed(vm);\n }\n if (opts.watch) {\n initWatch(vm);\n }\n}\nfunction initWatch(vm) {\n let { watch } = vm.$options;\n for (let key in watch) {\n const handler = watch[key];\n if (Array.isArray(handler)) {\n for (let i = 0; i < handler.length; i++) {\n createWatcher(vm, key, handler[i]);\n }\n } else {\n createWatcher(vm, key, handler);\n }\n }\n}\n\nfunction createWatcher(vm, key, handler) {\n if (typeof handler === \"string\") {\n handler = vm[handler];\n }\n return vm.$watch(key, handler);\n}\nfunction proxy(vm, target, key) {\n Object.defineProperty(vm, key, {\n get() {\n return vm[target][key];\n },\n set(newValue) {\n vm[target][key] = newValue;\n },\n });\n}\nfunction initData(vm) {\n let { data } = vm.$options;\n data = typeof data == \"function\" ? data.call(vm) : data;\n vm._data = data;\n observe(data);\n for (let key in data) {\n proxy(vm, \"_data\", key);\n }\n}\n\nfunction initComputed(vm) {\n const computed = vm.$options.computed;\n const watchers = (vm._computedWatchers = {});\n for (let key in computed) {\n let userDef = computed[key];\n // 我们需要监控计算属性中get的变化\n let fn = typeof userDef === \"function\" ? userDef : userDef.get;\n // 如果直接new watcher,默认立即执行fn\n watchers[key] = new Watcher(vm, fn, { lazy: true });\n defineComputed(vm, key, userDef);\n }\n}\n\nfunction defineComputed(target, key, userDef) {\n const getter = typeof userDef === \"function\" ? userDef : userDef.get;\n const setter = userDef.set || (() => {});\n Object.defineProperty(target, key, {\n get: createComputedGatter(key),\n set: setter,\n });\n}\n// 计算属性不会手收集依赖,只会让自己的依赖属性去收集依赖\nfunction createComputedGatter(key) {\n // 检测是否执行gatter\n return function () {\n // 获取到对应属性的watcher\n const watcher = this._computedWatchers[key];\n if (watcher.dirty) {\n // 如果是脏的,就去执行用户传入的函数\n watcher.evalute();\n // 求值后dirty变为false,下次就不求值了\n }\n if (Dep.target) {\n // 计算属性出栈后还有渲染watcher,应该让计算属性watcher里的属性也去收集渲染watcher\n watcher.depend();\n }\n // 最后返回的是watch上的值\n return watcher.value;\n };\n}\n\nexport function initStateMixin(Vue) {\n Vue.prototype.$nextTick = nextTick;\n // 所有watch方法的底层都是在调用$watch\n Vue.prototype.$watch = function (exprOrFn, cb, options = {}) {\n // expOrFn可能是一个变量,也可能是函数\n new Watcher(this, exprOrFn, { user: true }, cb);\n };\n}\n","const ncname = `[a-zA-Z_][\\\\-\\\\.0-9_a-zA-Z]*`;\n// 下面的这个正则中的:表示匹配命名空间:\nconst qnameCapture = `((?:${ncname}\\\\:)?${ncname})`;\n// 匹配前标签开始 ]>*>`);\n// 匹配属性,第一个分组是属性的key,属性的值是分组3/4/5\nconst attribute =\n /^\\s*([^\\s\"'<>\\/=]+)(?:\\s*(=)\\s*(?:\"([^\"]*)\"+|'([^']*)'+|([^\\s\"'=<>']+)))?/;\n//匹配前标签结束\nconst startTagClose = /^\\s*(\\/?)>/;\n// 匹配{{}}\nconst defaultTagRE = /\\{\\{((?:.|\\r?\\n)+?)\\}\\}/g;\n// 转化为ast模板语法树\nexport function parseHTML(html) {\n const ELEMENT_TYPE = 1;\n const TEXT_TYPE = 3;\n const stack = [];\n let currentParent;\n let root;\n // 创建节点\n function createASTElement(tag, attrs) {\n return {\n tag,\n type: ELEMENT_TYPE,\n children: [],\n attrs,\n parent: null,\n };\n }\n function advance(n) {\n html = html.substring(n);\n }\n // 在解析的各个阶段建立一颗ast语法树\n function start(tag, attrs) {\n let node = createASTElement(tag, attrs);\n if (!root) {\n root = node;\n }\n // 如果有栈中有值,就将栈中最后一个元素作为parent\n if (currentParent) {\n // 这里要同时建立节点的父子关系\n node.parent = currentParent;\n currentParent.children.push(node);\n }\n // 将当前的节点推入栈中,并更新当前的父节点\n stack.push(node);\n currentParent = node;\n }\n function end(tag) {\n // 出栈并更新当前父节点\n stack.pop();\n currentParent = stack[stack.length - 1];\n }\n function char(text) {\n // 处理文本节点\n text = text.replace(/\\s/g, \"\");\n text &&\n currentParent.children.push({\n type: TEXT_TYPE,\n text,\n parent: currentParent,\n });\n }\n // 解析开始标签,收集属性\n function parseStartTag() {\n const start = html.match(startTagOpen);\n if (start) {\n const match = {\n tagName: [start[1]], //标签名\n attrs: [],\n };\n advance(start[0].length);\n // 如果不是开始标签的结束,就一直匹配下去\n let attr, end;\n while (\n !(end = html.match(startTagClose)) &&\n (attr = html.match(attribute))\n ) {\n advance(attr[0].length);\n match.attrs.push({\n name: attr[1],\n value: attr[3] || attr[4] || attr[5] || true,\n });\n }\n if (end) {\n advance(end[0].length);\n }\n return match;\n }\n return false;\n }\n while (html) {\n // textEnd如果为0,就是一个开始标签或结束标签\n //textEnd>0,说明是一个文本\n let textEnd = html.indexOf(\"<\"); //如果indexOf中的索引是0,就是一个标签\n if (textEnd == 0) {\n const startTagMatch = parseStartTag();\n if (startTagMatch) {\n // 解析到开始标签\n start(startTagMatch.tagName, startTagMatch.attrs);\n continue;\n }\n let endTagMatch = html.match(endTag);\n if (endTagMatch) {\n advance(endTagMatch[0].length);\n end(endTagMatch[1]);\n continue;\n }\n }\n if (textEnd > 0) {\n let text = html.substring(0, textEnd); //文本内容\n if (text) {\n char(text);\n advance(text.length);\n }\n continue;\n }\n }\n return root;\n}\n","import { parseHTML } from \"./parse\";\n// 匹配{{}}\nconst defaultTagRE = /\\{\\{((?:.|\\r?\\n)+?)\\}\\}/g;\nfunction genProps(attrs) {\n let str = \"\";\n for (let i = 0; i < attrs.length; i++) {\n let attr = attrs[i];\n // style要做特殊处理\n if (attr.name == \"style\") {\n let obj = {};\n attr.value.split(\";\").forEach((item) => {\n let [key, value] = item.split(\":\");\n obj[key] = value;\n });\n attr.value = obj;\n }\n str += `${attr.name}:${JSON.stringify(attr.value)},`;\n }\n return `{${str.slice(0, -1)}}`;\n}\n// 将children生成代码\nfunction genChildren(children) {\n if (children) {\n return children\n .map((child) => {\n return gen(child);\n })\n .join(\",\");\n }\n}\nfunction gen(node) {\n // 如果有子节点就递归生成\n if (node.type === 1) {\n return codegen(node);\n } else {\n let text = node.text;\n if (!defaultTagRE.test(text)) {\n // 文本节点直接格式化处理\n return `_v(${JSON.stringify(text)})`;\n } else {\n // 操作模板语法,将模板语法替换为变量\n let tokens = [];\n let match;\n // 注意这里将正则的lastIndex重置为0,每次的行为一致\n defaultTagRE.lastIndex = 0;\n let lastIndex = 0;\n while ((match = defaultTagRE.exec(text))) {\n let index = match.index;\n if (index > lastIndex) {\n // 添加模板引擎之前/之后的内容\n tokens.push(JSON.stringify(text.slice(lastIndex, index)));\n }\n // 将模板中的变量添加进去\n tokens.push(`_s(${match[1].trim()})`);\n lastIndex = index + match[0].length;\n }\n if (lastIndex < text.length) {\n // 添加一般的文本\n tokens.push(JSON.stringify(text.slice(lastIndex)));\n }\n return `_v(${tokens.join(\"+\")})`;\n }\n }\n}\n// 将ast语法树生成render函数\nfunction codegen(ast) {\n let children = genChildren(ast.children);\n let code = `_c('${ast.tag}',${\n ast.attrs.length > 0 ? genProps(ast.attrs) : \"null\"\n }${ast.children.length ? `,${children}` : \"\"})`;\n return code;\n}\nexport function complieToFunction(template) {\n let ast = parseHTML(template);\n let code = codegen(ast);\n // 绑定this并利用Function生成函数\n code = `with(this){return ${code}}`;\n let render = new Function(code);\n return render;\n}\n","const isReservedTag = (tag) => {\n return [\n \"a\",\n \"div\",\n \"span\",\n \"ul\",\n \"li\",\n \"ol\",\n \"button\",\n \"input\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"p\",\n \"br\",\n ].includes(tag);\n};\nexport function createElementVNode(vm, tag, data, ...children) {\n if (data == null) {\n data = {};\n }\n let key = data.key;\n if (key) {\n delete data.key;\n }\n // 判断是否是原生标签\n if (isReservedTag(tag)) {\n return vnode(vm, tag, key, data, children);\n } else {\n // 创造一个组件的虚拟节点,包含组件的构造函数\n let Ctor = vm.$options.components[tag]; //组件的构造函数\n // Ctor是组件的定义,可能是配置对象(模板选项)或者是Sub(Vue的子类)\n //全局组件是构造函数,否则是对象\n return createComponentVNode(vm, tag, key, data, children, Ctor);\n // 调用完这个方法之后,vnode.componentInstance上\n }\n}\nfunction createComponentVNode(vm, tag, key, data, children, Ctor) {\n if (typeof Ctor == \"object\") {\n // 确保Ctor一定是构造函数\n Ctor = vm.$options._base.extend(Ctor);\n }\n data.hook = {\n // 用于创建真实节点的时候,如果是组件则调用此方法\n init(vnode) {\n // 保存组件的实例到虚拟节点上\n let instance = (vnode.componentInstance =\n new vnode.componentOptions.Ctor());\n instance.$mount();\n // 执行后instance上增加了$el\n },\n };\n return vnode(vm, tag, key, data, children, null, { Ctor });\n}\nexport function createTextVNode(vm, text) {\n return vnode(vm, undefined, undefined, undefined, undefined, text);\n}\n// ast是描述JS,css,等语言本身的情况的\n// 虚拟dom是描述dom节点的\nfunction vnode(vm, tag, key, data, children, text, componentOptions) {\n return {\n vm,\n tag,\n key,\n data,\n children,\n text,\n // 包含了组件的构造函数\n componentOptions,\n };\n}\nexport function isSameVnode(vnode1, vnode2) {\n return vnode1.tag === vnode2.tag && vnode1.key === vnode2.key;\n}\n","import { isSameVnode } from \"./index\";\nfunction createComponent(vnode) {\n let i = vnode.data;\n if ((i = i.hook) && (i = i.init)) {\n i(vnode); //使用init方法初始化组件,调用$mount()\n }\n if (vnode.componentInstance) {\n return true; //说明是组件\n }\n}\nexport function createElm(vnode) {\n let { tag, data, children, text } = vnode;\n if (typeof tag == \"string\") {\n // 创建真实节点需要知道是组件还是真实元素\n\n if (createComponent(vnode)) {\n // 这里的$el是在执行$mount后产生的虚拟节点对应的真实节点\n return vnode.componentInstance.$el;\n }\n // 将真实节点和虚拟节点进行对应,为后续diff算法做准备\n vnode.el = document.createElement(tag);\n patchProps(vnode.el, {}, data);\n children.forEach((child) => {\n vnode.el.appendChild(createElm(child));\n });\n } else {\n vnode.el = document.createTextNode(text);\n }\n return vnode.el;\n}\nexport function patchProps(el, oldProps = {}, props = {}) {\n // 老的属性中有,新的没有,要删除老的\n let oldStyles = oldProps.style || {};\n let newStyle = props.style;\n // 对于style\n for (let key in oldProps) {\n if (!newStyle[key]) {\n el.style[key] = \"\";\n }\n }\n // 对于一般属性\n for (let key in oldProps) {\n if (!props[key]) {\n el.removeAttribute(key);\n }\n }\n // 用新的覆盖掉老的\n for (let key in props) {\n if (key == \"style\") {\n for (let styleName in props.style) {\n el.style[styleName] = props.style[styleName];\n }\n } else {\n el.setAttribute(key, props[key]);\n }\n }\n}\nexport function patch(oldVNode, vnode) {\n if (!oldVNode) {\n // 没有el,表示是组件的挂载\n //注意这里要修改init中的挂载方法,没有el也可以挂载\n //vm.$el就是渲染的结果\n return createElm(vnode);\n }\n const isRealElement = oldVNode.nodeType;\n if (isRealElement) {\n // 获取真实元素\n const elm = oldVNode;\n // 拿到父元素\n const parentElm = elm.parentNode;\n let newElm = createElm(vnode);\n parentElm.insertBefore(newElm, elm.nextSibiling);\n parentElm.removeChild(elm);\n return newElm;\n } else {\n // diff算法\n return patchVnode(oldVNode, vnode);\n }\n}\n// 利用diff算法更新两个节点\nfunction patchVnode(oldVNode, vnode) {\n // 两个节点不是同一个节点,直接删除老的,换上新的(没有对比)\n\n // 两个节点是同一个节点,判断节点的tag和key,tag和key一样是同一个节点,此时去比较两个节点的属性是否有差异(复用老的节点,将差异的属性更新)\n // 节点比较完成后,比较两个节点的子节点\n // 如果不是同一节点,用新节点替换老节点\n if (!isSameVnode(oldVNode, vnode)) {\n // 用老节点的父亲进行替换\n //这里的el属性就是虚拟节点对应的真实节点\n let el = createElm(vnode);\n oldVNode.el.parentNode.replaceChild(el, oldVNode);\n return el;\n }\n // 如果是文本节点,就比对一下文本的内容\n let el = (vnode.el = oldVNode.el); //复用老节点的元素\n if (!oldVNode.tag) {\n // 文本的情况\n if (oldVNode.text !== vnode.text) {\n el.textContent = vnode.text;\n }\n }\n //是标签,需要比对标签的属性\n patchProps(el, oldVNode.data, vnode.data);\n // 比较子节点:\n // 1.一方有儿子,一方没儿子\n // 2.两方都有儿子\n let oldChildren = oldVNode.children || [];\n let newChildren = vnode.children || [];\n if (oldChildren.length > 0 && newChildren.length > 0) {\n // 完整的diff算法\n updateChild(el, oldChildren, newChildren);\n } else if (newChildren > 0) {\n // 老的没有新的有\n mountChildren(el, newChildren);\n } else if (oldChildren > 0) {\n // 新的没有老的有\n unmountChild(el, oldChildren);\n }\n return el;\n}\n\nfunction mountChildren(el, children) {\n for (let i = 0; i < children.length; i++) {\n let child = newChildren[i];\n el.appendChild(createElm(child));\n }\n}\n\nfunction unmountChild(el, children) {\n el.innerHTML = \"\";\n}\n\nfunction updateChild(el, oldChildren, newChildren) {\n // 为了增高性能,会有一些优化手段\n // vue2中采用双指针的方式比较两个节点\n let oldStartIndex = 0;\n let newStartIndex = 0;\n let oldEndIndex = oldChildren.length - 1;\n let newEndIndex = newChildren.length - 1;\n\n let oldStartVnode = oldChildren[0];\n let newStartVnode = newChildren[0];\n\n let oldEndVnode = oldChildren[oldEndIndex];\n let newEndVnode = newChildren[newEndIndex];\n function makeIndexByKey(children) {\n let map = {};\n children.forEach((child, index) => {\n map[child.key] = index;\n });\n return map;\n }\n let map = makeIndexByKey(oldChildren);\n while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {\n // 有一方的头指针大于尾部指针,则停止循环\n // 如果是相同节点,则递归比较子节点\n if (!oldStartVnode) {\n // 处理置空节点产生的undefind的问题\n oldStartVnode = oldChildren[++oldStartIndex];\n } else if (!oldEndVnode) {\n // 处理置空节点产生的undefind的问题\n oldEndVnode = oldChildren[--oldEndIndex];\n } else if (isSameVnode(oldStartVnode, newStartVnode)) {\n patchVnode(oldStartVnode, newStartVnode);\n // 指针移动\n oldStartVnode = oldChildren[++oldStartIndex];\n newStartVnode = newChildren[++newStartIndex];\n }\n // 当首个元素不同时反向比对\n else if (isSameVnode(oldEndVnode, newEndVnode)) {\n patchVnode(oldEndVnode, newEndVnode);\n oldEndVnode = oldChildren[--oldEndIndex];\n newEndVnode = newChildren[--newEndIndex];\n }\n // 交叉比对,优化reverse方法 abcd__>dabc,处理了倒叙和排序的情况\n else if (isSameVnode(oldEndVnode, newStartVnode)) {\n patchVnode(oldEndVnode, newStartVnode);\n // 将老的尾部移动到老的前面去(变为了新前对旧前)\n // insertBefore具有移动性,会将原来的元素移动走\n el.insertBefore(oldEndVnode.el, oldStartVnode.el);\n oldEndVnode = oldChildren[--oldEndIndex];\n newStartVnode = newChildren[++newStartIndex];\n } else if (isSameVnode(oldStartVnode, newEndVnode)) {\n patchVnode(oldStartVnode, newEndVnode);\n // 将老的尾部移动到老的前面去(变为了新前对旧前)\n // insertBefore具有移动性,会将原来的元素移动走\n el.insertBefore(oldStartVnode.el, oldEndVnode.el.nextSibiling);\n oldStartVnode = oldChildren[++oldStartIndex];\n newEndVnode = newChildren[--newEndIndex];\n } else {\n // 给动态列表添加key时,尽量避免使用索引,可能导致错误复用\n // 乱序比对:根据老的列表做一个映射关系,用新的逐个比对查找,找到移动,找不到添加,多出的删除\n // 如果拿到说明是要移动的索引\n let moveIndex = map[newStartVnode?.key];\n if (moveIndex !== undefined) {\n // 找到对应的虚拟节点进行复用\n let moveVnode = oldChildren[moveIndex];\n el.insertBefore(moveVnode.el, oldStartVnode.el);\n oldChildren[moveIndex] = undefined; //表示这个节点已经被移走了\n // 递归比较属性和子节点\n patchVnode(moveVnode, newStartVnode);\n } else {\n // 无法找到老节点\n el.insertBefore(createElm(newStartVnode), oldStartVnode.el);\n }\n newStartVnode = newChildren[++newStartIndex];\n }\n }\n\n // 多出元素删除,缺少元素添加\n // 相比于原有的数组有新增元素,尾部对新增元素进行添加\n if (newStartIndex <= newEndIndex) {\n for (let i = newStartIndex; i <= newEndIndex; i++) {\n let childEl = createElm(newChildren[i]);\n // 这里也有可能向前追加\n let anchor = newChildren[newEndIndex + 1]\n ? newChildren[newEndIndex + 1].el\n : null;\n el.insertBefore(childEl, anchor);\n // anchor为null时,则等价于appendChild\n }\n }\n // 相比于原有数组尾部减少元素,对被减少的元素进行删除\n if (oldStartIndex <= oldEndIndex) {\n for (let i = oldStartIndex; i <= oldEndIndex; i++) {\n if (oldChildren[i]) {\n let childEl = oldChildren[i].el;\n el.removeChild(childEl);\n }\n }\n }\n}\n","import { createElementVNode, createTextVNode } from \"./vdom/index\";\nimport Watcher from \"./observe/watcher\";\nimport { createElm, patch, patchProps } from \"./vdom/patch\";\nexport function initLifeCycle(Vue) {\n Vue.prototype._update = function (vnode) {\n // patch既有初始化功能,又有更新的功能\n const vm = this;\n const el = vm.$el;\n // 把组件第一次产生的虚拟节点保存到_vnode上\n const preVnode = vm._vnode;\n vm._vnode = vnode;\n if (preVnode) {\n // 之前渲染过\n vm.$el = patch(preVnode, vnode);\n } else {\n vm.$el = patch(el, vnode);\n }\n };\n Vue.prototype._render = function () {\n // 渲染时会去实例上取值\n const vm = this;\n return vm.$options.render.call(this); //转移后生产的 render方法\n };\n // 创造虚拟节点\n Vue.prototype._c = function () {\n return createElementVNode(this, ...arguments);\n };\n // 创建文本虚拟节点\n Vue.prototype._v = function () {\n return createTextVNode(this, ...arguments);\n };\n // 创建普通文字节点\n Vue.prototype._s = function (value) {\n if (typeof value !== \"object\") return value;\n return JSON.stringify(value);\n };\n}\nexport function mountComponent(vm, el) {\n vm.$el = el;\n const updateComponent = () => {\n vm._update(vm._render()); //vm.$options.render,返回虚拟节点\n };\n // 注意,子组件挂载时也会调用这个方法,因此每个子组件也都会对应一个Watcher\n // 1.调用render方法,产生虚拟dom\n const watcher = new Watcher(vm, updateComponent, true);\n // 2.根据虚拟dom产生真实dom\n\n // 3.插入到el元素中\n}\n\n// 将模板转化为ast模板语法树,ast转化为render函数,后续每次数据更新只执行render函数(无需再转化ast)\n// render函数会产生虚拟节点,根据创造的虚拟节点创造真实Dom\n\nexport function callHook(vm, hook) {\n const handlers = vm.$options[hook];\n if (handlers) {\n handlers.forEach((handler) => {\n handler.call(vm);\n });\n }\n}\n","const strats = {};\nconst LIFECYCLE = [\n \"beforeCreate\",\n \"created\",\n \"mounted\",\n \"beforeUpdate\",\n \"updated\",\n \"beforeDestroy\",\n \"destroy\",\n];\nLIFECYCLE.forEach((hook) => {\n strats[hook] = function (p, c) {\n if (c) {\n if (p) {\n // 第一次之后,p必定为一个数组\n return p.concat(c);\n } else {\n // 第一次合并p为{}\n return [c];\n }\n } else {\n // 如果儿子没有,直接返回父亲\n // c没有的情况下,p可能有,也可能为undefined\n return p;\n }\n };\n});\nstrats.components = function (parentVal, childVal) {\n const res = Object.create(parentVal);\n if (childVal) {\n for (let key in childVal) {\n // 返回的是构造的对象,可以返回父亲原型上的属性,并将儿子的属性拷贝到自己身上\n res[key] = childVal[key];\n }\n }\n return res;\n};\nexport function mergeOptions(parent, child) {\n const options = {};\n for (let key in parent) {\n mergeField(key);\n }\n for (let key in child) {\n if (!parent.hasOwnProperty(key)) {\n mergeField(key);\n }\n }\n function mergeField(key) {\n // 策略模式减少if-else\n if (strats[key]) {\n options[key] = strats[key](parent[key], child[key]);\n } else {\n // 不在策略中则优先采用儿子的,再采用父亲\n options[key] = child[key] || parent[key];\n }\n }\n return options;\n}\n","// 给Vue增加初始化方法\nimport { initState } from \"./state\";\nimport { complieToFunction } from \"./compiler/index\";\nimport { mountComponent } from \"./lifecycle\";\nimport { mergeOptions } from \"./utils\";\nimport { callHook } from \"./lifecycle\";\nexport function initMixin(Vue) {\n Vue.prototype._init = function (options) {\n const vm = this;\n // 将用户传入的选项和全局选项进行合并\n vm.$options = mergeOptions(this.constructor.options, options);\n console.log(vm.$options);\n callHook(vm, \"beforeCreated\");\n initState(vm);\n callHook(vm, \"created\");\n if (options.el) {\n vm.$mount(options.el);\n }\n };\n Vue.prototype.$mount = function (el) {\n const vm = this;\n el = document.querySelector(el);\n let opts = vm.$options;\n // 当没有render函数时\n if (!opts?.render) {\n let template = null;\n // 没有模板但写了el\n if (!opts.template && opts.el) {\n template = el.outerHTML;\n // 存在模板或不存在模板和el\n } else {\n // 存在模板\n if (opts.template) {\n template = opts.template;\n } else {\n // 既没有模板也没有el\n template = \"
\";\n }\n }\n //拿到模板\n // 获取优先级:render=>temple=>el\n if (template) {\n const render = complieToFunction(template);\n opts.render = render;\n }\n }\n mountComponent(vm, el);\n };\n}\n// script标签引入的vue,编译过程在浏览器\n// runtime是不包含编译的,编译时通过loader进行转译.vue文件,用runtime不能使用template(在mian.js中,.vue文件有loader转译,因此不影响)\n// 包含main.js中模板编译的版本是runtime-with-compiler\n","import { mergeOptions } from \"./utils\";\nexport function initGlobalAPI(Vue) {\n Vue.options = {\n _base: Vue,\n };\n Vue.mixin = function (mixin) {\n // 期望将用户的选项和全局的options进行合并\n // Vue的混入本质是一个订阅发布者模式\n this.options = mergeOptions(Vue.options, mixin);\n return this;\n };\n // 可以手动改创造组件进行挂载\n Vue.extend = function (options) {\n // 根据用户的参数,返回一个构造函数\n // 最终使用一个组件,就是new一个实例\n function Sub(options = {}) {\n this._init(options); // 默认对子类进行初始化操作\n }\n Sub.prototype = Object.create(Vue.prototype);\n Sub.prototype.constructor = Sub;\n // 希望将用户传递的参数和全局的Vue.options合并,使形成类似原型链的查找方式,出现重名优先查找自己\n Sub.options = mergeOptions(Vue.options, options); //保存用户传递的选项\n return Sub;\n // 子组件挂载时也会产生一个watcher\n };\n Vue.options.components = {};\n Vue.component = function (id, definition) {\n // 如果definition已经是一个函数了,说明用户自己调用了vue.extend\n definition =\n typeof definition == \"function\" ? definition : Vue.extend(definition);\n Vue.options.components[id] = definition;\n };\n}\n","import { initMixin } from \"./init\";\nimport { initLifeCycle } from \"./lifecycle\";\nimport { initStateMixin } from \"./state\";\nimport { complieToFunction } from \"./compiler/index\";\nimport { createElm, patch } from \"./vdom/patch\";\nimport { initGlobalAPI } from \"./gloablAPI\";\nfunction Vue(options) {\n this._init(options);\n}\n// 扩展了init方法\ninitMixin(Vue);\n// 提供了_update()和_render两个方法\ninitLifeCycle(Vue);\n// 实现了$nextTick和$watch\ninitStateMixin(Vue);\n// 实现全局API\ninitGlobalAPI(Vue);\n// diff算法是一个平级比较的过程,父亲不能跟儿子进行比对\nexport default Vue;\n"],"names":["id","Dep","subs","target","addDep","watcher","push","forEach","update","stack","pushTarget","popTarget","pop","length","oldArrayProto","Array","prototype","newArrayProto","Object","create","methods","method","args","result","call","ob","__ob__","inserted","slice","observeArray","dep","notify","Observe","data","defineProperty","value","enumerable","isArray","__proto__","walk","keys","key","defineReactive","item","observe","dependArray","i","depend","childOb","get","set","newValue","Watcher","vm","exprOrFn","options","cb","renderWatcher","getter","deps","depsId","Set","lazy","dirty","user","undefined","queueWatcher","has","add","addSub","oldValue","queue","pending","flushSchedulerQueue","flushQueue","q","run","timerFunc","callbacks","waiting","flushCallbacks","cbs","Promise","fn","resolve","then","MutationObserver","textNode","document","createElement","characterData","textContent","setImmediate","setTimeout","nextTick","initState","opts","$options","initData","computed","initComputed","watch","initWatch","handler","createWatcher","$watch","proxy","_data","watchers","_computedWatchers","userDef","defineComputed","setter","createComputedGatter","evalute","initStateMixin","Vue","$nextTick","ncname","qnameCapture","startTagOpen","RegExp","endTag","attribute","startTagClose","parseHTML","html","ELEMENT_TYPE","TEXT_TYPE","currentParent","root","createASTElement","tag","attrs","type","children","parent","advance","n","substring","start","node","end","char","text","replace","parseStartTag","match","tagName","attr","name","textEnd","indexOf","startTagMatch","endTagMatch","defaultTagRE","genProps","str","obj","split","JSON","stringify","genChildren","map","child","gen","join","codegen","test","tokens","lastIndex","exec","index","trim","ast","code","complieToFunction","template","render","Function","isReservedTag","includes","createElementVNode","vnode","Ctor","components","createComponentVNode","_base","extend","hook","init","instance","componentInstance","componentOptions","$mount","createTextVNode","isSameVnode","vnode1","vnode2","createComponent","createElm","$el","el","patchProps","appendChild","createTextNode","oldProps","props","style","newStyle","removeAttribute","styleName","setAttribute","patch","oldVNode","isRealElement","nodeType","elm","parentElm","parentNode","newElm","insertBefore","nextSibiling","removeChild","patchVnode","replaceChild","oldChildren","newChildren","updateChild","mountChildren","unmountChild","innerHTML","oldStartIndex","newStartIndex","oldEndIndex","newEndIndex","oldStartVnode","newStartVnode","oldEndVnode","newEndVnode","makeIndexByKey","moveIndex","moveVnode","childEl","anchor","initLifeCycle","_update","preVnode","_vnode","_render","_c","arguments","_v","_s","mountComponent","updateComponent","callHook","handlers","strats","LIFECYCLE","p","c","concat","parentVal","childVal","res","mergeOptions","mergeField","hasOwnProperty","initMixin","_init","constructor","console","log","querySelector","outerHTML","initGlobalAPI","mixin","Sub","component","definition"],"mappings":"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"} --------------------------------------------------------------------------------