├── .gitignore ├── README.md ├── build.sh ├── docs ├── .vuepress │ ├── config.js │ └── public │ │ ├── assets │ │ ├── complie │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ └── 7.png │ │ ├── lifecycle │ │ │ └── 1.png │ │ ├── reactive │ │ │ ├── 1.png │ │ │ └── 2.png │ │ ├── start │ │ │ └── 1.png │ │ └── virtualDOM │ │ │ ├── 1.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 13.png │ │ │ ├── 14.png │ │ │ ├── 15.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ └── 9.png │ │ ├── icons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── msapplication-icon-144x144.png │ │ ├── mstile-150x150.png │ │ └── safari-pinned-tab.svg │ │ ├── logo.png │ │ └── manifest.json ├── README.md ├── complie │ ├── HTMLParse.md │ ├── codegen.md │ ├── index.md │ ├── optimize.md │ ├── parse.md │ ├── summary.md │ └── textParse.md ├── lifecycle │ ├── index.md │ ├── initEvents.md │ ├── initInjections.md │ ├── initLifecycle.md │ └── newVue.md ├── reactive │ ├── array.md │ ├── index.md │ └── object.md ├── start │ └── index.md └── virtualDOM │ ├── index.md │ ├── optimizeUpdataChildren.md │ ├── patch.md │ └── updataChildren.md ├── package-lock.json ├── package.json └── 带注释的Vue源码 └── vue ├── dist ├── README.md ├── vue.common.js ├── vue.esm.browser.js ├── vue.esm.js ├── vue.js ├── vue.min.js ├── vue.runtime.common.js ├── vue.runtime.esm.js ├── vue.runtime.js └── vue.runtime.min.js ├── flow ├── compiler.js ├── component.js ├── global-api.js ├── modules.js ├── options.js ├── ssr.js ├── vnode.js └── weex.js ├── package.json ├── scripts ├── alias.js ├── build.js ├── config.js ├── gen-release-note.js ├── get-weex-version.js ├── git-hooks │ ├── commit-msg │ └── pre-commit ├── release-weex.sh ├── release.sh └── verify-commit-msg.js ├── src ├── compiler │ ├── codegen │ │ ├── events.js │ │ └── index.js │ ├── create-compiler.js │ ├── directives │ │ ├── bind.js │ │ ├── index.js │ │ ├── model.js │ │ └── on.js │ ├── error-detector.js │ ├── helpers.js │ ├── index.js │ ├── optimizer.js │ ├── parser │ │ ├── entity-decoder.js │ │ ├── filter-parser.js │ │ ├── html-parser.js │ │ ├── index.js │ │ └── text-parser.js │ └── to-function.js ├── core │ ├── components │ │ ├── index.js │ │ └── keep-alive.js │ ├── config.js │ ├── global-api │ │ ├── assets.js │ │ ├── extend.js │ │ ├── index.js │ │ ├── mixin.js │ │ └── use.js │ ├── index.js │ ├── instance │ │ ├── events.js │ │ ├── index.js │ │ ├── init.js │ │ ├── inject.js │ │ ├── lifecycle.js │ │ ├── proxy.js │ │ ├── render-helpers │ │ │ ├── bind-object-listeners.js │ │ │ ├── bind-object-props.js │ │ │ ├── check-keycodes.js │ │ │ ├── index.js │ │ │ ├── render-list.js │ │ │ ├── render-slot.js │ │ │ ├── render-static.js │ │ │ ├── resolve-filter.js │ │ │ └── resolve-slots.js │ │ ├── render.js │ │ └── state.js │ ├── observer │ │ ├── array.js │ │ ├── dep.js │ │ ├── index.js │ │ ├── scheduler.js │ │ ├── traverse.js │ │ └── watcher.js │ ├── util │ │ ├── debug.js │ │ ├── env.js │ │ ├── error.js │ │ ├── index.js │ │ ├── lang.js │ │ ├── next-tick.js │ │ ├── options.js │ │ ├── perf.js │ │ └── props.js │ └── vdom │ │ ├── create-component.js │ │ ├── create-element.js │ │ ├── create-functional-component.js │ │ ├── helpers │ │ ├── extract-props.js │ │ ├── get-first-component-child.js │ │ ├── index.js │ │ ├── is-async-placeholder.js │ │ ├── merge-hook.js │ │ ├── normalize-children.js │ │ ├── resolve-async-component.js │ │ └── update-listeners.js │ │ ├── modules │ │ ├── directives.js │ │ ├── index.js │ │ └── ref.js │ │ ├── patch.js │ │ └── vnode.js ├── platforms │ ├── web │ │ ├── compiler │ │ │ ├── directives │ │ │ │ ├── html.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── text.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── class.js │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── style.js │ │ │ ├── options.js │ │ │ └── util.js │ │ ├── entry-compiler.js │ │ ├── entry-runtime-with-compiler.js │ │ ├── entry-runtime.js │ │ ├── entry-server-basic-renderer.js │ │ ├── entry-server-renderer.js │ │ ├── runtime │ │ │ ├── class-util.js │ │ │ ├── components │ │ │ │ ├── index.js │ │ │ │ ├── transition-group.js │ │ │ │ └── transition.js │ │ │ ├── directives │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── show.js │ │ │ ├── index.js │ │ │ ├── modules │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── dom-props.js │ │ │ │ ├── events.js │ │ │ │ ├── index.js │ │ │ │ ├── style.js │ │ │ │ └── transition.js │ │ │ ├── node-ops.js │ │ │ ├── patch.js │ │ │ └── transition-util.js │ │ ├── server │ │ │ ├── compiler.js │ │ │ ├── directives │ │ │ │ ├── index.js │ │ │ │ ├── model.js │ │ │ │ └── show.js │ │ │ ├── modules │ │ │ │ ├── attrs.js │ │ │ │ ├── class.js │ │ │ │ ├── dom-props.js │ │ │ │ ├── index.js │ │ │ │ └── style.js │ │ │ └── util.js │ │ └── util │ │ │ ├── attrs.js │ │ │ ├── class.js │ │ │ ├── compat.js │ │ │ ├── element.js │ │ │ ├── index.js │ │ │ └── style.js │ └── weex │ │ ├── compiler │ │ ├── directives │ │ │ ├── index.js │ │ │ └── model.js │ │ ├── index.js │ │ └── modules │ │ │ ├── append.js │ │ │ ├── class.js │ │ │ ├── index.js │ │ │ ├── props.js │ │ │ ├── recycle-list │ │ │ ├── component-root.js │ │ │ ├── component.js │ │ │ ├── index.js │ │ │ ├── recycle-list.js │ │ │ ├── text.js │ │ │ ├── v-bind.js │ │ │ ├── v-for.js │ │ │ ├── v-if.js │ │ │ ├── v-on.js │ │ │ └── v-once.js │ │ │ └── style.js │ │ ├── entry-compiler.js │ │ ├── entry-framework.js │ │ ├── entry-runtime-factory.js │ │ ├── runtime │ │ ├── components │ │ │ ├── index.js │ │ │ ├── richtext.js │ │ │ ├── transition-group.js │ │ │ └── transition.js │ │ ├── directives │ │ │ └── index.js │ │ ├── index.js │ │ ├── modules │ │ │ ├── attrs.js │ │ │ ├── class.js │ │ │ ├── events.js │ │ │ ├── index.js │ │ │ ├── style.js │ │ │ └── transition.js │ │ ├── node-ops.js │ │ ├── patch.js │ │ ├── recycle-list │ │ │ ├── render-component-template.js │ │ │ └── virtual-component.js │ │ └── text-node.js │ │ └── util │ │ ├── element.js │ │ ├── index.js │ │ └── parser.js ├── server │ ├── bundle-renderer │ │ ├── create-bundle-renderer.js │ │ ├── create-bundle-runner.js │ │ └── source-map-support.js │ ├── create-basic-renderer.js │ ├── create-renderer.js │ ├── optimizing-compiler │ │ ├── codegen.js │ │ ├── index.js │ │ ├── modules.js │ │ ├── optimizer.js │ │ └── runtime-helpers.js │ ├── render-context.js │ ├── render-stream.js │ ├── render.js │ ├── template-renderer │ │ ├── create-async-file-mapper.js │ │ ├── index.js │ │ ├── parse-template.js │ │ └── template-stream.js │ ├── util.js │ ├── webpack-plugin │ │ ├── client.js │ │ ├── server.js │ │ └── util.js │ └── write.js ├── sfc │ └── parser.js └── shared │ ├── constants.js │ └── util.js └── test ├── e2e ├── .eslintrc ├── nightwatch.config.js ├── runner.js └── specs │ ├── async-edge-cases.html │ ├── async-edge-cases.js │ ├── basic-ssr.html │ ├── basic-ssr.js │ ├── commits.js │ ├── grid.js │ ├── markdown.js │ ├── modal.js │ ├── select2.js │ ├── svg.js │ ├── todomvc.js │ └── tree.js ├── helpers ├── .eslintrc ├── classlist.js ├── test-object-option.js ├── to-equal.js ├── to-have-been-warned.js ├── trigger-event.js ├── vdom.js └── wait-for-update.js ├── ssr ├── .eslintrc ├── async-loader.js ├── compile-with-webpack.js ├── fixtures │ ├── app.js │ ├── async-bar.js │ ├── async-foo.js │ ├── cache.js │ ├── error.js │ ├── nested-cache.js │ ├── promise-rejection.js │ ├── split.js │ ├── test.css │ ├── test.png │ └── test.woff2 ├── jasmine.json ├── ssr-basic-renderer.spec.js ├── ssr-bundle-render.spec.js ├── ssr-stream.spec.js ├── ssr-string.spec.js └── ssr-template.spec.js ├── unit ├── .eslintrc ├── features │ ├── component │ │ ├── component-async.spec.js │ │ ├── component-keep-alive.spec.js │ │ ├── component-scoped-slot.spec.js │ │ ├── component-slot.spec.js │ │ └── component.spec.js │ ├── debug.spec.js │ ├── directives │ │ ├── bind.spec.js │ │ ├── class.spec.js │ │ ├── cloak.spec.js │ │ ├── for.spec.js │ │ ├── html.spec.js │ │ ├── if.spec.js │ │ ├── model-checkbox.spec.js │ │ ├── model-component.spec.js │ │ ├── model-dynamic.spec.js │ │ ├── model-file.spec.js │ │ ├── model-parse.spec.js │ │ ├── model-radio.spec.js │ │ ├── model-select.spec.js │ │ ├── model-text.spec.js │ │ ├── on.spec.js │ │ ├── once.spec.js │ │ ├── pre.spec.js │ │ ├── show.spec.js │ │ ├── static-style-parser.spec.js │ │ ├── style.spec.js │ │ └── text.spec.js │ ├── error-handling.spec.js │ ├── filter │ │ └── filter.spec.js │ ├── global-api │ │ ├── assets.spec.js │ │ ├── compile.spec.js │ │ ├── config.spec.js │ │ ├── extend.spec.js │ │ ├── mixin.spec.js │ │ ├── set-delete.spec.js │ │ └── use.spec.js │ ├── instance │ │ ├── init.spec.js │ │ ├── methods-data.spec.js │ │ ├── methods-events.spec.js │ │ ├── methods-lifecycle.spec.js │ │ ├── properties.spec.js │ │ └── render-proxy.spec.js │ ├── options │ │ ├── _scopeId.spec.js │ │ ├── comments.spec.js │ │ ├── components.spec.js │ │ ├── computed.spec.js │ │ ├── data.spec.js │ │ ├── delimiters.spec.js │ │ ├── directives.spec.js │ │ ├── el.spec.js │ │ ├── errorCaptured.spec.js │ │ ├── extends.spec.js │ │ ├── functional.spec.js │ │ ├── inheritAttrs.spec.js │ │ ├── inject.spec.js │ │ ├── lifecycle.spec.js │ │ ├── methods.spec.js │ │ ├── mixins.spec.js │ │ ├── name.spec.js │ │ ├── parent.spec.js │ │ ├── props.spec.js │ │ ├── propsData.spec.js │ │ ├── render.spec.js │ │ ├── renderError.spec.js │ │ ├── template.spec.js │ │ └── watch.spec.js │ ├── ref.spec.js │ └── transition │ │ ├── inject-styles.js │ │ ├── transition-group.spec.js │ │ ├── transition-mode.spec.js │ │ └── transition.spec.js ├── index.js ├── karma.base.config.js ├── karma.cover.config.js ├── karma.dev.config.js ├── karma.sauce.config.js ├── karma.unit.config.js └── modules │ ├── compiler │ ├── codegen.spec.js │ ├── compiler-options.spec.js │ ├── optimizer.spec.js │ └── parser.spec.js │ ├── observer │ ├── dep.spec.js │ ├── observer.spec.js │ ├── scheduler.spec.js │ └── watcher.spec.js │ ├── server-compiler │ └── optimizer.spec.js │ ├── sfc │ └── sfc-parser.spec.js │ ├── util │ └── next-tick.spec.js │ └── vdom │ ├── create-component.spec.js │ ├── create-element.spec.js │ ├── modules │ ├── attrs.spec.js │ ├── class.spec.js │ ├── directive.spec.js │ ├── dom-props.spec.js │ ├── events.spec.js │ └── style.spec.js │ └── patch │ ├── children.spec.js │ ├── edge-cases.spec.js │ ├── element.spec.js │ ├── hooks.spec.js │ └── hydration.spec.js └── weex ├── .eslintrc ├── cases ├── cases.spec.js ├── event │ ├── click.after.vdom.js │ ├── click.before.vdom.js │ └── click.vue ├── recycle-list │ ├── attrs.vdom.js │ ├── attrs.vue │ ├── classname.vdom.js │ ├── classname.vue │ ├── components │ │ ├── banner.vue │ │ ├── counter.vue │ │ ├── editor.vue │ │ ├── footer.vue │ │ ├── lifecycle.vue │ │ ├── poster.vue │ │ ├── stateful-lifecycle.vdom.js │ │ ├── stateful-lifecycle.vue │ │ ├── stateful-v-model.vdom.js │ │ ├── stateful-v-model.vue │ │ ├── stateful.vdom.js │ │ ├── stateful.vue │ │ ├── stateless-multi-components.vdom.js │ │ ├── stateless-multi-components.vue │ │ ├── stateless-with-props.vdom.js │ │ ├── stateless-with-props.vue │ │ ├── stateless.vdom.js │ │ └── stateless.vue │ ├── inline-style.vdom.js │ ├── inline-style.vue │ ├── text-node.vdom.js │ ├── text-node.vue │ ├── v-else-if.vdom.js │ ├── v-else-if.vue │ ├── v-else.vdom.js │ ├── v-else.vue │ ├── v-for-iterator.vdom.js │ ├── v-for-iterator.vue │ ├── v-for.vdom.js │ ├── v-for.vue │ ├── v-if.vdom.js │ ├── v-if.vue │ ├── v-on-inline.vdom.js │ ├── v-on-inline.vue │ ├── v-on.vdom.js │ ├── v-on.vue │ ├── v-once.vdom.js │ └── v-once.vue └── render │ ├── sample.vdom.js │ └── sample.vue ├── compiler ├── append.spec.js ├── class.spec.js ├── compile.spec.js ├── parser.spec.js ├── props.spec.js ├── style.spec.js └── v-model.spec.js ├── helpers └── index.js ├── jasmine.json └── runtime ├── attrs.spec.js ├── class.spec.js ├── components └── richtext.spec.js ├── events.spec.js ├── framework.spec.js ├── node.spec.js └── style.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | docs/.vuepress/dist/ 3 | dist 4 | .vscode -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | npm run build 5 | 6 | cd dist 7 | 8 | git init 9 | git add -A 10 | git commit -m 'deploy' 11 | 12 | git push -f git@github.com:NLRX-WJC/Learn-Vue-Source-Code.git master:gh-pages 13 | 14 | cd - -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/3.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/4.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/5.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/6.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/complie/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/complie/7.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/lifecycle/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/lifecycle/1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/reactive/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/reactive/1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/reactive/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/reactive/2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/start/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/start/1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/1.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/10.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/11.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/12.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/13.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/14.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/15.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/2.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/3.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/4.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/5.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/6.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/7.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/8.png -------------------------------------------------------------------------------- /docs/.vuepress/public/assets/virtualDOM/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/assets/virtualDOM/9.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/icons/mstile-150x150.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/docs/.vuepress/public/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LearnVueSourceCode", 3 | "short_name": "LearnVueSourceCode", 4 | "icons": [ 5 | { 6 | "src": "/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/Learn-Vue-Source-Code/", 17 | "display": "standalone", 18 | "background_color": "#fff", 19 | "theme_color": "#3eaf7c" 20 | } 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /logo.png 4 | heroText: 逐行剖析 Vue.js 源码 5 | tagline: 九大模块,逐个击破 6 | actionText: 开始学习 7 | actionLink: /start/ 8 | features: 9 | - title: 变化侦测 10 | details: 学习 Vue中如何实现数据的响应式系统,从而达到数据驱动视图。 11 | - title: 虚拟DOM 12 | details: 学习什么是虚拟DOM,以及 Vue 中的 DOM-Diff 原理. 13 | - title: 模板编译 14 | details: 学习 Vue 内部是怎么把 template 模板编译成虚拟DOM,从而渲染出真实DOM。 15 | - title: 实例方法 16 | details: 学习 Vue 中所有实例方法(即所有以$开头的方法)的实现原理。 17 | - title: 全局API 18 | details: 学习 Vue 中所有全局 API 的实现原理。 19 | - title: 生命周期 20 | details: 学习 Vue 中组件的生命周期实现原理。 21 | - title: 指令 22 | details: 学习 Vue 中所有指令的实现原理。 23 | - title: 过滤器 24 | details: 学习 Vue 中所有过滤器的实现原理。 25 | - title: 内置组件 26 | details: 学习 Vue 中内置组件的实现原理。 27 | 28 | footer: MIT Licensed | Copyright © 2019-present 难凉热血 29 | --- -------------------------------------------------------------------------------- /docs/lifecycle/index.md: -------------------------------------------------------------------------------- 1 | ## 1. 前言 2 | 3 | 在`Vue`中,每个`Vue`实例从被创建出来到最终被销毁都会经历一个过程,就像人一样,从出生到死亡。在这一过程里会发生许许多多的事,例如设置数据监听,编译模板,组件挂载等。在`Vue`中,把`Vue`实例从被创建出来到最终被销毁的这一过程称为`Vue`实例的生命周期,同时,在`Vue`实例生命周期的不同阶段`Vue`还提供了不同的钩子函数,以方便用户在不同的生命周期阶段做一些额外的事情。那么,接下来的几篇文章我们就从源码角度深入剖析一下一个`Vue`实例在从生到死的生命周期里到底都经历了些什么,每个阶段都做了哪些事情。 4 | 5 | ## 2. 生命周期流程图 6 | 7 | 下图是`Vue`官网给出的`Vue`实例的生命周期流程图,如下: 8 | 9 | ![](~@/lifecycle/1.png) 10 | 11 | 从图中我们可以看到,`Vue`实例的生命周期大致可分为4个阶段: 12 | 13 | - 初始化阶段:为`Vue`实例上初始化一些属性,事件以及响应式数据; 14 | - 模板编译阶段:将模板编译成渲染函数; 15 | - 挂载阶段:将实例挂载到指定的`DOM`上,即将模板渲染到真实`DOM`中; 16 | - 卸载阶段:将实例自身从父组件中删除,并取消依赖追踪及事件监听器; 17 | 18 | 19 | 20 | ## 3. 总结 21 | 22 | 本篇文章时生命周期篇的开篇综述,借用`Vue`官网的生命周期流程图介绍了一个`Vue`实例的生命周期大致可分为四个阶段,分别时初始化阶段、模板编译阶段、挂载阶段、卸载阶段。接下来的几篇文章我们就从这个流程图为基础,自上到下,从每个阶段入手,深入分析在每个阶段里都干了些什么。 23 | -------------------------------------------------------------------------------- /docs/reactive/index.md: -------------------------------------------------------------------------------- 1 | 2 | ## 1. 前言 3 | 4 | 众所周知,`Vue`最大的特点之一就是数据驱动视图,那么什么是数据驱动视图呢?在这里,我们可以把数据理解为状态,而视图就是用户可直观看到页面。页面不可能是一成不变的,它应该是动态变化的,而它的变化也不应该是无迹可寻的,它或者是由用户操作引起的,亦或者是由后端数据变化引起的,不管它是因为什么引起的,我们统称为它的状态变了,它由前一个状态变到了后一个状态,页面也就应该随之而变化,所以我们就可以得到如下一个公式: 5 | 6 | **UI = render(state)** 7 | 8 | 上述公式中:状态`state`是输入,页面`UI`输出,状态输入一旦变化了,页面输出也随之而变化。我们把这种特性称之为数据驱动视图。 9 | 10 | OK,有了基本概念以后,我们再把上述公式拆成三部分:`state`、`render()`以及`UI`。我们知道`state`和`UI`都是用户定的,而不变的是这个`render()`。所以`Vue`就扮演了`render()`这个角色,当`Vue`发现`state`变化之后,经过一系列加工,最终将变化反应在`UI`上。 11 | 12 | 那么第一个问题来了,`Vue`怎么知道`state`变化了呢? 13 | 14 | ## 2. 什么是变化侦测 15 | 16 | 那`Vue`是怎么知道`state`变化了呢?换句话说,数据变化了是怎么通知给`Vue`呢?那么,这就引出了`Vue`中的变化侦测。 17 | 18 | 变化侦测就是追踪状态,亦或者说是数据的变化,一旦发生了变化,就要去更新视图。 19 | 20 | 变化侦测可不是个新名词,它在目前的前端三大框架中均有涉及。在`Angular`中是通过脏值检查流程来实现变化侦测;在`React`是通过对比虚拟`DOM`来实现变化侦测,而在`Vue`中也有自己的一套变化侦测实现机制。 21 | 22 | 那么,接下来我们就通过阅读源码来学习一下`Vue`是怎么实现自己的对数据变化进行侦测的机制。 23 | 24 | ## 3. 总结 25 | 26 | 首先,我们知道了什么是数据驱动视图。数据驱动视图简单来说就是数据变化引起视图变化,那么第一步就是先要知道数据什么时候发生变化,也就是说对数据的变化要进行侦测。 27 | 28 | 其次,数据的变化侦测在三大框架中均有涉及,不同的框架有着自己的一套侦测机制。 29 | 30 | 最后,我们从源码触发,学习在`Vue`中是如何对数据进行变化侦测的。 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Learn-Vue-Source-Code", 3 | "version": "1.0.0", 4 | "description": "", 5 | "directories": { 6 | "doc": "doc" 7 | }, 8 | "scripts": { 9 | "dev": "vuepress dev docs", 10 | "build": "vuepress build docs", 11 | "deploy": "sh build.sh" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/NLRX-WJC/Learn-Vue-Source-Code.git" 16 | }, 17 | "keywords": [], 18 | "author": "NLRX", 19 | "license": "ISC", 20 | "devDependencies": { 21 | "vuepress": "^1.2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/flow/global-api.js: -------------------------------------------------------------------------------- 1 | declare interface GlobalAPI { 2 | cid: number; 3 | options: Object; 4 | config: Config; 5 | util: Object; 6 | 7 | extend: (options: Object) => Function; 8 | set: (target: Object | Array, key: string | number, value: T) => T; 9 | delete: (target: Object| Array, key: string | number) => void; 10 | nextTick: (fn: Function, context?: Object) => void | Promise<*>; 11 | use: (plugin: Function | Object) => void; 12 | mixin: (mixin: Object) => void; 13 | compile: (template: string) => { render: Function, staticRenderFns: Array }; 14 | 15 | directive: (id: string, def?: Function | Object) => Function | Object | void; 16 | component: (id: string, def?: Class | Object) => Class; 17 | filter: (id: string, def?: Function) => Function | void; 18 | 19 | // allow dynamic method registration 20 | [key: string]: any 21 | }; 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/flow/modules.js: -------------------------------------------------------------------------------- 1 | declare module 'he' { 2 | declare function escape(html: string): string; 3 | declare function decode(html: string): string; 4 | } 5 | 6 | declare module 'source-map' { 7 | declare class SourceMapGenerator { 8 | setSourceContent(filename: string, content: string): void; 9 | addMapping(mapping: Object): void; 10 | toString(): string; 11 | } 12 | declare class SourceMapConsumer { 13 | constructor (map: Object): void; 14 | originalPositionFor(position: { line: number; column: number; }): { 15 | source: ?string; 16 | line: ?number; 17 | column: ?number; 18 | }; 19 | } 20 | } 21 | 22 | declare module 'lru-cache' { 23 | declare var exports: { 24 | (): any 25 | } 26 | } 27 | 28 | declare module 'de-indent' { 29 | declare var exports: { 30 | (input: string): string 31 | } 32 | } 33 | 34 | declare module 'serialize-javascript' { 35 | declare var exports: { 36 | (input: string, options: { isJSON: boolean }): string 37 | } 38 | } 39 | 40 | declare module 'lodash.template' { 41 | declare var exports: { 42 | (input: string, options: { interpolate: RegExp, escape: RegExp }): Function 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/flow/ssr.js: -------------------------------------------------------------------------------- 1 | declare type ComponentWithCacheContext = { 2 | type: 'ComponentWithCache'; 3 | bufferIndex: number; 4 | buffer: Array; 5 | key: string; 6 | }; 7 | 8 | declare type ElementContext = { 9 | type: 'Element'; 10 | children: Array; 11 | rendered: number; 12 | endTag: string; 13 | total: number; 14 | }; 15 | 16 | declare type ComponentContext = { 17 | type: 'Component'; 18 | prevActive: Component; 19 | }; 20 | 21 | declare type RenderState = ComponentContext | ComponentWithCacheContext | ElementContext; 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/alias.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const resolve = p => path.resolve(__dirname, '../', p) 4 | 5 | module.exports = { 6 | vue: resolve('src/platforms/web/entry-runtime-with-compiler'), 7 | compiler: resolve('src/compiler'), 8 | core: resolve('src/core'), 9 | shared: resolve('src/shared'), 10 | web: resolve('src/platforms/web'), 11 | weex: resolve('src/platforms/weex'), 12 | server: resolve('src/server'), 13 | entries: resolve('src/entries'), 14 | sfc: resolve('src/sfc') 15 | } 16 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/gen-release-note.js: -------------------------------------------------------------------------------- 1 | const version = process.argv[2] || process.env.VERSION 2 | const cc = require('conventional-changelog') 3 | const file = `./RELEASE_NOTE${version ? `_${version}` : ``}.md` 4 | const fileStream = require('fs').createWriteStream(file) 5 | 6 | cc({ 7 | preset: 'angular', 8 | pkg: { 9 | transform (pkg) { 10 | pkg.version = `v${version}` 11 | return pkg 12 | } 13 | } 14 | }).pipe(fileStream).on('close', () => { 15 | console.log(`Generated release note at ${file}`) 16 | }) 17 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/get-weex-version.js: -------------------------------------------------------------------------------- 1 | var coreVersion = require('../package.json').version 2 | var weexVersion = require('../packages/weex-vue-framework/package.json').version 3 | var weexBaseVersion = weexVersion.match(/^[\d.]+/)[0] 4 | var weexSubVersion = Number(weexVersion.match(/-weex\.(\d+)$/)[1]) 5 | 6 | if (weexBaseVersion === coreVersion) { 7 | // same core version, increment sub version 8 | weexSubVersion++ 9 | } else { 10 | // new core version, reset sub version 11 | weexBaseVersion = coreVersion 12 | weexSubVersion = 1 13 | } 14 | 15 | if (process.argv[2] === '-c') { 16 | console.log(weexVersion) 17 | } else { 18 | console.log(weexBaseVersion + '-weex.' + weexSubVersion) 19 | } 20 | 21 | module.exports = { 22 | base: weexBaseVersion, 23 | sub: weexSubVersion 24 | } 25 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/git-hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Validate commit log 4 | commit_regex='^Merge.+|(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|types)(\(.+\))?: .{1,50}' 5 | 6 | if ! grep -iqE "$commit_regex" "$1"; then 7 | echo 8 | echo " Error: proper commit message format is required for automated changelog generation." 9 | echo 10 | echo " - Use \`npm run commit\` to interactively generate a commit message." 11 | echo " - See .github/COMMIT_CONVENTION.md for more details." 12 | echo 13 | exit 1 14 | fi 15 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/git-hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | files_to_lint=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$') 4 | 5 | if [ -n "$files_to_lint" ]; then 6 | NODE_ENV=production eslint --quiet $files_to_lint 7 | fi 8 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/release-weex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CUR_VERSION=$(node build/get-weex-version.js -c) 4 | NEXT_VERSION=$(node build/get-weex-version.js) 5 | 6 | echo "Current: $CUR_VERSION" 7 | read -p "Enter new version ($NEXT_VERSION): " -n 1 -r 8 | if ! [[ -z $REPLY ]]; then 9 | NEXT_VERSION=$REPLY 10 | fi 11 | 12 | read -p "Releasing weex-vue-framework@$NEXT_VERSION - are you sure? (y/n) " -n 1 -r 13 | echo 14 | if [[ $REPLY =~ ^[Yy]$ ]]; then 15 | echo "Releasing weex-vue-framework@$NEXT_VERSION ..." 16 | npm run lint 17 | npm run flow 18 | npm run test:weex 19 | 20 | # build 21 | WEEX_VERSION=$NEXT_VERSION npm run build:weex 22 | 23 | # update package 24 | # using subshells to avoid having to cd back 25 | ( cd packages/weex-vue-framework 26 | npm version "$NEXT_VERSION" 27 | npm publish 28 | ) 29 | 30 | ( cd packages/weex-template-compiler 31 | npm version "$NEXT_VERSION" 32 | npm publish 33 | ) 34 | 35 | # commit 36 | git add packages/weex* 37 | git commit -m "[release] weex-vue-framework@$NEXT_VERSION" 38 | fi 39 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/scripts/verify-commit-msg.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const msgPath = process.env.GIT_PARAMS 3 | const msg = require('fs').readFileSync(msgPath, 'utf-8').trim() 4 | 5 | const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/ 6 | 7 | if (!commitRE.test(msg)) { 8 | console.log() 9 | console.error( 10 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\n\n` + 11 | chalk.red(` Proper commit message format is required for automated changelog generation. Examples:\n\n`) + 12 | ` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` + 13 | ` ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\n\n` + 14 | chalk.red(` See .github/COMMIT_CONVENTION.md for more details.\n`) + 15 | chalk.red(` You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\n`) 16 | ) 17 | process.exit(1) 18 | } 19 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/create-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { extend } from 'shared/util' 4 | import { detectErrors } from './error-detector' 5 | import { createCompileToFunctionFn } from './to-function' 6 | 7 | export function createCompilerCreator (baseCompile: Function): Function { 8 | return function createCompiler (baseOptions: CompilerOptions) { 9 | function compile ( 10 | template: string, 11 | options?: CompilerOptions 12 | ): CompiledResult { 13 | const finalOptions = Object.create(baseOptions) 14 | const errors = [] 15 | const tips = [] 16 | finalOptions.warn = (msg, tip) => { 17 | (tip ? tips : errors).push(msg) 18 | } 19 | 20 | if (options) { 21 | // merge custom modules 22 | if (options.modules) { 23 | finalOptions.modules = 24 | (baseOptions.modules || []).concat(options.modules) 25 | } 26 | // merge custom directives 27 | if (options.directives) { 28 | finalOptions.directives = extend( 29 | Object.create(baseOptions.directives || null), 30 | options.directives 31 | ) 32 | } 33 | // copy other options 34 | for (const key in options) { 35 | if (key !== 'modules' && key !== 'directives') { 36 | finalOptions[key] = options[key] 37 | } 38 | } 39 | } 40 | 41 | const compiled = baseCompile(template, finalOptions) 42 | if (process.env.NODE_ENV !== 'production') { 43 | errors.push.apply(errors, detectErrors(compiled.ast)) 44 | } 45 | compiled.errors = errors 46 | compiled.tips = tips 47 | return compiled 48 | } 49 | 50 | return { 51 | compile, 52 | compileToFunctions: createCompileToFunctionFn(compile) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/directives/bind.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default function bind (el: ASTElement, dir: ASTDirective) { 4 | el.wrapData = (code: string) => { 5 | return `_b(${code},'${el.tag}',${dir.value},${ 6 | dir.modifiers && dir.modifiers.prop ? 'true' : 'false' 7 | }${ 8 | dir.modifiers && dir.modifiers.sync ? ',true' : '' 9 | })` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import on from './on' 4 | import bind from './bind' 5 | import { noop } from 'shared/util' 6 | 7 | export default { 8 | on, 9 | bind, 10 | cloak: noop 11 | } 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/directives/on.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn } from 'core/util/index' 4 | 5 | export default function on (el: ASTElement, dir: ASTDirective) { 6 | if (process.env.NODE_ENV !== 'production' && dir.modifiers) { 7 | warn(`v-on without argument does not support modifiers.`) 8 | } 9 | el.wrapListeners = (code: string) => `_g(${code},${dir.value})` 10 | } 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parse } from './parser/index' 4 | import { optimize } from './optimizer' 5 | import { generate } from './codegen/index' 6 | import { createCompilerCreator } from './create-compiler' 7 | 8 | // `createCompilerCreator` allows creating compilers that use alternative 9 | // parser/optimizer/codegen, e.g the SSR optimizing compiler. 10 | // Here we just export a default compiler using the default parts. 11 | export const createCompiler = createCompilerCreator(function baseCompile ( 12 | template: string, 13 | options: CompilerOptions 14 | ): CompiledResult { 15 | // 模板解析阶段:用正则等方式解析 template 模板中的指令、class、style等数据,形成AST 16 | const ast = parse(template.trim(), options) 17 | if (options.optimize !== false) { 18 | // 优化阶段:遍历AST,找出其中的静态节点,并打上标记; 19 | optimize(ast, options) 20 | } 21 | // 代码生成阶段:将AST转换成渲染函数; 22 | const code = generate(ast, options) 23 | return { 24 | ast, 25 | render: code.render, 26 | staticRenderFns: code.staticRenderFns 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/compiler/parser/entity-decoder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | let decoder 4 | 5 | export default { 6 | decode (html: string): string { 7 | decoder = decoder || document.createElement('div') 8 | decoder.innerHTML = html 9 | return decoder.textContent 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/components/index.js: -------------------------------------------------------------------------------- 1 | import KeepAlive from './keep-alive' 2 | 3 | export default { 4 | KeepAlive 5 | } 6 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/global-api/assets.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { ASSET_TYPES } from 'shared/constants' 4 | import { isPlainObject, validateComponentName } from '../util/index' 5 | 6 | export function initAssetRegisters (Vue: GlobalAPI) { 7 | /** 8 | * Create asset registration methods. 9 | */ 10 | ASSET_TYPES.forEach(type => { 11 | Vue[type] = function ( 12 | id: string, 13 | definition: Function | Object 14 | ): Function | Object | void { 15 | if (!definition) { 16 | return this.options[type + 's'][id] 17 | } else { 18 | /* istanbul ignore if */ 19 | if (process.env.NODE_ENV !== 'production' && type === 'component') { 20 | validateComponentName(id) 21 | } 22 | if (type === 'component' && isPlainObject(definition)) { 23 | definition.name = definition.name || id 24 | definition = this.options._base.extend(definition) 25 | } 26 | if (type === 'directive' && typeof definition === 'function') { 27 | definition = { bind: definition, update: definition } 28 | } 29 | this.options[type + 's'][id] = definition 30 | return definition 31 | } 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/global-api/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { initUse } from './use' 5 | import { initMixin } from './mixin' 6 | import { initExtend } from './extend' 7 | import { initAssetRegisters } from './assets' 8 | import { set, del } from '../observer/index' 9 | import { ASSET_TYPES } from 'shared/constants' 10 | import builtInComponents from '../components/index' 11 | 12 | import { 13 | warn, 14 | extend, 15 | nextTick, 16 | mergeOptions, 17 | defineReactive 18 | } from '../util/index' 19 | 20 | export function initGlobalAPI (Vue: GlobalAPI) { 21 | // config 22 | const configDef = {} 23 | configDef.get = () => config 24 | if (process.env.NODE_ENV !== 'production') { 25 | configDef.set = () => { 26 | warn( 27 | 'Do not replace the Vue.config object, set individual fields instead.' 28 | ) 29 | } 30 | } 31 | Object.defineProperty(Vue, 'config', configDef) 32 | 33 | // exposed util methods. 34 | // NOTE: these are not considered part of the public API - avoid relying on 35 | // them unless you are aware of the risk. 36 | Vue.util = { 37 | warn, 38 | extend, 39 | mergeOptions, 40 | defineReactive 41 | } 42 | 43 | Vue.set = set 44 | Vue.delete = del 45 | Vue.nextTick = nextTick 46 | 47 | Vue.options = Object.create(null) 48 | ASSET_TYPES.forEach(type => { 49 | Vue.options[type + 's'] = Object.create(null) 50 | }) 51 | 52 | // this is used to identify the "base" constructor to extend all plain-object 53 | // components with in Weex's multi-instance scenarios. 54 | Vue.options._base = Vue 55 | 56 | extend(Vue.options.components, builtInComponents) 57 | 58 | initUse(Vue) 59 | initMixin(Vue) 60 | initExtend(Vue) 61 | initAssetRegisters(Vue) 62 | } 63 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/global-api/mixin.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { mergeOptions } from '../util/index' 4 | 5 | export function initMixin (Vue: GlobalAPI) { 6 | Vue.mixin = function (mixin: Object) { 7 | this.options = mergeOptions(this.options, mixin) 8 | return this 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/global-api/use.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toArray } from '../util/index' 4 | 5 | export function initUse (Vue: GlobalAPI) { 6 | Vue.use = function (plugin: Function | Object) { 7 | const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) 8 | if (installedPlugins.indexOf(plugin) > -1) { 9 | return this 10 | } 11 | 12 | // additional parameters 13 | const args = toArray(arguments, 1) 14 | args.unshift(this) 15 | if (typeof plugin.install === 'function') { 16 | plugin.install.apply(plugin, args) 17 | } else if (typeof plugin === 'function') { 18 | plugin.apply(null, args) 19 | } 20 | installedPlugins.push(plugin) 21 | return this 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/index.js: -------------------------------------------------------------------------------- 1 | import Vue from './instance/index' 2 | import { initGlobalAPI } from './global-api/index' 3 | import { isServerRendering } from 'core/util/env' 4 | import { FunctionalRenderContext } from 'core/vdom/create-functional-component' 5 | 6 | initGlobalAPI(Vue) 7 | 8 | Object.defineProperty(Vue.prototype, '$isServer', { 9 | get: isServerRendering 10 | }) 11 | 12 | Object.defineProperty(Vue.prototype, '$ssrContext', { 13 | get () { 14 | /* istanbul ignore next */ 15 | return this.$vnode && this.$vnode.ssrContext 16 | } 17 | }) 18 | 19 | // expose FunctionalRenderContext for ssr runtime helper installation 20 | Object.defineProperty(Vue, 'FunctionalRenderContext', { 21 | value: FunctionalRenderContext 22 | }) 23 | 24 | Vue.version = '__VERSION__' 25 | 26 | export default Vue 27 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/index.js: -------------------------------------------------------------------------------- 1 | import { initMixin } from './init' 2 | import { stateMixin } from './state' 3 | import { renderMixin } from './render' 4 | import { eventsMixin } from './events' 5 | import { lifecycleMixin } from './lifecycle' 6 | import { warn } from '../util/index' 7 | 8 | function Vue (options) { 9 | if (process.env.NODE_ENV !== 'production' && 10 | !(this instanceof Vue) 11 | ) { 12 | warn('Vue is a constructor and should be called with the `new` keyword') 13 | } 14 | this._init(options) 15 | } 16 | 17 | initMixin(Vue) 18 | stateMixin(Vue) 19 | eventsMixin(Vue) 20 | lifecycleMixin(Vue) 21 | renderMixin(Vue) 22 | 23 | export default Vue 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/bind-object-listeners.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { warn, extend, isPlainObject } from 'core/util/index' 4 | 5 | export function bindObjectListeners (data: any, value: any): VNodeData { 6 | if (value) { 7 | if (!isPlainObject(value)) { 8 | process.env.NODE_ENV !== 'production' && warn( 9 | 'v-on without argument expects an Object value', 10 | this 11 | ) 12 | } else { 13 | const on = data.on = data.on ? extend({}, data.on) : {} 14 | for (const key in value) { 15 | const existing = on[key] 16 | const ours = value[key] 17 | on[key] = existing ? [].concat(existing, ours) : ours 18 | } 19 | } 20 | } 21 | return data 22 | } 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/bind-object-props.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from 'core/config' 4 | 5 | import { 6 | warn, 7 | isObject, 8 | toObject, 9 | isReservedAttribute 10 | } from 'core/util/index' 11 | 12 | /** 13 | * Runtime helper for merging v-bind="object" into a VNode's data. 14 | */ 15 | export function bindObjectProps ( 16 | data: any, 17 | tag: string, 18 | value: any, 19 | asProp: boolean, 20 | isSync?: boolean 21 | ): VNodeData { 22 | if (value) { 23 | if (!isObject(value)) { 24 | process.env.NODE_ENV !== 'production' && warn( 25 | 'v-bind without argument expects an Object or Array value', 26 | this 27 | ) 28 | } else { 29 | if (Array.isArray(value)) { 30 | value = toObject(value) 31 | } 32 | let hash 33 | for (const key in value) { 34 | if ( 35 | key === 'class' || 36 | key === 'style' || 37 | isReservedAttribute(key) 38 | ) { 39 | hash = data 40 | } else { 41 | const type = data.attrs && data.attrs.type 42 | hash = asProp || config.mustUseProp(tag, type, key) 43 | ? data.domProps || (data.domProps = {}) 44 | : data.attrs || (data.attrs = {}) 45 | } 46 | if (!(key in hash)) { 47 | hash[key] = value[key] 48 | 49 | if (isSync) { 50 | const on = data.on || (data.on = {}) 51 | on[`update:${key}`] = function ($event) { 52 | value[key] = $event 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | return data 60 | } 61 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/check-keycodes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from 'core/config' 4 | import { hyphenate } from 'shared/util' 5 | 6 | function isKeyNotMatch (expect: T | Array, actual: T): boolean { 7 | if (Array.isArray(expect)) { 8 | return expect.indexOf(actual) === -1 9 | } else { 10 | return expect !== actual 11 | } 12 | } 13 | 14 | /** 15 | * Runtime helper for checking keyCodes from config. 16 | * exposed as Vue.prototype._k 17 | * passing in eventKeyName as last argument separately for backwards compat 18 | */ 19 | export function checkKeyCodes ( 20 | eventKeyCode: number, 21 | key: string, 22 | builtInKeyCode?: number | Array, 23 | eventKeyName?: string, 24 | builtInKeyName?: string | Array 25 | ): ?boolean { 26 | const mappedKeyCode = config.keyCodes[key] || builtInKeyCode 27 | if (builtInKeyName && eventKeyName && !config.keyCodes[key]) { 28 | return isKeyNotMatch(builtInKeyName, eventKeyName) 29 | } else if (mappedKeyCode) { 30 | return isKeyNotMatch(mappedKeyCode, eventKeyCode) 31 | } else if (eventKeyName) { 32 | return hyphenate(eventKeyName) !== key 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { toNumber, toString, looseEqual, looseIndexOf } from 'shared/util' 4 | import { createTextVNode, createEmptyVNode } from 'core/vdom/vnode' 5 | import { renderList } from './render-list' 6 | import { renderSlot } from './render-slot' 7 | import { resolveFilter } from './resolve-filter' 8 | import { checkKeyCodes } from './check-keycodes' 9 | import { bindObjectProps } from './bind-object-props' 10 | import { renderStatic, markOnce } from './render-static' 11 | import { bindObjectListeners } from './bind-object-listeners' 12 | import { resolveScopedSlots } from './resolve-slots' 13 | 14 | export function installRenderHelpers (target: any) { 15 | target._o = markOnce 16 | target._n = toNumber 17 | target._s = toString 18 | target._l = renderList 19 | target._t = renderSlot 20 | target._q = looseEqual 21 | target._i = looseIndexOf 22 | target._m = renderStatic 23 | target._f = resolveFilter 24 | target._k = checkKeyCodes 25 | target._b = bindObjectProps 26 | target._v = createTextVNode 27 | target._e = createEmptyVNode 28 | target._u = resolveScopedSlots 29 | target._g = bindObjectListeners 30 | } 31 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/render-list.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isObject, isDef } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for rendering v-for lists. 7 | */ 8 | export function renderList ( 9 | val: any, 10 | render: ( 11 | val: any, 12 | keyOrIndex: string | number, 13 | index?: number 14 | ) => VNode 15 | ): ?Array { 16 | let ret: ?Array, i, l, keys, key 17 | if (Array.isArray(val) || typeof val === 'string') { 18 | ret = new Array(val.length) 19 | for (i = 0, l = val.length; i < l; i++) { 20 | ret[i] = render(val[i], i) 21 | } 22 | } else if (typeof val === 'number') { 23 | ret = new Array(val) 24 | for (i = 0; i < val; i++) { 25 | ret[i] = render(i + 1, i) 26 | } 27 | } else if (isObject(val)) { 28 | keys = Object.keys(val) 29 | ret = new Array(keys.length) 30 | for (i = 0, l = keys.length; i < l; i++) { 31 | key = keys[i] 32 | ret[i] = render(val[key], key, i) 33 | } 34 | } 35 | if (isDef(ret)) { 36 | (ret: any)._isVList = true 37 | } 38 | return ret 39 | } 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/render-slot.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { extend, warn, isObject } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for rendering 7 | */ 8 | export function renderSlot ( 9 | name: string, 10 | fallback: ?Array, 11 | props: ?Object, 12 | bindObject: ?Object 13 | ): ?Array { 14 | const scopedSlotFn = this.$scopedSlots[name] 15 | let nodes 16 | if (scopedSlotFn) { // scoped slot 17 | props = props || {} 18 | if (bindObject) { 19 | if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) { 20 | warn( 21 | 'slot v-bind without argument expects an Object', 22 | this 23 | ) 24 | } 25 | props = extend(extend({}, bindObject), props) 26 | } 27 | nodes = scopedSlotFn(props) || fallback 28 | } else { 29 | const slotNodes = this.$slots[name] 30 | // warn duplicate slot usage 31 | if (slotNodes) { 32 | if (process.env.NODE_ENV !== 'production' && slotNodes._rendered) { 33 | warn( 34 | `Duplicate presence of slot "${name}" found in the same render tree ` + 35 | `- this will likely cause render errors.`, 36 | this 37 | ) 38 | } 39 | slotNodes._rendered = true 40 | } 41 | nodes = slotNodes || fallback 42 | } 43 | 44 | const target = props && props.slot 45 | if (target) { 46 | return this.$createElement('template', { slot: target }, nodes) 47 | } else { 48 | return nodes 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/render-static.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Runtime helper for rendering static trees. 5 | */ 6 | export function renderStatic ( 7 | index: number, 8 | isInFor: boolean 9 | ): VNode | Array { 10 | const cached = this._staticTrees || (this._staticTrees = []) 11 | let tree = cached[index] 12 | // if has already-rendered static tree and not inside v-for, 13 | // we can reuse the same tree. 14 | if (tree && !isInFor) { 15 | return tree 16 | } 17 | // otherwise, render a fresh tree. 18 | tree = cached[index] = this.$options.staticRenderFns[index].call( 19 | this._renderProxy, 20 | null, 21 | this // for render fns generated for functional component templates 22 | ) 23 | markStatic(tree, `__static__${index}`, false) 24 | return tree 25 | } 26 | 27 | /** 28 | * Runtime helper for v-once. 29 | * Effectively it means marking the node as static with a unique key. 30 | */ 31 | export function markOnce ( 32 | tree: VNode | Array, 33 | index: number, 34 | key: string 35 | ) { 36 | markStatic(tree, `__once__${index}${key ? `_${key}` : ``}`, true) 37 | return tree 38 | } 39 | 40 | function markStatic ( 41 | tree: VNode | Array, 42 | key: string, 43 | isOnce: boolean 44 | ) { 45 | if (Array.isArray(tree)) { 46 | for (let i = 0; i < tree.length; i++) { 47 | if (tree[i] && typeof tree[i] !== 'string') { 48 | markStaticNode(tree[i], `${key}_${i}`, isOnce) 49 | } 50 | } 51 | } else { 52 | markStaticNode(tree, key, isOnce) 53 | } 54 | } 55 | 56 | function markStaticNode (node, key, isOnce) { 57 | node.isStatic = true 58 | node.key = key 59 | node.isOnce = isOnce 60 | } 61 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/instance/render-helpers/resolve-filter.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { identity, resolveAsset } from 'core/util/index' 4 | 5 | /** 6 | * Runtime helper for resolving filters 7 | */ 8 | export function resolveFilter (id: string): Function { 9 | return resolveAsset(this.$options, 'filters', id, true) || identity 10 | } 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/observer/array.js: -------------------------------------------------------------------------------- 1 | /* 2 | * not type checking this file because flow doesn't play well with 3 | * dynamically accessing methods on Array prototype 4 | */ 5 | 6 | import { def } from '../util/index' 7 | 8 | const arrayProto = Array.prototype 9 | // 新建一个继承于Array的对象,作为拦截器 10 | export const arrayMethods = Object.create(arrayProto) 11 | // 改变数组自身内容的7个方法 12 | const methodsToPatch = [ 13 | 'push', 14 | 'pop', 15 | 'shift', 16 | 'unshift', 17 | 'splice', 18 | 'sort', 19 | 'reverse' 20 | ] 21 | 22 | /** 23 | * Intercept mutating methods and emit events 24 | */ 25 | methodsToPatch.forEach(function (method) { 26 | // cache original method 27 | const original = arrayProto[method] // 缓存原生方法 28 | def(arrayMethods, method, function mutator (...args) { 29 | const result = original.apply(this, args) 30 | const ob = this.__ob__ 31 | let inserted 32 | switch (method) { 33 | case 'push': 34 | case 'unshift': 35 | inserted = args 36 | break 37 | case 'splice': 38 | inserted = args.slice(2) 39 | break 40 | } 41 | if (inserted) ob.observeArray(inserted) 42 | // notify change 43 | ob.dep.notify() 44 | return result 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/observer/dep.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import type Watcher from './watcher' 4 | import { remove } from '../util/index' 5 | 6 | let uid = 0 7 | 8 | /** 9 | * A dep is an observable that can have multiple 10 | * directives subscribing to it. 11 | */ 12 | export default class Dep { 13 | static target: ?Watcher; 14 | id: number; 15 | subs: Array; 16 | 17 | constructor () { 18 | this.id = uid++ 19 | this.subs = [] 20 | } 21 | 22 | addSub (sub: Watcher) { 23 | this.subs.push(sub) 24 | } 25 | 26 | removeSub (sub: Watcher) { 27 | remove(this.subs, sub) 28 | } 29 | 30 | depend () { 31 | if (Dep.target) { 32 | Dep.target.addDep(this) 33 | } 34 | } 35 | 36 | notify () { 37 | // stabilize the subscriber list first 38 | const subs = this.subs.slice() 39 | for (let i = 0, l = subs.length; i < l; i++) { 40 | subs[i].update() 41 | } 42 | } 43 | } 44 | 45 | // the current target watcher being evaluated. 46 | // this is globally unique because there could be only one 47 | // watcher being evaluated at any time. 48 | Dep.target = null 49 | const targetStack = [] 50 | 51 | export function pushTarget (_target: ?Watcher) { 52 | if (Dep.target) targetStack.push(Dep.target) 53 | Dep.target = _target 54 | } 55 | 56 | export function popTarget () { 57 | Dep.target = targetStack.pop() 58 | } 59 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/observer/traverse.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { _Set as Set, isObject } from '../util/index' 4 | import type { SimpleSet } from '../util/index' 5 | import VNode from '../vdom/vnode' 6 | 7 | const seenObjects = new Set() 8 | 9 | /** 10 | * Recursively traverse an object to evoke all converted 11 | * getters, so that every nested property inside the object 12 | * is collected as a "deep" dependency. 13 | */ 14 | export function traverse (val: any) { 15 | _traverse(val, seenObjects) 16 | seenObjects.clear() 17 | } 18 | 19 | function _traverse (val: any, seen: SimpleSet) { 20 | let i, keys 21 | const isA = Array.isArray(val) 22 | if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { 23 | return 24 | } 25 | if (val.__ob__) { 26 | const depId = val.__ob__.dep.id 27 | if (seen.has(depId)) { 28 | return 29 | } 30 | seen.add(depId) 31 | } 32 | if (isA) { 33 | i = val.length 34 | while (i--) _traverse(val[i], seen) 35 | } else { 36 | keys = Object.keys(val) 37 | i = keys.length 38 | while (i--) _traverse(val[keys[i]], seen) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/util/error.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import config from '../config' 4 | import { warn } from './debug' 5 | import { inBrowser, inWeex } from './env' 6 | 7 | export function handleError (err: Error, vm: any, info: string) { 8 | if (vm) { 9 | let cur = vm 10 | while ((cur = cur.$parent)) { 11 | const hooks = cur.$options.errorCaptured 12 | if (hooks) { 13 | for (let i = 0; i < hooks.length; i++) { 14 | try { 15 | const capture = hooks[i].call(cur, err, vm, info) === false 16 | if (capture) return 17 | } catch (e) { 18 | globalHandleError(e, cur, 'errorCaptured hook') 19 | } 20 | } 21 | } 22 | } 23 | } 24 | globalHandleError(err, vm, info) 25 | } 26 | 27 | function globalHandleError (err, vm, info) { 28 | if (config.errorHandler) { 29 | try { 30 | return config.errorHandler.call(null, err, vm, info) 31 | } catch (e) { 32 | logError(e, null, 'config.errorHandler') 33 | } 34 | } 35 | logError(err, vm, info) 36 | } 37 | 38 | function logError (err, vm, info) { 39 | if (process.env.NODE_ENV !== 'production') { 40 | warn(`Error in ${info}: "${err.toString()}"`, vm) 41 | } 42 | /* istanbul ignore else */ 43 | if ((inBrowser || inWeex) && typeof console !== 'undefined') { 44 | console.error(err) 45 | } else { 46 | throw err 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/util/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from 'shared/util' 4 | export * from './lang' 5 | export * from './env' 6 | export * from './options' 7 | export * from './debug' 8 | export * from './props' 9 | export * from './error' 10 | export * from './next-tick' 11 | export { defineReactive } from '../observer/index' 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/util/lang.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Check if a string starts with $ or _ 5 | */ 6 | export function isReserved (str: string): boolean { 7 | const c = (str + '').charCodeAt(0) 8 | return c === 0x24 || c === 0x5F 9 | } 10 | 11 | /** 12 | * Define a property. 13 | */ 14 | export function def (obj: Object, key: string, val: any, enumerable?: boolean) { 15 | Object.defineProperty(obj, key, { 16 | value: val, 17 | enumerable: !!enumerable, 18 | writable: true, 19 | configurable: true 20 | }) 21 | } 22 | 23 | /** 24 | * Parse simple path. 25 | */ 26 | const bailRE = /[^\w.$]/ 27 | export function parsePath (path: string): any { 28 | if (bailRE.test(path)) { 29 | return 30 | } 31 | const segments = path.split('.') 32 | return function (obj) { 33 | for (let i = 0; i < segments.length; i++) { 34 | if (!obj) return 35 | obj = obj[segments[i]] 36 | } 37 | return obj 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/util/perf.js: -------------------------------------------------------------------------------- 1 | import { inBrowser } from './env' 2 | 3 | export let mark 4 | export let measure 5 | 6 | if (process.env.NODE_ENV !== 'production') { 7 | const perf = inBrowser && window.performance 8 | /* istanbul ignore if */ 9 | if ( 10 | perf && 11 | perf.mark && 12 | perf.measure && 13 | perf.clearMarks && 14 | perf.clearMeasures 15 | ) { 16 | mark = tag => perf.mark(tag) 17 | measure = (name, startTag, endTag) => { 18 | perf.measure(name, startTag, endTag) 19 | perf.clearMarks(startTag) 20 | perf.clearMarks(endTag) 21 | perf.clearMeasures(name) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/helpers/get-first-component-child.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { isDef } from 'shared/util' 4 | import { isAsyncPlaceholder } from './is-async-placeholder' 5 | 6 | export function getFirstComponentChild (children: ?Array): ?VNode { 7 | if (Array.isArray(children)) { 8 | for (let i = 0; i < children.length; i++) { 9 | const c = children[i] 10 | if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) { 11 | return c 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export * from './merge-hook' 4 | export * from './extract-props' 5 | export * from './update-listeners' 6 | export * from './normalize-children' 7 | export * from './resolve-async-component' 8 | export * from './get-first-component-child' 9 | export * from './is-async-placeholder' 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/helpers/is-async-placeholder.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export function isAsyncPlaceholder (node: VNode): boolean { 4 | return node.isComment && node.asyncFactory 5 | } 6 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/helpers/merge-hook.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import VNode from '../vnode' 4 | import { createFnInvoker } from './update-listeners' 5 | import { remove, isDef, isUndef, isTrue } from 'shared/util' 6 | 7 | export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) { 8 | if (def instanceof VNode) { 9 | def = def.data.hook || (def.data.hook = {}) 10 | } 11 | let invoker 12 | const oldHook = def[hookKey] 13 | 14 | function wrappedHook () { 15 | hook.apply(this, arguments) 16 | // important: remove merged hook to ensure it's called only once 17 | // and prevent memory leak 18 | remove(invoker.fns, wrappedHook) 19 | } 20 | 21 | if (isUndef(oldHook)) { 22 | // no existing hook 23 | invoker = createFnInvoker([wrappedHook]) 24 | } else { 25 | /* istanbul ignore if */ 26 | if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { 27 | // already a merged invoker 28 | invoker = oldHook 29 | invoker.fns.push(wrappedHook) 30 | } else { 31 | // existing plain hook 32 | invoker = createFnInvoker([oldHook, wrappedHook]) 33 | } 34 | } 35 | 36 | invoker.merged = true 37 | def[hookKey] = invoker 38 | } 39 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/modules/index.js: -------------------------------------------------------------------------------- 1 | import directives from './directives' 2 | import ref from './ref' 3 | 4 | export default [ 5 | ref, 6 | directives 7 | ] 8 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/core/vdom/modules/ref.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { remove, isDef } from 'shared/util' 4 | 5 | export default { 6 | create (_: any, vnode: VNodeWithData) { 7 | registerRef(vnode) 8 | }, 9 | update (oldVnode: VNodeWithData, vnode: VNodeWithData) { 10 | if (oldVnode.data.ref !== vnode.data.ref) { 11 | registerRef(oldVnode, true) 12 | registerRef(vnode) 13 | } 14 | }, 15 | destroy (vnode: VNodeWithData) { 16 | registerRef(vnode, true) 17 | } 18 | } 19 | 20 | export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) { 21 | const key = vnode.data.ref 22 | if (!isDef(key)) return 23 | 24 | const vm = vnode.context 25 | const ref = vnode.componentInstance || vnode.elm 26 | const refs = vm.$refs 27 | if (isRemoval) { 28 | if (Array.isArray(refs[key])) { 29 | remove(refs[key], ref) 30 | } else if (refs[key] === ref) { 31 | refs[key] = undefined 32 | } 33 | } else { 34 | if (vnode.data.refInFor) { 35 | if (!Array.isArray(refs[key])) { 36 | refs[key] = [ref] 37 | } else if (refs[key].indexOf(ref) < 0) { 38 | // $flow-disable-line 39 | refs[key].push(ref) 40 | } 41 | } else { 42 | refs[key] = ref 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/directives/html.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function html (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'innerHTML', `_s(${dir.value})`) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import text from './text' 3 | import html from './html' 4 | 5 | export default { 6 | model, 7 | text, 8 | html 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/directives/text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { addProp } from 'compiler/helpers' 4 | 5 | export default function text (el: ASTElement, dir: ASTDirective) { 6 | if (dir.value) { 7 | addProp(el, 'textContent', `_s(${dir.value})`) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from './options' 4 | import { createCompiler } from 'compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { compile, compileToFunctions } 9 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseText } from 'compiler/parser/text-parser' 4 | import { 5 | getAndRemoveAttr, 6 | getBindingAttr, 7 | baseWarn 8 | } from 'compiler/helpers' 9 | 10 | function transformNode (el: ASTElement, options: CompilerOptions) { 11 | const warn = options.warn || baseWarn 12 | const staticClass = getAndRemoveAttr(el, 'class') 13 | if (process.env.NODE_ENV !== 'production' && staticClass) { 14 | const res = parseText(staticClass, options.delimiters) 15 | if (res) { 16 | warn( 17 | `class="${staticClass}": ` + 18 | 'Interpolation inside attributes has been removed. ' + 19 | 'Use v-bind or the colon shorthand instead. For example, ' + 20 | 'instead of
, use
.' 21 | ) 22 | } 23 | } 24 | if (staticClass) { 25 | el.staticClass = JSON.stringify(staticClass) 26 | } 27 | const classBinding = getBindingAttr(el, 'class', false /* getStatic */) 28 | if (classBinding) { 29 | el.classBinding = classBinding 30 | } 31 | } 32 | 33 | function genData (el: ASTElement): string { 34 | let data = '' 35 | if (el.staticClass) { 36 | data += `staticClass:${el.staticClass},` 37 | } 38 | if (el.classBinding) { 39 | data += `class:${el.classBinding},` 40 | } 41 | return data 42 | } 43 | 44 | export default { 45 | staticKeys: ['staticClass'], 46 | transformNode, 47 | genData 48 | } 49 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/modules/index.js: -------------------------------------------------------------------------------- 1 | import klass from './class' 2 | import style from './style' 3 | import model from './model' 4 | 5 | export default [ 6 | klass, 7 | style, 8 | model 9 | ] 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/modules/style.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { parseText } from 'compiler/parser/text-parser' 4 | import { parseStyleText } from 'web/util/style' 5 | import { 6 | getAndRemoveAttr, 7 | getBindingAttr, 8 | baseWarn 9 | } from 'compiler/helpers' 10 | 11 | function transformNode (el: ASTElement, options: CompilerOptions) { 12 | const warn = options.warn || baseWarn 13 | const staticStyle = getAndRemoveAttr(el, 'style') 14 | if (staticStyle) { 15 | /* istanbul ignore if */ 16 | if (process.env.NODE_ENV !== 'production') { 17 | const res = parseText(staticStyle, options.delimiters) 18 | if (res) { 19 | warn( 20 | `style="${staticStyle}": ` + 21 | 'Interpolation inside attributes has been removed. ' + 22 | 'Use v-bind or the colon shorthand instead. For example, ' + 23 | 'instead of
, use
.' 24 | ) 25 | } 26 | } 27 | el.staticStyle = JSON.stringify(parseStyleText(staticStyle)) 28 | } 29 | 30 | const styleBinding = getBindingAttr(el, 'style', false /* getStatic */) 31 | if (styleBinding) { 32 | el.styleBinding = styleBinding 33 | } 34 | } 35 | 36 | function genData (el: ASTElement): string { 37 | let data = '' 38 | if (el.staticStyle) { 39 | data += `staticStyle:${el.staticStyle},` 40 | } 41 | if (el.styleBinding) { 42 | data += `style:(${el.styleBinding}),` 43 | } 44 | return data 45 | } 46 | 47 | export default { 48 | staticKeys: ['staticStyle'], 49 | transformNode, 50 | genData 51 | } 52 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/options.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isPreTag, 5 | mustUseProp, 6 | isReservedTag, 7 | getTagNamespace 8 | } from '../util/index' 9 | 10 | import modules from './modules/index' 11 | import directives from './directives/index' 12 | import { genStaticKeys } from 'shared/util' 13 | import { isUnaryTag, canBeLeftOpenTag } from './util' 14 | 15 | export const baseOptions: CompilerOptions = { 16 | expectHTML: true, 17 | modules, 18 | directives, 19 | isPreTag, 20 | isUnaryTag, 21 | mustUseProp, 22 | canBeLeftOpenTag, 23 | isReservedTag, 24 | getTagNamespace, 25 | staticKeys: genStaticKeys(modules) 26 | } 27 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/compiler/util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { makeMap } from 'shared/util' 4 | 5 | export const isUnaryTag = makeMap( 6 | 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' + 7 | 'link,meta,param,source,track,wbr' 8 | ) 9 | 10 | // Elements that you can, intentionally, leave open 11 | // (and which close themselves) 12 | export const canBeLeftOpenTag = makeMap( 13 | 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source' 14 | ) 15 | 16 | // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3 17 | // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content 18 | export const isNonPhrasingTag = makeMap( 19 | 'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' + 20 | 'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' + 21 | 'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' + 22 | 'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' + 23 | 'title,tr,track' 24 | ) 25 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/entry-compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export { parseComponent } from 'sfc/parser' 4 | export { compile, compileToFunctions } from './compiler/index' 5 | export { ssrCompile, ssrCompileToFunctions } from './server/compiler' 6 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/entry-runtime.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import Vue from './runtime/index' 4 | 5 | export default Vue 6 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/entry-server-basic-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import modules from './server/modules/index' 4 | import directives from './server/directives/index' 5 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 6 | import { createBasicRenderer } from 'server/create-basic-renderer' 7 | 8 | export default createBasicRenderer({ 9 | modules, 10 | directives, 11 | isUnaryTag, 12 | canBeLeftOpenTag 13 | }) 14 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/entry-server-renderer.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | process.env.VUE_ENV = 'server' 4 | 5 | import { extend } from 'shared/util' 6 | import modules from './server/modules/index' 7 | import baseDirectives from './server/directives/index' 8 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util' 9 | 10 | import { createRenderer as _createRenderer } from 'server/create-renderer' 11 | import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer' 12 | 13 | export function createRenderer (options?: Object = {}): { 14 | renderToString: Function, 15 | renderToStream: Function 16 | } { 17 | return _createRenderer(extend(extend({}, options), { 18 | isUnaryTag, 19 | canBeLeftOpenTag, 20 | modules, 21 | // user can provide server-side implementations for custom directives 22 | // when creating the renderer. 23 | directives: extend(baseDirectives, options.directives) 24 | })) 25 | } 26 | 27 | export const createBundleRenderer = createBundleRendererCreator(createRenderer) 28 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/class-util.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | /** 4 | * Add class with compatibility for SVG since classList is not supported on 5 | * SVG elements in IE 6 | */ 7 | export function addClass (el: HTMLElement, cls: ?string) { 8 | /* istanbul ignore if */ 9 | if (!cls || !(cls = cls.trim())) { 10 | return 11 | } 12 | 13 | /* istanbul ignore else */ 14 | if (el.classList) { 15 | if (cls.indexOf(' ') > -1) { 16 | cls.split(/\s+/).forEach(c => el.classList.add(c)) 17 | } else { 18 | el.classList.add(cls) 19 | } 20 | } else { 21 | const cur = ` ${el.getAttribute('class') || ''} ` 22 | if (cur.indexOf(' ' + cls + ' ') < 0) { 23 | el.setAttribute('class', (cur + cls).trim()) 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * Remove class with compatibility for SVG since classList is not supported on 30 | * SVG elements in IE 31 | */ 32 | export function removeClass (el: HTMLElement, cls: ?string) { 33 | /* istanbul ignore if */ 34 | if (!cls || !(cls = cls.trim())) { 35 | return 36 | } 37 | 38 | /* istanbul ignore else */ 39 | if (el.classList) { 40 | if (cls.indexOf(' ') > -1) { 41 | cls.split(/\s+/).forEach(c => el.classList.remove(c)) 42 | } else { 43 | el.classList.remove(cls) 44 | } 45 | if (!el.classList.length) { 46 | el.removeAttribute('class') 47 | } 48 | } else { 49 | let cur = ` ${el.getAttribute('class') || ''} ` 50 | const tar = ' ' + cls + ' ' 51 | while (cur.indexOf(tar) >= 0) { 52 | cur = cur.replace(tar, ' ') 53 | } 54 | cur = cur.trim() 55 | if (cur) { 56 | el.setAttribute('class', cur) 57 | } else { 58 | el.removeAttribute('class') 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/components/index.js: -------------------------------------------------------------------------------- 1 | import Transition from './transition' 2 | import TransitionGroup from './transition-group' 3 | 4 | export default { 5 | Transition, 6 | TransitionGroup 7 | } 8 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/directives/index.js: -------------------------------------------------------------------------------- 1 | import model from './model' 2 | import show from './show' 3 | 4 | export default { 5 | model, 6 | show 7 | } 8 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/modules/class.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { 4 | isDef, 5 | isUndef 6 | } from 'shared/util' 7 | 8 | import { 9 | concat, 10 | stringifyClass, 11 | genClassForVnode 12 | } from 'web/util/index' 13 | 14 | function updateClass (oldVnode: any, vnode: any) { 15 | const el = vnode.elm 16 | const data: VNodeData = vnode.data 17 | const oldData: VNodeData = oldVnode.data 18 | if ( 19 | isUndef(data.staticClass) && 20 | isUndef(data.class) && ( 21 | isUndef(oldData) || ( 22 | isUndef(oldData.staticClass) && 23 | isUndef(oldData.class) 24 | ) 25 | ) 26 | ) { 27 | return 28 | } 29 | 30 | let cls = genClassForVnode(vnode) 31 | 32 | // handle transition classes 33 | const transitionClass = el._transitionClasses 34 | if (isDef(transitionClass)) { 35 | cls = concat(cls, stringifyClass(transitionClass)) 36 | } 37 | 38 | // set the class 39 | if (cls !== el._prevClass) { 40 | el.setAttribute('class', cls) 41 | el._prevClass = cls 42 | } 43 | } 44 | 45 | export default { 46 | create: updateClass, 47 | update: updateClass 48 | } 49 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/modules/index.js: -------------------------------------------------------------------------------- 1 | import attrs from './attrs' 2 | import klass from './class' 3 | import events from './events' 4 | import domProps from './dom-props' 5 | import style from './style' 6 | import transition from './transition' 7 | 8 | export default [ 9 | attrs, 10 | klass, 11 | events, 12 | domProps, 13 | style, 14 | transition 15 | ] 16 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/node-ops.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { namespaceMap } from 'web/util/index' 4 | 5 | export function createElement (tagName: string, vnode: VNode): Element { 6 | const elm = document.createElement(tagName) 7 | if (tagName !== 'select') { 8 | return elm 9 | } 10 | // false or null will remove the attribute but undefined will not 11 | if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) { 12 | elm.setAttribute('multiple', 'multiple') 13 | } 14 | return elm 15 | } 16 | 17 | export function createElementNS (namespace: string, tagName: string): Element { 18 | return document.createElementNS(namespaceMap[namespace], tagName) 19 | } 20 | 21 | export function createTextNode (text: string): Text { 22 | return document.createTextNode(text) 23 | } 24 | 25 | export function createComment (text: string): Comment { 26 | return document.createComment(text) 27 | } 28 | 29 | export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) { 30 | parentNode.insertBefore(newNode, referenceNode) 31 | } 32 | 33 | export function removeChild (node: Node, child: Node) { 34 | node.removeChild(child) 35 | } 36 | 37 | export function appendChild (node: Node, child: Node) { 38 | node.appendChild(child) 39 | } 40 | 41 | export function parentNode (node: Node): ?Node { 42 | return node.parentNode 43 | } 44 | 45 | export function nextSibling (node: Node): ?Node { 46 | return node.nextSibling 47 | } 48 | 49 | export function tagName (node: Element): string { 50 | return node.tagName 51 | } 52 | 53 | export function setTextContent (node: Node, text: string) { 54 | node.textContent = text 55 | } 56 | 57 | export function setStyleScope (node: Element, scopeId: string) { 58 | node.setAttribute(scopeId, '') 59 | } 60 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/runtime/patch.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import * as nodeOps from 'web/runtime/node-ops' 4 | import { createPatchFunction } from 'core/vdom/patch' 5 | import baseModules from 'core/vdom/modules/index' 6 | import platformModules from 'web/runtime/modules/index' 7 | 8 | // the directive module should be applied last, after all 9 | // built-in modules have been applied. 10 | const modules = platformModules.concat(baseModules) 11 | 12 | export const patch: Function = createPatchFunction({ nodeOps, modules }) 13 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/server/compiler.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { baseOptions } from '../compiler/options' 4 | import { createCompiler } from 'server/optimizing-compiler/index' 5 | 6 | const { compile, compileToFunctions } = createCompiler(baseOptions) 7 | 8 | export { 9 | compile as ssrCompile, 10 | compileToFunctions as ssrCompileToFunctions 11 | } 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/server/directives/index.js: -------------------------------------------------------------------------------- 1 | import show from './show' 2 | import model from './model' 3 | 4 | export default { 5 | show, 6 | model 7 | } 8 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/src/platforms/web/server/directives/model.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | import { looseEqual, looseIndexOf } from 'shared/util' 4 | 5 | // this is only applied for 15 |
16 |
17 | 26 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | countA: {{countA}} 37 |
38 |
39 | countB: {{countB}} 40 |
41 |
42 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/async-edge-cases.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'async edge cases': function (browser) { 3 | browser 4 | .url('http://localhost:8080/test/e2e/specs/async-edge-cases.html') 5 | // #4510 6 | .assert.containsText('#case-1', '1') 7 | .assert.checked('#case-1 input', false) 8 | 9 | .click('#case-1 input') 10 | .assert.containsText('#case-1', '2') 11 | .assert.checked('#case-1 input', true) 12 | 13 | .click('#case-1 input') 14 | .assert.containsText('#case-1', '3') 15 | .assert.checked('#case-1 input', false) 16 | 17 | // #6566 18 | .assert.containsText('#case-2 button', 'Expand is True') 19 | .assert.containsText('.count-a', 'countA: 0') 20 | .assert.containsText('.count-b', 'countB: 0') 21 | 22 | .click('#case-2 button') 23 | .assert.containsText('#case-2 button', 'Expand is False') 24 | .assert.containsText('.count-a', 'countA: 1') 25 | .assert.containsText('.count-b', 'countB: 0') 26 | 27 | .click('#case-2 button') 28 | .assert.containsText('#case-2 button', 'Expand is True') 29 | .assert.containsText('.count-a', 'countA: 1') 30 | .assert.containsText('.count-b', 'countB: 1') 31 | 32 | .end() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/basic-ssr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
wtf
12 | 13 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/basic-ssr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'basic SSR': function (browser) { 3 | browser 4 | .url('http://localhost:8080/test/e2e/specs/basic-ssr.html') 5 | .assert.containsText('#result', '
foo
') 6 | .end() 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/commits.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'commits': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/commits/') 5 | .waitForElementVisible('li', 5000) 6 | .assert.count('input', 2) 7 | .assert.count('label', 2) 8 | .assert.containsText('label[for="master"]', 'master') 9 | .assert.containsText('label[for="dev"]', 'dev') 10 | .assert.checked('#master') 11 | .assert.checked('#dev', false) 12 | .assert.containsText('p', 'vuejs/vue@master') 13 | .assert.count('li', 3) 14 | .assert.count('li .commit', 3) 15 | .assert.count('li .message', 3) 16 | .click('#dev') 17 | .assert.containsText('p', 'vuejs/vue@dev') 18 | .assert.count('li', 3) 19 | .assert.count('li .commit', 3) 20 | .assert.count('li .message', 3) 21 | .end() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/markdown.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'markdown': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/markdown/') 5 | .waitForElementVisible('#editor', 1000) 6 | .assert.value('textarea', '# hello') 7 | .assert.hasHTML('#editor div', '

hello

') 8 | .setValue('textarea', '\n## foo\n\n- bar\n- baz') 9 | // assert the output is not updated yet because of debounce 10 | .assert.hasHTML('#editor div', '

hello

') 11 | .waitFor(500) 12 | .assert.hasHTML('#editor div', 13 | '

hello

\n' + 14 | '

foo

\n' + 15 | '
    \n
  • bar
  • \n
  • baz
  • \n
' 16 | ) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/e2e/specs/modal.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'modal': function (browser) { 3 | browser 4 | .url('http://localhost:8080/examples/modal/') 5 | .waitForElementVisible('#app', 1000) 6 | .assert.elementNotPresent('.modal-mask') 7 | .click('#show-modal') 8 | .assert.elementPresent('.modal-mask') 9 | .assert.elementPresent('.modal-wrapper') 10 | .assert.elementPresent('.modal-container') 11 | .waitFor(50) 12 | .assert.cssClassPresent('.modal-mask', 'modal-enter-active') 13 | .waitFor(300) 14 | .assert.cssClassNotPresent('.modal-mask', 'modal-enter-active') 15 | .assert.containsText('.modal-header h3', 'custom header') 16 | .assert.containsText('.modal-body', 'default body') 17 | .assert.containsText('.modal-footer', 'default footer') 18 | .click('.modal-default-button') 19 | // should have transition 20 | .assert.elementPresent('.modal-mask') 21 | .waitFor(50) 22 | .assert.cssClassPresent('.modal-mask', 'modal-leave-active') 23 | .waitFor(300) 24 | .assert.elementNotPresent('.modal-mask') 25 | .end() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "waitForUpdate": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/classlist.js: -------------------------------------------------------------------------------- 1 | beforeEach(() => { 2 | jasmine.addMatchers({ 3 | // since classList may not be supported in all browsers 4 | toHaveClass: () => { 5 | return { 6 | compare: (el, cls) => { 7 | const pass = el.classList 8 | ? el.classList.contains(cls) 9 | : el.getAttribute('class').split(/\s+/g).indexOf(cls) > -1 10 | return { 11 | pass, 12 | message: `Expected element${pass ? ' ' : ' not '}to have class ${cls}` 13 | } 14 | } 15 | } 16 | } 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/test-object-option.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default function testObjectOption (name) { 4 | it(`Options ${name}: should warn non object value`, () => { 5 | const options = {} 6 | options[name] = () => {} 7 | new Vue(options) 8 | expect(`Invalid value for option "${name}"`).toHaveBeenWarned() 9 | }) 10 | 11 | it(`Options ${name}: should not warn valid object value`, () => { 12 | const options = {} 13 | options[name] = {} 14 | new Vue(options) 15 | expect(`Invalid value for option "${name}"`).not.toHaveBeenWarned() 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/to-equal.js: -------------------------------------------------------------------------------- 1 | import { isEqual } from 'lodash' 2 | 3 | beforeEach(() => { 4 | jasmine.addMatchers({ 5 | // override built-in toEqual because it behaves incorrectly 6 | // on Vue-observed arrays in Safari 7 | toEqual: () => { 8 | return { 9 | compare: (a, b) => { 10 | const pass = isEqual(a, b) 11 | return { 12 | pass, 13 | message: `Expected ${a} to equal ${b}` 14 | } 15 | } 16 | } 17 | } 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/to-have-been-warned.js: -------------------------------------------------------------------------------- 1 | function noop () {} 2 | 3 | if (typeof console === 'undefined') { 4 | window.console = { 5 | warn: noop, 6 | error: noop 7 | } 8 | } 9 | 10 | // avoid info messages during test 11 | console.info = noop 12 | 13 | let asserted 14 | 15 | function createCompareFn (spy) { 16 | const hasWarned = msg => { 17 | var count = spy.calls.count() 18 | var args 19 | while (count--) { 20 | args = spy.calls.argsFor(count) 21 | if (args.some(containsMsg)) { 22 | return true 23 | } 24 | } 25 | 26 | function containsMsg (arg) { 27 | return arg.toString().indexOf(msg) > -1 28 | } 29 | } 30 | 31 | return { 32 | compare: msg => { 33 | asserted = asserted.concat(msg) 34 | var warned = Array.isArray(msg) 35 | ? msg.some(hasWarned) 36 | : hasWarned(msg) 37 | return { 38 | pass: warned, 39 | message: warned 40 | ? 'Expected message "' + msg + '" not to have been warned' 41 | : 'Expected message "' + msg + '" to have been warned' 42 | } 43 | } 44 | } 45 | } 46 | 47 | // define custom matcher for warnings 48 | beforeEach(() => { 49 | asserted = [] 50 | spyOn(console, 'warn') 51 | spyOn(console, 'error') 52 | jasmine.addMatchers({ 53 | toHaveBeenWarned: () => createCompareFn(console.error), 54 | toHaveBeenTipped: () => createCompareFn(console.warn) 55 | }) 56 | }) 57 | 58 | afterEach(done => { 59 | const warned = msg => asserted.some(assertedMsg => msg.toString().indexOf(assertedMsg) > -1) 60 | let count = console.error.calls.count() 61 | let args 62 | while (count--) { 63 | args = console.error.calls.argsFor(count) 64 | if (!warned(args[0])) { 65 | done.fail(`Unexpected console.error message: ${args[0]}`) 66 | return 67 | } 68 | } 69 | done() 70 | }) 71 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/trigger-event.js: -------------------------------------------------------------------------------- 1 | window.triggerEvent = function triggerEvent (target, event, process) { 2 | var e = document.createEvent('HTMLEvents') 3 | e.initEvent(event, true, true) 4 | if (process) process(e) 5 | target.dispatchEvent(e) 6 | } 7 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/vdom.js: -------------------------------------------------------------------------------- 1 | import VNode from 'core/vdom/vnode' 2 | 3 | window.createTextVNode = function (text) { 4 | return new VNode(undefined, undefined, undefined, text) 5 | } 6 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/helpers/wait-for-update.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | // helper for async assertions. 4 | // Use like this: 5 | // 6 | // vm.a = 123 7 | // waitForUpdate(() => { 8 | // expect(vm.$el.textContent).toBe('123') 9 | // vm.a = 234 10 | // }) 11 | // .then(() => { 12 | // // more assertions... 13 | // }) 14 | // .then(done) 15 | window.waitForUpdate = initialCb => { 16 | let end 17 | const queue = initialCb ? [initialCb] : [] 18 | 19 | function shift () { 20 | const job = queue.shift() 21 | if (queue.length) { 22 | let hasError = false 23 | try { 24 | job.wait ? job(shift) : job() 25 | } catch (e) { 26 | hasError = true 27 | const done = queue[queue.length - 1] 28 | if (done && done.fail) { 29 | done.fail(e) 30 | } 31 | } 32 | if (!hasError && !job.wait) { 33 | if (queue.length) { 34 | Vue.nextTick(shift) 35 | } 36 | } 37 | } else if (job && (job.fail || job === end)) { 38 | job() // done 39 | } 40 | } 41 | 42 | Vue.nextTick(() => { 43 | if (!queue.length || (!end && !queue[queue.length - 1].fail)) { 44 | throw new Error('waitForUpdate chain is missing .then(done)') 45 | } 46 | shift() 47 | }) 48 | 49 | const chainer = { 50 | then: nextCb => { 51 | queue.push(nextCb) 52 | return chainer 53 | }, 54 | thenWaitFor: (wait) => { 55 | if (typeof wait === 'number') { 56 | wait = timeout(wait) 57 | } 58 | wait.wait = true 59 | queue.push(wait) 60 | return chainer 61 | }, 62 | end: endFn => { 63 | queue.push(endFn) 64 | end = endFn 65 | } 66 | } 67 | 68 | return chainer 69 | } 70 | 71 | function timeout (n) { 72 | return next => setTimeout(next, n) 73 | } 74 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/async-loader.js: -------------------------------------------------------------------------------- 1 | const hash = require('hash-sum') 2 | 3 | module.exports = function (code) { 4 | const id = hash(this.request) // simulating vue-loader module id injection 5 | return code.replace('__MODULE_ID__', id) 6 | } 7 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/compile-with-webpack.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import webpack from 'webpack' 3 | import MemoryFS from 'memory-fs' 4 | 5 | export function compileWithWebpack (file, extraConfig, cb) { 6 | const config = Object.assign({ 7 | entry: path.resolve(__dirname, 'fixtures', file), 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.js$/, 12 | loader: 'babel-loader' 13 | }, 14 | { 15 | test: /async-.*\.js$/, 16 | loader: require.resolve('./async-loader') 17 | }, 18 | { 19 | test: /\.(png|woff2|css)$/, 20 | loader: 'file-loader', 21 | options: { 22 | name: '[name].[ext]' 23 | } 24 | } 25 | ] 26 | } 27 | }, extraConfig) 28 | 29 | const compiler = webpack(config) 30 | const fs = new MemoryFS() 31 | compiler.outputFileSystem = fs 32 | 33 | compiler.run((err, stats) => { 34 | expect(err).toBeFalsy() 35 | expect(stats.errors).toBeFalsy() 36 | cb(fs) 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/app.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | export default context => { 4 | return new Promise(resolve => { 5 | context.msg = 'hello' 6 | resolve(new Vue({ 7 | render (h) { 8 | return h('div', context.url) 9 | } 10 | })) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/async-bar.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | beforeCreate () { 3 | this.$vnode.ssrContext._registeredComponents.add('__MODULE_ID__') 4 | }, 5 | render (h) { 6 | return h('div', 'async bar') 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/async-foo.js: -------------------------------------------------------------------------------- 1 | // import image and font 2 | import './test.css' 3 | import font from './test.woff2' 4 | import image from './test.png' 5 | 6 | module.exports = { 7 | beforeCreate () { 8 | this.$vnode.ssrContext._registeredComponents.add('__MODULE_ID__') 9 | }, 10 | render (h) { 11 | return h('div', `async ${font} ${image}`) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/cache.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | const app = { 4 | name: 'app', 5 | props: ['id'], 6 | serverCacheKey: props => props.id, 7 | render (h) { 8 | return h('div', '/test') 9 | } 10 | } 11 | 12 | export default () => { 13 | return Promise.resolve(new Vue({ 14 | render: h => h(app, { props: { id: 1 }}) 15 | })) 16 | } 17 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/error.js: -------------------------------------------------------------------------------- 1 | throw new Error('foo') 2 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/nested-cache.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | function createRegisterFn (id) { 4 | return function (context) { 5 | context = context || this.$vnode.ssrContext 6 | context.registered.push(id) 7 | } 8 | } 9 | 10 | function addHooks (comp) { 11 | const hook = createRegisterFn(comp.name) 12 | return Object.assign(comp, { 13 | _ssrRegister: hook, 14 | beforeCreate: hook 15 | }) 16 | } 17 | 18 | const grandchild = addHooks({ 19 | name: 'grandchild', 20 | props: ['id'], 21 | serverCacheKey: props => props.id, 22 | render (h) { 23 | return h('div', '/test') 24 | } 25 | }) 26 | 27 | const child = addHooks({ 28 | name: 'child', 29 | props: ['id'], 30 | serverCacheKey: props => props.id, 31 | render (h) { 32 | return h(grandchild, { props: { id: this.id }}) 33 | } 34 | }) 35 | 36 | const app = addHooks({ 37 | name: 'app', 38 | props: ['id'], 39 | serverCacheKey: props => props.id, 40 | render (h) { 41 | return h(child, { props: { id: this.id }}) 42 | } 43 | }) 44 | 45 | export default () => { 46 | return Promise.resolve(new Vue({ 47 | render: h => h(app, { props: { id: 1 }}) 48 | })) 49 | } 50 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/promise-rejection.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | return Promise.reject(new Error('foo')) 3 | } 4 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/split.js: -------------------------------------------------------------------------------- 1 | import Vue from '../../../dist/vue.runtime.common.js' 2 | 3 | // async component! 4 | const Foo = () => import('./async-foo') 5 | const Bar = () => import('./async-bar') // eslint-disable-line 6 | 7 | export default context => { 8 | return new Promise(resolve => { 9 | context.msg = 'hello' 10 | const vm = new Vue({ 11 | render (h) { 12 | return h('div', [ 13 | context.url, 14 | h(Foo) 15 | ]) 16 | } 17 | }) 18 | 19 | // simulate router.onReady 20 | Foo().then(comp => { 21 | // resolve now to make the render sync 22 | Foo.resolved = Vue.extend(comp) 23 | resolve(vm) 24 | }) 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/test.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/带注释的Vue源码/vue/test/ssr/fixtures/test.css -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/带注释的Vue源码/vue/test/ssr/fixtures/test.png -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/fixtures/test.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/带注释的Vue源码/vue/test/ssr/fixtures/test.woff2 -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/ssr/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test/ssr", 3 | "spec_files": [ 4 | "*.spec.js" 5 | ], 6 | "helpers": [ 7 | "../../node_modules/babel-register/lib/node.js" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "waitForUpdate": true, 7 | "triggerEvent": true, 8 | "createTextVNode": true 9 | }, 10 | "plugins": ["jasmine"], 11 | "rules": { 12 | "jasmine/no-focused-tests": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/cloak.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-cloak', () => { 4 | it('should be removed after compile', () => { 5 | const el = document.createElement('div') 6 | el.setAttribute('v-cloak', '') 7 | const vm = new Vue({ el }) 8 | expect(vm.$el.hasAttribute('v-cloak')).toBe(false) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/model-file.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-model file', () => { 4 | it('warn to use @change instead', () => { 5 | new Vue({ 6 | data: { 7 | file: '' 8 | }, 9 | template: '' 10 | }).$mount() 11 | expect('Use a v-on:change listener instead').toHaveBeenWarned() 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/model-parse.spec.js: -------------------------------------------------------------------------------- 1 | import { parseModel } from 'compiler/directives/model' 2 | 3 | describe('model expression parser', () => { 4 | it('parse single path', () => { 5 | const res = parseModel('foo') 6 | expect(res.exp).toBe('foo') 7 | expect(res.key).toBe(null) 8 | }) 9 | 10 | it('parse object dot notation', () => { 11 | const res = parseModel('a.b.c') 12 | expect(res.exp).toBe('a.b') 13 | expect(res.key).toBe('"c"') 14 | }) 15 | 16 | it('parse string in brackets', () => { 17 | const res = parseModel('a["b"][c]') 18 | expect(res.exp).toBe('a["b"]') 19 | expect(res.key).toBe('c') 20 | }) 21 | 22 | it('parse brackets with object dot notation', () => { 23 | const res = parseModel('a["b"][c].xxx') 24 | expect(res.exp).toBe('a["b"][c]') 25 | expect(res.key).toBe('"xxx"') 26 | }) 27 | 28 | it('parse nested brackets', () => { 29 | const res = parseModel('a[i[c]]') 30 | expect(res.exp).toBe('a') 31 | expect(res.key).toBe('i[c]') 32 | }) 33 | 34 | it('combined', () => { 35 | const res = parseModel('test.xxx.a["asa"][test1[key]]') 36 | expect(res.exp).toBe('test.xxx.a["asa"]') 37 | expect(res.key).toBe('test1[key]') 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/pre.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-pre', function () { 4 | it('should not compile inner content', function () { 5 | const vm = new Vue({ 6 | template: `
7 |
{{ a }}
8 |
{{ a }}
9 |
10 | 11 |
12 |
`, 13 | data: { 14 | a: 123 15 | } 16 | }) 17 | vm.$mount() 18 | expect(vm.$el.firstChild.textContent).toBe('{{ a }}') 19 | expect(vm.$el.children[1].textContent).toBe('123') 20 | expect(vm.$el.lastChild.innerHTML).toBe('') 21 | }) 22 | 23 | it('should not compile on root node', function () { 24 | const vm = new Vue({ 25 | template: '
{{ a }}
', 26 | replace: true, 27 | data: { 28 | a: 123 29 | } 30 | }) 31 | vm.$mount() 32 | expect(vm.$el.firstChild.textContent).toBe('{{ a }}') 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/static-style-parser.spec.js: -------------------------------------------------------------------------------- 1 | import { parseStyleText } from 'web/util/style' 2 | const base64ImgUrl = 'url("data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==")' 3 | const logoUrl = 'url(https://vuejs.org/images/logo.png)' 4 | 5 | it('should parse normal static style', () => { 6 | const staticStyle = `font-size: 12px;background: ${logoUrl};color:red` 7 | const res = parseStyleText(staticStyle) 8 | expect(res.background).toBe(logoUrl) 9 | expect(res.color).toBe('red') 10 | expect(res['font-size']).toBe('12px') 11 | }) 12 | 13 | it('should parse base64 background', () => { 14 | const staticStyle = `background: ${base64ImgUrl}` 15 | const res = parseStyleText(staticStyle) 16 | expect(res.background).toBe(base64ImgUrl) 17 | }) 18 | 19 | it('should parse multiple background images ', () => { 20 | let staticStyle = `background: ${logoUrl}, ${logoUrl};` 21 | let res = parseStyleText(staticStyle) 22 | expect(res.background).toBe(`${logoUrl}, ${logoUrl}`) 23 | 24 | staticStyle = `background: ${base64ImgUrl}, ${base64ImgUrl}` 25 | res = parseStyleText(staticStyle) 26 | expect(res.background).toBe(`${base64ImgUrl}, ${base64ImgUrl}`) 27 | }) 28 | 29 | it('should parse other images ', () => { 30 | let staticStyle = `shape-outside: ${logoUrl}` 31 | let res = parseStyleText(staticStyle) 32 | expect(res['shape-outside']).toBe(logoUrl) 33 | 34 | staticStyle = `list-style-image: ${logoUrl}` 35 | res = parseStyleText(staticStyle) 36 | expect(res['list-style-image']).toBe(logoUrl) 37 | 38 | staticStyle = `border-image: ${logoUrl} 30 30 repeat` 39 | res = parseStyleText(staticStyle) 40 | expect(res['border-image']).toBe(`${logoUrl} 30 30 repeat`) 41 | }) 42 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/directives/text.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Directive v-text', () => { 4 | it('should render text', () => { 5 | const vm = new Vue({ 6 | template: '
', 7 | data: { a: 'hello' } 8 | }).$mount() 9 | expect(vm.$el.innerHTML).toBe('hello') 10 | }) 11 | 12 | it('should encode html entities', () => { 13 | const vm = new Vue({ 14 | template: '
', 15 | data: { a: '' } 16 | }).$mount() 17 | expect(vm.$el.innerHTML).toBe('<foo>') 18 | }) 19 | 20 | it('should support all value types', done => { 21 | const vm = new Vue({ 22 | template: '
', 23 | data: { a: false } 24 | }).$mount() 25 | waitForUpdate(() => { 26 | expect(vm.$el.innerHTML).toBe('false') 27 | vm.a = [] 28 | }).then(() => { 29 | expect(vm.$el.innerHTML).toBe('[]') 30 | vm.a = {} 31 | }).then(() => { 32 | expect(vm.$el.innerHTML).toBe('{}') 33 | vm.a = 123 34 | }).then(() => { 35 | expect(vm.$el.innerHTML).toBe('123') 36 | vm.a = 0 37 | }).then(() => { 38 | expect(vm.$el.innerHTML).toBe('0') 39 | vm.a = ' ' 40 | }).then(() => { 41 | expect(vm.$el.innerHTML).toBe(' ') 42 | vm.a = ' ' 43 | }).then(() => { 44 | expect(vm.$el.innerHTML).toBe(' ') 45 | vm.a = null 46 | }).then(() => { 47 | expect(vm.$el.innerHTML).toBe('') 48 | vm.a = undefined 49 | }).then(() => { 50 | expect(vm.$el.innerHTML).toBe('') 51 | }).then(done) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/global-api/compile.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Global API: compile', () => { 4 | it('should compile render functions', () => { 5 | const res = Vue.compile('
{{ msg }}
') 6 | const vm = new Vue({ 7 | data: { 8 | msg: 'hello' 9 | }, 10 | render: res.render, 11 | staticRenderFns: res.staticRenderFns 12 | }).$mount() 13 | expect(vm.$el.innerHTML).toContain('hello') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/global-api/use.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Global API: use', () => { 4 | const def = {} 5 | const options = {} 6 | const pluginStub = { 7 | install: (Vue, opts) => { 8 | Vue.directive('plugin-test', def) 9 | expect(opts).toBe(options) 10 | } 11 | } 12 | 13 | it('should apply Object plugin', () => { 14 | Vue.use(pluginStub, options) 15 | expect(Vue.options.directives['plugin-test']).toBe(def) 16 | delete Vue.options.directives['plugin-test'] 17 | expect(Vue.options.directives['plugin-test']).toBeUndefined() 18 | 19 | // should not double apply 20 | Vue.use(pluginStub, options) 21 | expect(Vue.options.directives['plugin-test']).toBeUndefined() 22 | }) 23 | 24 | it('should apply Function plugin', () => { 25 | Vue.use(pluginStub.install, options) 26 | expect(Vue.options.directives['plugin-test']).toBe(def) 27 | delete Vue.options.directives['plugin-test'] 28 | }) 29 | 30 | it('should work on extended constructors without polluting the base', () => { 31 | const Ctor = Vue.extend({}) 32 | Ctor.use(pluginStub, options) 33 | expect(Vue.options.directives['plugin-test']).toBeUndefined() 34 | expect(Ctor.options.directives['plugin-test']).toBe(def) 35 | }) 36 | 37 | // GitHub issue #5970 38 | it('should work on multi version', () => { 39 | const Ctor1 = Vue.extend({}) 40 | const Ctor2 = Vue.extend({}) 41 | 42 | Ctor1.use(pluginStub, options) 43 | expect(Vue.options.directives['plugin-test']).toBeUndefined() 44 | expect(Ctor1.options.directives['plugin-test']).toBe(def) 45 | 46 | // multi version Vue Ctor with the same cid 47 | Ctor2.cid = Ctor1.cid 48 | Ctor2.use(pluginStub, options) 49 | expect(Vue.options.directives['plugin-test']).toBeUndefined() 50 | expect(Ctor2.options.directives['plugin-test']).toBe(def) 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/instance/init.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Initialization', () => { 4 | it('without new', () => { 5 | try { Vue() } catch (e) {} 6 | expect('Vue is a constructor and should be called with the `new` keyword').toHaveBeenWarned() 7 | }) 8 | 9 | it('with new', () => { 10 | expect(new Vue() instanceof Vue).toBe(true) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/instance/render-proxy.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | if (typeof Proxy !== 'undefined') { 4 | describe('render proxy', () => { 5 | it('should warn missing property in render fns with `with`', () => { 6 | new Vue({ 7 | template: `
{{ a }}
` 8 | }).$mount() 9 | expect(`Property or method "a" is not defined`).toHaveBeenWarned() 10 | }) 11 | 12 | it('should warn missing property in render fns without `with`', () => { 13 | const render = function (h) { 14 | return h('div', [this.a]) 15 | } 16 | render._withStripped = true 17 | new Vue({ 18 | render 19 | }).$mount() 20 | expect(`Property or method "a" is not defined`).toHaveBeenWarned() 21 | }) 22 | 23 | it('should not warn for hand-written render functions', () => { 24 | new Vue({ 25 | render (h) { 26 | return h('div', [this.a]) 27 | } 28 | }).$mount() 29 | expect(`Property or method "a" is not defined`).not.toHaveBeenWarned() 30 | }) 31 | 32 | it('support symbols using the `in` operator in hand-written render functions', () => { 33 | const sym = Symbol() 34 | 35 | const vm = new Vue({ 36 | created () { 37 | this[sym] = 'foo' 38 | }, 39 | render (h) { 40 | if (sym in this) { 41 | return h('div', [this[sym]]) 42 | } 43 | } 44 | }).$mount() 45 | 46 | expect(vm.$el.textContent).toBe('foo') 47 | }) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/comments.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Comments', () => { 4 | it('comments should be kept', () => { 5 | const vm = new Vue({ 6 | comments: true, 7 | data () { 8 | return { 9 | foo: 1 10 | } 11 | }, 12 | template: '
node1{{foo}}
' 13 | }).$mount() 14 | expect(vm.$el.innerHTML).toEqual('node11') 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/extends.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { nativeWatch } from 'core/util/env' 3 | 4 | describe('Options extends', () => { 5 | it('should work on objects', () => { 6 | const A = { 7 | data () { 8 | return { a: 1 } 9 | } 10 | } 11 | const B = { 12 | extends: A, 13 | data () { 14 | return { b: 2 } 15 | } 16 | } 17 | const vm = new Vue({ 18 | extends: B, 19 | data: { 20 | c: 3 21 | } 22 | }) 23 | expect(vm.a).toBe(1) 24 | expect(vm.b).toBe(2) 25 | expect(vm.c).toBe(3) 26 | }) 27 | 28 | it('should work on extended constructors', () => { 29 | const A = Vue.extend({ 30 | data () { 31 | return { a: 1 } 32 | } 33 | }) 34 | const B = Vue.extend({ 35 | extends: A, 36 | data () { 37 | return { b: 2 } 38 | } 39 | }) 40 | const vm = new Vue({ 41 | extends: B, 42 | data: { 43 | c: 3 44 | } 45 | }) 46 | expect(vm.a).toBe(1) 47 | expect(vm.b).toBe(2) 48 | expect(vm.c).toBe(3) 49 | }) 50 | 51 | if (nativeWatch) { 52 | it('should work with global mixins + Object.prototype.watch', done => { 53 | Vue.mixin({}) 54 | 55 | const spy = jasmine.createSpy('watch') 56 | const A = Vue.extend({ 57 | data: function () { 58 | return { a: 1 } 59 | }, 60 | watch: { 61 | a: spy 62 | }, 63 | created: function () { 64 | this.a = 2 65 | } 66 | }) 67 | new Vue({ 68 | extends: A 69 | }) 70 | waitForUpdate(() => { 71 | expect(spy).toHaveBeenCalledWith(2, 1) 72 | }).then(done) 73 | }) 74 | } 75 | }) 76 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/inheritAttrs.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options inheritAttrs', () => { 4 | it('should work', done => { 5 | const vm = new Vue({ 6 | template: ``, 7 | data: { foo: 'foo' }, 8 | components: { 9 | foo: { 10 | inheritAttrs: false, 11 | template: `
foo
` 12 | } 13 | } 14 | }).$mount() 15 | expect(vm.$el.id).toBe('') 16 | vm.foo = 'bar' 17 | waitForUpdate(() => { 18 | expect(vm.$el.id).toBe('') 19 | }).then(done) 20 | }) 21 | 22 | it('with inner v-bind', done => { 23 | const vm = new Vue({ 24 | template: ``, 25 | data: { foo: 'foo' }, 26 | components: { 27 | foo: { 28 | inheritAttrs: false, 29 | template: `
` 30 | } 31 | } 32 | }).$mount() 33 | expect(vm.$el.children[0].id).toBe('foo') 34 | vm.foo = 'bar' 35 | waitForUpdate(() => { 36 | expect(vm.$el.children[0].id).toBe('bar') 37 | }).then(done) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/methods.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import testObjectOption from '../../../helpers/test-object-option' 3 | 4 | describe('Options methods', () => { 5 | testObjectOption('methods') 6 | 7 | it('should have correct context', () => { 8 | const vm = new Vue({ 9 | data: { 10 | a: 1 11 | }, 12 | methods: { 13 | plus () { 14 | this.a++ 15 | } 16 | } 17 | }) 18 | vm.plus() 19 | expect(vm.a).toBe(2) 20 | }) 21 | 22 | it('should warn undefined methods', () => { 23 | new Vue({ 24 | methods: { 25 | hello: undefined 26 | } 27 | }) 28 | expect(`Method "hello" has an undefined value in the component definition`).toHaveBeenWarned() 29 | }) 30 | 31 | it('should warn methods conflicting with data', () => { 32 | new Vue({ 33 | data: { 34 | foo: 1 35 | }, 36 | methods: { 37 | foo () {} 38 | } 39 | }) 40 | expect(`Method "foo" has already been defined as a data property`).toHaveBeenWarned() 41 | }) 42 | 43 | it('should warn methods conflicting with internal methods', () => { 44 | new Vue({ 45 | methods: { 46 | _update () {} 47 | } 48 | }) 49 | expect(`Method "_update" conflicts with an existing Vue instance method`).toHaveBeenWarned() 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/name.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options name', () => { 4 | it('should contain itself in self components', () => { 5 | const vm = Vue.extend({ 6 | name: 'SuperVue' 7 | }) 8 | 9 | expect(vm.options.components['SuperVue']).toEqual(vm) 10 | }) 11 | 12 | it('should warn when incorrect name given', () => { 13 | Vue.extend({ 14 | name: 'Hyper*Vue' 15 | }) 16 | 17 | /* eslint-disable */ 18 | expect(`Invalid component name: "Hyper*Vue". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) 19 | .toHaveBeenWarned() 20 | /* eslint-enable */ 21 | 22 | Vue.extend({ 23 | name: '2Cool2BValid' 24 | }) 25 | 26 | /* eslint-disable */ 27 | expect(`Invalid component name: "2Cool2BValid". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) 28 | .toHaveBeenWarned() 29 | /* eslint-enable */ 30 | }) 31 | 32 | it('id should not override given name when using Vue.component', () => { 33 | const SuperComponent = Vue.component('super-component', { 34 | name: 'SuperVue' 35 | }) 36 | 37 | expect(SuperComponent.options.components['SuperVue']).toEqual(SuperComponent) 38 | expect(SuperComponent.options.components['super-component']).toEqual(SuperComponent) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/parent.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options parent', () => { 4 | it('should work', () => { 5 | const parent = new Vue({ 6 | render () {} 7 | }).$mount() 8 | 9 | const child = new Vue({ 10 | parent: parent, 11 | render () {} 12 | }).$mount() 13 | 14 | // this option is straight-forward 15 | // it should register 'parent' as a $parent for 'child' 16 | // and push 'child' to $children array on 'parent' 17 | expect(child.$options.parent).toBeDefined() 18 | expect(child.$options.parent).toEqual(parent) 19 | expect(child.$parent).toBeDefined() 20 | expect(child.$parent).toEqual(parent) 21 | expect(parent.$children).toContain(child) 22 | 23 | // destroy 'child' and check if it was removed from 'parent' $children 24 | child.$destroy() 25 | expect(parent.$children.length).toEqual(0) 26 | parent.$destroy() 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/propsData.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options propsData', () => { 4 | it('should work', done => { 5 | const A = Vue.extend({ 6 | props: ['a'], 7 | template: '
{{ a }}
' 8 | }) 9 | const vm = new A({ 10 | propsData: { 11 | a: 123 12 | } 13 | }).$mount() 14 | expect(vm.a).toBe(123) 15 | expect(vm.$el.textContent).toBe('123') 16 | vm.a = 234 17 | waitForUpdate(() => { 18 | expect(vm.$el.textContent).toBe('234') 19 | }).then(done) 20 | }) 21 | 22 | it('warn non instantiation usage', () => { 23 | Vue.extend({ 24 | propsData: { 25 | a: 123 26 | } 27 | }) 28 | expect('option "propsData" can only be used during instance creation').toHaveBeenWarned() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/render.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options render', () => { 4 | it('basic usage', () => { 5 | const vm = new Vue({ 6 | render (h) { 7 | const children = [] 8 | for (let i = 0; i < this.items.length; i++) { 9 | children.push(h('li', { staticClass: 'task' }, [this.items[i].name])) 10 | } 11 | return h('ul', { staticClass: 'tasks' }, children) 12 | }, 13 | data: { 14 | items: [{ id: 1, name: 'task1' }, { id: 2, name: 'task2' }] 15 | } 16 | }).$mount() 17 | expect(vm.$el.tagName).toBe('UL') 18 | for (let i = 0; i < vm.$el.children.length; i++) { 19 | const li = vm.$el.children[i] 20 | expect(li.tagName).toBe('LI') 21 | expect(li.textContent).toBe(vm.items[i].name) 22 | } 23 | }) 24 | 25 | it('allow null data', () => { 26 | const vm = new Vue({ 27 | render (h) { 28 | return h('div', null, 'hello' /* string as children*/) 29 | } 30 | }).$mount() 31 | expect(vm.$el.tagName).toBe('DIV') 32 | expect(vm.$el.textContent).toBe('hello') 33 | }) 34 | 35 | it('should warn non `render` option and non `template` option', () => { 36 | new Vue().$mount() 37 | expect('Failed to mount component: template or render function not defined.').toHaveBeenWarned() 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/features/options/renderError.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | describe('Options renderError', () => { 4 | it('should be used on render errors', done => { 5 | Vue.config.errorHandler = () => {} 6 | const vm = new Vue({ 7 | data: { 8 | ok: true 9 | }, 10 | render (h) { 11 | if (this.ok) { 12 | return h('div', 'ok') 13 | } else { 14 | throw new Error('no') 15 | } 16 | }, 17 | renderError (h, err) { 18 | return h('div', err.toString()) 19 | } 20 | }).$mount() 21 | expect(vm.$el.textContent).toBe('ok') 22 | vm.ok = false 23 | waitForUpdate(() => { 24 | expect(vm.$el.textContent).toBe('Error: no') 25 | Vue.config.errorHandler = null 26 | }).then(done) 27 | }) 28 | 29 | it('should pass on errors in renderError to global handler', () => { 30 | const spy = Vue.config.errorHandler = jasmine.createSpy() 31 | const err = new Error('renderError') 32 | const vm = new Vue({ 33 | render () { 34 | throw new Error('render') 35 | }, 36 | renderError () { 37 | throw err 38 | } 39 | }).$mount() 40 | expect(spy).toHaveBeenCalledWith(err, vm, 'renderError') 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/index.js: -------------------------------------------------------------------------------- 1 | require('es6-promise/auto') 2 | 3 | // import all helpers 4 | const helpersContext = require.context('../helpers', true) 5 | helpersContext.keys().forEach(helpersContext) 6 | 7 | // require all test files 8 | const testsContext = require.context('./', true, /\.spec$/) 9 | testsContext.keys().forEach(testsContext) 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/karma.base.config.js: -------------------------------------------------------------------------------- 1 | var alias = require('../../scripts/alias') 2 | var webpack = require('webpack') 3 | 4 | var webpackConfig = { 5 | resolve: { 6 | alias: alias 7 | }, 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.js$/, 12 | loader: 'babel-loader', 13 | exclude: /node_modules/ 14 | } 15 | ] 16 | }, 17 | plugins: [ 18 | new webpack.DefinePlugin({ 19 | __WEEX__: false, 20 | 'process.env': { 21 | NODE_ENV: '"development"', 22 | TRANSITION_DURATION: process.env.CI ? 100 : 50, 23 | TRANSITION_BUFFER: 10 24 | } 25 | }) 26 | ], 27 | devtool: '#inline-source-map' 28 | } 29 | 30 | // shared config for all unit tests 31 | module.exports = { 32 | frameworks: ['jasmine'], 33 | files: [ 34 | './index.js' 35 | ], 36 | preprocessors: { 37 | './index.js': ['webpack', 'sourcemap'] 38 | }, 39 | webpack: webpackConfig, 40 | webpackMiddleware: { 41 | noInfo: true 42 | }, 43 | plugins: [ 44 | 'karma-jasmine', 45 | 'karma-mocha-reporter', 46 | 'karma-sourcemap-loader', 47 | 'karma-webpack' 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/karma.cover.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | var options = Object.assign(base, { 5 | browsers: ['PhantomJS'], 6 | reporters: ['mocha', 'coverage'], 7 | coverageReporter: { 8 | reporters: [ 9 | { type: 'lcov', dir: '../../coverage', subdir: '.' }, 10 | { type: 'text-summary', dir: '../../coverage', subdir: '.' } 11 | ] 12 | }, 13 | singleRun: true, 14 | plugins: base.plugins.concat([ 15 | 'karma-coverage', 16 | 'karma-phantomjs-launcher' 17 | ]) 18 | }) 19 | 20 | // add babel-plugin-istanbul for code instrumentation 21 | options.webpack.module.rules[0].options = { 22 | plugins: [['istanbul', { 23 | exclude: [ 24 | 'test/', 25 | 'src/compiler/parser/html-parser.js', 26 | 'src/core/instance/proxy.js', 27 | 'src/sfc/deindent.js', 28 | 'src/platforms/weex/' 29 | ] 30 | }]] 31 | } 32 | 33 | config.set(options) 34 | } 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/karma.dev.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set(Object.assign(base, { 5 | browsers: ['PhantomJS'], 6 | reporters: ['progress'], 7 | plugins: base.plugins.concat([ 8 | 'karma-phantomjs-launcher' 9 | ]) 10 | })) 11 | } 12 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/karma.unit.config.js: -------------------------------------------------------------------------------- 1 | var base = require('./karma.base.config.js') 2 | 3 | module.exports = function (config) { 4 | config.set(Object.assign(base, { 5 | browsers: ['Chrome', 'Firefox', 'Safari'], 6 | reporters: ['progress'], 7 | singleRun: true, 8 | plugins: base.plugins.concat([ 9 | 'karma-chrome-launcher', 10 | 'karma-firefox-launcher', 11 | 'karma-safari-launcher' 12 | ]) 13 | })) 14 | } 15 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/modules/observer/dep.spec.js: -------------------------------------------------------------------------------- 1 | import Dep from 'core/observer/dep' 2 | 3 | describe('Dep', () => { 4 | let dep 5 | 6 | beforeEach(() => { 7 | dep = new Dep() 8 | }) 9 | 10 | describe('instance', () => { 11 | it('should be created with correct properties', () => { 12 | expect(dep.subs.length).toBe(0) 13 | expect(new Dep().id).toBe(dep.id + 1) 14 | }) 15 | }) 16 | 17 | describe('addSub()', () => { 18 | it('should add sub', () => { 19 | dep.addSub(null) 20 | expect(dep.subs.length).toBe(1) 21 | expect(dep.subs[0]).toBe(null) 22 | }) 23 | }) 24 | 25 | describe('removeSub()', () => { 26 | it('should remove sub', () => { 27 | dep.subs.push(null) 28 | dep.removeSub(null) 29 | expect(dep.subs.length).toBe(0) 30 | }) 31 | }) 32 | 33 | describe('depend()', () => { 34 | let _target 35 | 36 | beforeAll(() => { 37 | _target = Dep.target 38 | }) 39 | 40 | afterAll(() => { 41 | Dep.target = _target 42 | }) 43 | 44 | it('should do nothing if no target', () => { 45 | Dep.target = null 46 | dep.depend() 47 | }) 48 | 49 | it('should add itself to target', () => { 50 | Dep.target = jasmine.createSpyObj('TARGET', ['addDep']) 51 | dep.depend() 52 | expect(Dep.target.addDep).toHaveBeenCalledWith(dep) 53 | }) 54 | }) 55 | 56 | describe('notify()', () => { 57 | it('should notify subs', () => { 58 | dep.subs.push(jasmine.createSpyObj('SUB', ['update'])) 59 | dep.notify() 60 | expect(dep.subs[0].update).toHaveBeenCalled() 61 | }) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/modules/server-compiler/optimizer.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18835596648/Learn-Vue-Source-Code/8a4461328999b3b862c0a03048daca79e7427aca/带注释的Vue源码/vue/test/unit/modules/server-compiler/optimizer.spec.js -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/modules/util/next-tick.spec.js: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'core/util/next-tick' 2 | 3 | describe('nextTick', () => { 4 | it('accepts a callback', done => { 5 | nextTick(done) 6 | }) 7 | 8 | it('returns undefined when passed a callback', () => { 9 | expect(nextTick(() => {})).toBeUndefined() 10 | }) 11 | 12 | if (typeof Promise !== 'undefined') { 13 | it('returns a Promise when provided no callback', done => { 14 | nextTick().then(done) 15 | }) 16 | 17 | it('returns a Promise with a context argument when provided a falsy callback and an object', done => { 18 | const obj = {} 19 | nextTick(undefined, obj).then(ctx => { 20 | expect(ctx).toBe(obj) 21 | done() 22 | }) 23 | }) 24 | 25 | it('returned Promise should resolve correctly vs callback', done => { 26 | const spy = jasmine.createSpy() 27 | nextTick(spy) 28 | nextTick().then(() => { 29 | expect(spy).toHaveBeenCalled() 30 | done() 31 | }) 32 | }) 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/modules/vdom/modules/directive.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { patch } from 'web/runtime/patch' 3 | import VNode from 'core/vdom/vnode' 4 | 5 | describe('vdom directive module', () => { 6 | it('should work', () => { 7 | const directive1 = { 8 | bind: jasmine.createSpy('bind'), 9 | update: jasmine.createSpy('update'), 10 | unbind: jasmine.createSpy('unbind') 11 | } 12 | const vm = new Vue({ directives: { directive1 }}) 13 | // create 14 | const vnode1 = new VNode('div', {}, [ 15 | new VNode('p', { 16 | directives: [{ 17 | name: 'directive1', value: 'hello', arg: 'arg1', modifiers: { modifier1: true } 18 | }] 19 | }, undefined, 'hello world', undefined, vm) 20 | ]) 21 | patch(null, vnode1) 22 | expect(directive1.bind).toHaveBeenCalled() 23 | // update 24 | const vnode2 = new VNode('div', {}, [ 25 | new VNode('p', { 26 | directives: [{ 27 | name: 'directive1', value: 'world', arg: 'arg1', modifiers: { modifier1: true } 28 | }] 29 | }, undefined, 'hello world', undefined, vm) 30 | ]) 31 | patch(vnode1, vnode2) 32 | expect(directive1.update).toHaveBeenCalled() 33 | // destroy 34 | const vnode3 = new VNode('div') 35 | patch(vnode2, vnode3) 36 | expect(directive1.unbind).toHaveBeenCalled() 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/unit/modules/vdom/modules/style.spec.js: -------------------------------------------------------------------------------- 1 | import { patch } from 'web/runtime/patch' 2 | import VNode from 'core/vdom/vnode' 3 | 4 | describe('vdom style module', () => { 5 | it('should create an element with style', () => { 6 | const vnode = new VNode('p', { style: { fontSize: '12px' }}) 7 | const elm = patch(null, vnode) 8 | expect(elm.style.fontSize).toBe('12px') 9 | }) 10 | 11 | it('should create an element with array style', () => { 12 | const vnode = new VNode('p', { style: [{ fontSize: '12px' }, { color: 'red' }] }) 13 | const elm = patch(null, vnode) 14 | expect(elm.style.fontSize).toBe('12px') 15 | expect(elm.style.color).toBe('red') 16 | }) 17 | 18 | it('should change elements style', () => { 19 | const vnode1 = new VNode('p', { style: { fontSize: '12px' }}) 20 | const vnode2 = new VNode('p', { style: { fontSize: '10px', display: 'block' }}) 21 | patch(null, vnode1) 22 | const elm = patch(vnode1, vnode2) 23 | expect(elm.style.fontSize).toBe('10px') 24 | expect(elm.style.display).toBe('block') 25 | }) 26 | 27 | it('should remove elements attrs', () => { 28 | const vnode1 = new VNode('p', { style: { fontSize: '12px' }}) 29 | const vnode2 = new VNode('p', { style: { display: 'block' }}) 30 | patch(null, vnode1) 31 | const elm = patch(vnode1, vnode2) 32 | expect(elm.style.fontSize).toBe('') 33 | expect(elm.style.display).toBe('block') 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "plugins": ["jasmine"], 6 | "rules": { 7 | "jasmine/no-focused-tests": 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/event/click.after.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | event: ['click'], 4 | children: [{ 5 | type: 'text', 6 | attr: { 7 | value: '43' 8 | } 9 | }] 10 | }) 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/event/click.before.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | event: ['click'], 4 | children: [{ 5 | type: 'text', 6 | attr: { 7 | value: '42' 8 | } 9 | }] 10 | }) 11 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/event/click.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/attrs.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', count: 1, source: 'http://whatever.com/x.png' }, 7 | { type: 'A', count: 2, source: 'http://whatever.com/y.png' }, 8 | { type: 'A', count: 3, source: 'http://whatever.com/z.png' } 9 | ], 10 | switch: 'type', 11 | alias: 'item' 12 | }, 13 | children: [{ 14 | type: 'cell-slot', 15 | attr: { append: 'tree', case: 'A' }, 16 | children: [{ 17 | type: 'image', 18 | attr: { 19 | resize: 'cover', 20 | src: { 21 | '@binding': 'item.source' 22 | } 23 | } 24 | }, { 25 | type: 'text', 26 | attr: { 27 | lines: '3', 28 | count: { 29 | '@binding': 'item.count' 30 | } 31 | } 32 | }] 33 | }] 34 | }) 35 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/attrs.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/classname.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', color: 'red' }, 7 | { type: 'A', color: 'blue' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | style: { 16 | backgroundColor: '#FF6600' 17 | }, 18 | children: [{ 19 | type: 'text', 20 | attr: { 21 | // not supported yet 22 | // classList: ['text', { '@binding': 'item.color' }], 23 | value: 'content' 24 | } 25 | }] 26 | }] 27 | }) 28 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/classname.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 37 | 38 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/banner.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/counter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 37 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/editor.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 32 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/footer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/lifecycle.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 40 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/poster.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful-lifecycle.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'X' }, 7 | { type: 'X' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'X' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': {} 20 | }, 21 | children: [{ 22 | type: 'text', 23 | attr: { 24 | value: { '@binding': 'number' } 25 | } 26 | }] 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful-lifecycle.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful-v-model.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | message: 'No binding' 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | classList: ['output'], 26 | attr: { 27 | value: { '@binding': 'output' } 28 | } 29 | }, { 30 | type: 'input', 31 | event: ['input'], 32 | classList: ['input'], 33 | attr: { 34 | type: 'text', 35 | value: 'No binding' 36 | } 37 | }] 38 | }] 39 | }] 40 | }) 41 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful-v-model.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', number: 24 }, 7 | { type: 'A', number: 42 } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | start: { '@binding': 'item.number' } 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | classList: ['output'], 26 | attr: { 27 | value: { '@binding': 'count' } // need confirm 28 | } 29 | }, { 30 | type: 'text', 31 | event: ['click'], 32 | classList: ['button'], 33 | attr: { value: '+' } 34 | }] 35 | }, { 36 | type: 'text', 37 | attr: { value: 'other' } 38 | }] 39 | }] 40 | }) 41 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateful.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateless-multi-components.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 31 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateless-with-props.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', poster: 'xx', title: 'x' }, 7 | { type: 'A', poster: 'yy', title: 'y' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': { 20 | imageUrl: { '@binding': 'item.poster' }, 21 | title: { '@binding': 'item.title' } 22 | } 23 | }, 24 | children: [{ 25 | type: 'image', 26 | classList: ['image'], 27 | attr: { 28 | src: { '@binding': 'imageUrl' } 29 | } 30 | }, { 31 | type: 'text', 32 | classList: ['title'], 33 | attr: { 34 | value: { '@binding': 'title' } 35 | } 36 | }] 37 | }, { 38 | type: 'text', 39 | attr: { 40 | value: 'content' 41 | } 42 | }] 43 | }] 44 | }) 45 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateless-with-props.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateless.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '@isComponentRoot': true, 19 | '@componentProps': {} 20 | }, 21 | classList: ['banner'], 22 | children: [{ 23 | type: 'text', 24 | classList: ['title'], 25 | attr: { 26 | value: 'BANNER' 27 | } 28 | }] 29 | }, { 30 | type: 'text', 31 | attr: { 32 | value: 'content' 33 | } 34 | }] 35 | }] 36 | }) 37 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/components/stateless.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/inline-style.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', color: '#606060' }, 7 | { type: 'A', color: '#E5E5E5' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | style: { 16 | backgroundColor: '#FF6600' 17 | }, 18 | children: [{ 19 | type: 'text', 20 | style: { 21 | fontSize: '100px', 22 | color: { '@binding': 'item.color' } 23 | }, 24 | attr: { 25 | value: 'content' 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/inline-style.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/text-node.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A', dynamic: 'decimal', two: '2', four: '4' }, 7 | { type: 'A', dynamic: 'binary', two: '10', four: '100' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | attr: { 18 | value: 'static' 19 | } 20 | }, { 21 | type: 'text', 22 | attr: { 23 | value: { '@binding': 'item.dynamic' } 24 | } 25 | }, { 26 | type: 'text', 27 | attr: { 28 | value: [ 29 | 'one ', 30 | { '@binding': 'item.two' }, 31 | ' three ', 32 | { '@binding': 'item.four' }, 33 | ' five' 34 | ] 35 | } 36 | }] 37 | }] 38 | }) 39 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/text-node.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-else-if.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.sourceA', 19 | src: { '@binding': 'item.sourceA' } 20 | } 21 | }, { 22 | type: 'image', 23 | attr: { 24 | '[[match]]': '!(item.sourceA) && (item.sourceB)', 25 | src: { '@binding': 'item.sourceB' } 26 | } 27 | }, { 28 | type: 'image', 29 | attr: { 30 | '[[match]]': '!(item.sourceA || item.sourceB)', 31 | src: { '@binding': 'item.placeholder' } 32 | } 33 | }] 34 | }] 35 | }) 36 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-else-if.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-else.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.source', 19 | src: { '@binding': 'item.source' } 20 | } 21 | }, { 22 | type: 'image', 23 | attr: { 24 | '[[match]]': '!(item.source)', 25 | src: { '@binding': 'item.placeholder' } 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-else.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-for-iterator.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '[[repeat]]': { 19 | '@expression': 'item.list', 20 | '@index': 'index', 21 | '@alias': 'object' 22 | } 23 | }, 24 | children: [{ 25 | type: 'text', 26 | attr: { 27 | value: { 28 | '@binding': 'object.name' 29 | } 30 | } 31 | }, { 32 | type: 'text', 33 | attr: { 34 | '[[repeat]]': { 35 | '@expression': 'object', 36 | '@alias': 'v', 37 | '@key': 'k', 38 | '@index': 'i' 39 | }, 40 | value: { 41 | '@binding': 'v' 42 | } 43 | } 44 | }] 45 | }] 46 | }] 47 | }) 48 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-for-iterator.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-for.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'div', 17 | attr: { 18 | '[[repeat]]': { 19 | '@expression': 'item.list', 20 | '@alias': 'panel' 21 | } 22 | }, 23 | children: [{ 24 | type: 'text', 25 | attr: { 26 | value: { 27 | '@binding': 'panel.label' 28 | } 29 | } 30 | }] 31 | }] 32 | }] 33 | }) 34 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-for.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-if.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'image', 17 | attr: { 18 | '[[match]]': 'item.source', 19 | src: { '@binding': 'item.source' } 20 | } 21 | }, { 22 | type: 'text', 23 | attr: { 24 | '[[match]]': '!item.source', 25 | value: 'Title' 26 | } 27 | }] 28 | }] 29 | }) 30 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-if.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-on-inline.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | event: ['click', { 18 | type: 'longpress', 19 | params: [{ '@binding': 'item.key' }] 20 | }] 21 | }, { 22 | type: 'text', 23 | event: [{ 24 | type: 'appear', 25 | params: [ 26 | { '@binding': 'item.index' }, 27 | { '@binding': 'item.type' } 28 | ] 29 | }], 30 | attr: { value: 'Button' } 31 | }, { 32 | type: 'text', 33 | event: [{ type: 'disappear' }], 34 | attr: { value: 'Tips' } 35 | }] 36 | }] 37 | }) 38 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-on-inline.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 28 | 29 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-on.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | switch: 'type', 10 | alias: 'item' 11 | }, 12 | children: [{ 13 | type: 'cell-slot', 14 | attr: { append: 'tree', case: 'A' }, 15 | children: [{ 16 | type: 'text', 17 | event: ['click', 'longpress'], 18 | attr: { value: 'A' } 19 | }, { 20 | type: 'text', 21 | event: ['touchend'], 22 | attr: { value: 'B' } 23 | }] 24 | }] 25 | }) 26 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-on.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 26 | 27 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-once.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'recycle-list', 3 | attr: { 4 | append: 'tree', 5 | listData: [ 6 | { type: 'A' }, 7 | { type: 'A' } 8 | ], 9 | alias: 'item' 10 | }, 11 | children: [{ 12 | type: 'cell-slot', 13 | attr: { append: 'tree' }, 14 | children: [{ 15 | type: 'text', 16 | attr: { 17 | '[[once]]': true, 18 | value: { '@binding': 'item.type' } 19 | } 20 | }] 21 | }] 22 | }) 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/recycle-list/v-once.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/render/sample.vdom.js: -------------------------------------------------------------------------------- 1 | ({ 2 | type: 'div', 3 | style: { 4 | justifyContent: 'center' 5 | }, 6 | children: [{ 7 | type: 'text', 8 | attr: { 9 | value: 'Yo' 10 | }, 11 | classList: ['freestyle'] 12 | }] 13 | }) 14 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/cases/render/sample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/compiler/props.spec.js: -------------------------------------------------------------------------------- 1 | import { compile } from '../../../packages/weex-template-compiler' 2 | import { strToRegExp } from '../helpers/index' 3 | 4 | describe('compile props', () => { 5 | it('custom props', () => { 6 | const { render, staticRenderFns, errors } = compile(`
`) 7 | expect(render).not.toBeUndefined() 8 | expect(staticRenderFns).not.toBeUndefined() 9 | expect(staticRenderFns.length).toEqual(0) 10 | expect(render).toMatch(strToRegExp(`attrs:{"custom":"whatever"}`)) 11 | expect(errors).toEqual([]) 12 | }) 13 | 14 | it('camelize props', () => { 15 | const { render, staticRenderFns, errors } = compile(`
`) 16 | expect(render).not.toBeUndefined() 17 | expect(staticRenderFns).not.toBeUndefined() 18 | expect(staticRenderFns.length).toEqual(0) 19 | expect(render).toMatch(strToRegExp(`attrs:{"kebabCase":"whatever"}`)) 20 | expect(errors).toEqual([]) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /带注释的Vue源码/vue/test/weex/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test/weex", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "../../node_modules/babel-register/lib/node.js" 8 | ] 9 | } 10 | --------------------------------------------------------------------------------