.'
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-src/platforms/web/compiler/util.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { makeMap } from 'shared/util'
4 | /*Github:https://github.com/answershuto*/
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 | /*Github:https://github.com/answershuto*/
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-src/platforms/web/runtime-with-compiler.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import config from 'core/config'
4 | import { warn, cached } from 'core/util/index'
5 | import { mark, measure } from 'core/util/perf'
6 |
7 | import Vue from './runtime/index'
8 | import { query } from './util/index'
9 | import { shouldDecodeNewlines } from './util/compat'
10 | import { compileToFunctions } from './compiler/index'
11 |
12 | /*根据id获取templete,即获取id对应的DOM,然后访问其innerHTML*/
13 | const idToTemplate = cached(id => {
14 | const el = query(id)
15 | return el && el.innerHTML
16 | })
17 |
18 | /*把原本不带编译的$mount方法保存下来,在最后会调用。*/
19 | const mount = Vue.prototype.$mount
20 | /*挂载组件,带模板编译*/
21 | Vue.prototype.$mount = function (
22 | el?: string | Element,
23 | hydrating?: boolean
24 | ): Component {
25 | el = el && query(el)
26 |
27 | /* istanbul ignore if */
28 | if (el === document.body || el === document.documentElement) {
29 | process.env.NODE_ENV !== 'production' && warn(
30 | `Do not mount Vue to or - mount to normal elements instead.`
31 | )
32 | return this
33 | }
34 |
35 | const options = this.$options
36 | // resolve template/el and convert to render function
37 | /*处理模板templete,编译成render函数,render不存在的时候才会编译template,否则优先使用render*/
38 | if (!options.render) {
39 | let template = options.template
40 | /*template存在的时候取template,不存在的时候取el的outerHTML*/
41 | if (template) {
42 | /*当template是字符串的时候*/
43 | if (typeof template === 'string') {
44 | if (template.charAt(0) === '#') {
45 | template = idToTemplate(template)
46 | /* istanbul ignore if */
47 | if (process.env.NODE_ENV !== 'production' && !template) {
48 | warn(
49 | `Template element not found or is empty: ${options.template}`,
50 | this
51 | )
52 | }
53 | }
54 | } else if (template.nodeType) {
55 | /*当template为DOM节点的时候*/
56 | template = template.innerHTML
57 | } else {
58 | /*报错*/
59 | if (process.env.NODE_ENV !== 'production') {
60 | warn('invalid template option:' + template, this)
61 | }
62 | return this
63 | }
64 | } else if (el) {
65 | /*获取element的outerHTML*/
66 | template = getOuterHTML(el)
67 | }
68 | if (template) {
69 | /* istanbul ignore if */
70 | if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
71 | mark('compile')
72 | }
73 |
74 | /*将template编译成render函数,这里会有render以及staticRenderFns两个返回,这是vue的编译时优化,static静态不需要在VNode更新时进行patch,优化性能*/
75 | const { render, staticRenderFns } = compileToFunctions(template, {
76 | shouldDecodeNewlines,
77 | delimiters: options.delimiters
78 | }, this)
79 | options.render = render
80 | options.staticRenderFns = staticRenderFns
81 |
82 | /* istanbul ignore if */
83 | if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
84 | mark('compile end')
85 | measure(`${this._name} compile`, 'compile', 'compile end')
86 | }
87 | }
88 | }
89 | /*调用const mount = Vue.prototype.$mount保存下来的不带编译的mount*/
90 | return mount.call(this, el, hydrating)
91 | }
92 |
93 | /**
94 | * Get outerHTML of elements, taking care
95 | * of SVG elements in IE as well.
96 | */
97 | /*获取element的outerHTML*/
98 | function getOuterHTML (el: Element): string {
99 | if (el.outerHTML) {
100 | return el.outerHTML
101 | } else {
102 | const container = document.createElement('div')
103 | container.appendChild(el.cloneNode(true))
104 | return container.innerHTML
105 | }
106 | }
107 |
108 | Vue.compile = compileToFunctions
109 | /*Github:https://github.com/answershuto*/
110 | export default Vue
111 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import Vue from './runtime/index'
4 | /*Github:https://github.com/answershuto*/
5 | export default Vue
6 |
--------------------------------------------------------------------------------
/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 | } else {
46 | let cur = ` ${el.getAttribute('class') || ''} `
47 | const tar = ' ' + cls + ' '
48 | while (cur.indexOf(tar) >= 0) {
49 | cur = cur.replace(tar, ' ')
50 | }
51 | el.setAttribute('class', cur.trim())
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/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-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-src/platforms/web/runtime/directives/show.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { isIE9 } from 'core/util/env'
4 | import { enter, leave } from '../modules/transition'
5 |
6 | // recursively search for possible transition defined inside the component root
7 | function locateNode (vnode: VNode): VNodeWithData {
8 | return vnode.componentInstance && (!vnode.data || !vnode.data.transition)
9 | ? locateNode(vnode.componentInstance._vnode)
10 | : vnode
11 | }
12 |
13 | export default {
14 | bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
15 | vnode = locateNode(vnode)
16 | const transition = vnode.data && vnode.data.transition
17 | const originalDisplay = el.__vOriginalDisplay =
18 | el.style.display === 'none' ? '' : el.style.display
19 | if (value && transition && !isIE9) {
20 | vnode.data.show = true
21 | enter(vnode, () => {
22 | el.style.display = originalDisplay
23 | })
24 | } else {
25 | el.style.display = value ? originalDisplay : 'none'
26 | }
27 | },
28 |
29 | update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) {
30 | /* istanbul ignore if */
31 | if (value === oldValue) return
32 | vnode = locateNode(vnode)
33 | const transition = vnode.data && vnode.data.transition
34 | if (transition && !isIE9) {
35 | vnode.data.show = true
36 | if (value) {
37 | enter(vnode, () => {
38 | el.style.display = el.__vOriginalDisplay
39 | })
40 | } else {
41 | leave(vnode, () => {
42 | el.style.display = 'none'
43 | })
44 | }
45 | } else {
46 | el.style.display = value ? el.__vOriginalDisplay : 'none'
47 | }
48 | },
49 |
50 | unbind (
51 | el: any,
52 | binding: VNodeDirective,
53 | vnode: VNodeWithData,
54 | oldVnode: VNodeWithData,
55 | isDestroy: boolean
56 | ) {
57 | if (!isDestroy) {
58 | el.style.display = el.__vOriginalDisplay
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime/index.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import Vue from 'core/index'
4 | import config from 'core/config'
5 | import { extend, noop } from 'shared/util'
6 | import { mountComponent } from 'core/instance/lifecycle'
7 | import { devtools, inBrowser, isChrome } from 'core/util/index'
8 |
9 | import {
10 | query,
11 | mustUseProp,
12 | isReservedTag,
13 | isReservedAttr,
14 | getTagNamespace,
15 | isUnknownElement
16 | } from 'web/util/index'
17 |
18 | import { patch } from './patch'
19 | import platformDirectives from './directives/index'
20 | import platformComponents from './components/index'
21 |
22 | // install platform specific utils
23 | Vue.config.mustUseProp = mustUseProp
24 | Vue.config.isReservedTag = isReservedTag
25 | Vue.config.isReservedAttr = isReservedAttr
26 | Vue.config.getTagNamespace = getTagNamespace
27 | Vue.config.isUnknownElement = isUnknownElement
28 |
29 | // install platform runtime directives & components
30 | extend(Vue.options.directives, platformDirectives)
31 | extend(Vue.options.components, platformComponents)
32 |
33 | // install platform patch function
34 | Vue.prototype.__patch__ = inBrowser ? patch : noop
35 |
36 | // public mount method
37 | /*组件挂载方法*/
38 | Vue.prototype.$mount = function (
39 | el?: string | Element,
40 | hydrating?: boolean
41 | ): Component {
42 | /*获取DOM实例对象*/
43 | el = el && inBrowser ? query(el) : undefined
44 | /*挂载组件*/
45 | return mountComponent(this, el, hydrating)
46 | }
47 |
48 | // devtools global hook
49 | /* istanbul ignore next */
50 | setTimeout(() => {
51 | if (config.devtools) {
52 | if (devtools) {
53 | devtools.emit('init', Vue)
54 | } else if (process.env.NODE_ENV !== 'production' && isChrome) {
55 | console[console.info ? 'info' : 'log'](
56 | 'Download the Vue Devtools extension for a better development experience:\n' +
57 | 'https://github.com/vuejs/vue-devtools'
58 | )
59 | }
60 | }
61 | if (process.env.NODE_ENV !== 'production' &&
62 | config.productionTip !== false &&
63 | inBrowser && typeof console !== 'undefined') {
64 | console[console.info ? 'info' : 'log'](
65 | `You are running Vue in development mode.\n` +
66 | `Make sure to turn on production mode when deploying for production.\n` +
67 | `See more tips at https://vuejs.org/guide/deployment.html`
68 | )
69 | }
70 | }, 0)
71 |
72 | export default Vue
73 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime/modules/attrs.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { isIE9 } from 'core/util/env'
4 |
5 | import {
6 | extend,
7 | isDef,
8 | isUndef
9 | } from 'shared/util'
10 |
11 | import {
12 | isXlink,
13 | xlinkNS,
14 | getXlinkProp,
15 | isBooleanAttr,
16 | isEnumeratedAttr,
17 | isFalsyAttrValue
18 | } from 'web/util/index'
19 |
20 | /*更新attr*/
21 | function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
22 | /*如果旧的以及新的VNode节点均没有attr属性,则直接返回*/
23 | if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
24 | return
25 | }
26 | let key, cur, old
27 | /*VNode节点对应的Dom实例*/
28 | const elm = vnode.elm
29 | /*旧VNode节点的attr*/
30 | const oldAttrs = oldVnode.data.attrs || {}
31 | /*新VNode节点的attr*/
32 | let attrs: any = vnode.data.attrs || {}
33 | // clone observed objects, as the user probably wants to mutate it
34 | /*如果新的VNode的attr已经有__ob__(代表已经被Observe处理过了), 进行深拷贝*/
35 | if (isDef(attrs.__ob__)) {
36 | attrs = vnode.data.attrs = extend({}, attrs)
37 | }
38 |
39 | /*遍历attr,不一致则替换*/
40 | for (key in attrs) {
41 | cur = attrs[key]
42 | old = oldAttrs[key]
43 | if (old !== cur) {
44 | setAttr(elm, key, cur)
45 | }
46 | }
47 | // #4391: in IE9, setting type can reset value for input[type=radio]
48 | /* istanbul ignore if */
49 | if (isIE9 && attrs.value !== oldAttrs.value) {
50 | setAttr(elm, 'value', attrs.value)
51 | }
52 | for (key in oldAttrs) {
53 | if (isUndef(attrs[key])) {
54 | if (isXlink(key)) {
55 | elm.removeAttributeNS(xlinkNS, getXlinkProp(key))
56 | } else if (!isEnumeratedAttr(key)) {
57 | elm.removeAttribute(key)
58 | }
59 | }
60 | }
61 | }
62 |
63 | /*设置attr*/
64 | function setAttr (el: Element, key: string, value: any) {
65 | if (isBooleanAttr(key)) {
66 | // set attribute for blank value
67 | // e.g.
68 | if (isFalsyAttrValue(value)) {
69 | el.removeAttribute(key)
70 | } else {
71 | el.setAttribute(key, key)
72 | }
73 | } else if (isEnumeratedAttr(key)) {
74 | el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true')
75 | } else if (isXlink(key)) {
76 | if (isFalsyAttrValue(value)) {
77 | el.removeAttributeNS(xlinkNS, getXlinkProp(key))
78 | } else {
79 | el.setAttributeNS(xlinkNS, key, value)
80 | }
81 | } else {
82 | if (isFalsyAttrValue(value)) {
83 | el.removeAttribute(key)
84 | } else {
85 | el.setAttribute(key, value)
86 | }
87 | }
88 | }
89 |
90 | export default {
91 | create: updateAttrs,
92 | update: updateAttrs
93 | }
94 |
--------------------------------------------------------------------------------
/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 | /*更新VNode的class*/
15 | function updateClass (oldVnode: any, vnode: any) {
16 | const el = vnode.elm
17 | const data: VNodeData = vnode.data
18 | const oldData: VNodeData = oldVnode.data
19 | if (
20 | isUndef(data.staticClass) &&
21 | isUndef(data.class) && (
22 | isUndef(oldData) || (
23 | isUndef(oldData.staticClass) &&
24 | isUndef(oldData.class)
25 | )
26 | )
27 | ) {
28 | return
29 | }
30 |
31 | let cls = genClassForVnode(vnode)
32 |
33 | // handle transition classes
34 | const transitionClass = el._transitionClasses
35 | if (isDef(transitionClass)) {
36 | cls = concat(cls, stringifyClass(transitionClass))
37 | }
38 |
39 | // set the class
40 | if (cls !== el._prevClass) {
41 | el.setAttribute('class', cls)
42 | el._prevClass = cls
43 | }
44 | }
45 |
46 | export default {
47 | create: updateClass,
48 | update: updateClass
49 | }
50 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime/modules/dom-props.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { isDef, isUndef, extend, toNumber } from 'shared/util'
4 |
5 | function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
6 | if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {
7 | return
8 | }
9 | let key, cur
10 | const elm: any = vnode.elm
11 | const oldProps = oldVnode.data.domProps || {}
12 | let props = vnode.data.domProps || {}
13 | // clone observed objects, as the user probably wants to mutate it
14 | if (isDef(props.__ob__)) {
15 | props = vnode.data.domProps = extend({}, props)
16 | }
17 |
18 | for (key in oldProps) {
19 | if (isUndef(props[key])) {
20 | elm[key] = ''
21 | }
22 | }
23 | for (key in props) {
24 | cur = props[key]
25 | // ignore children if the node has textContent or innerHTML,
26 | // as these will throw away existing DOM nodes and cause removal errors
27 | // on subsequent patches (#3360)
28 | if (key === 'textContent' || key === 'innerHTML') {
29 | if (vnode.children) vnode.children.length = 0
30 | if (cur === oldProps[key]) continue
31 | }
32 |
33 | if (key === 'value') {
34 | // store value as _value as well since
35 | // non-string values will be stringified
36 | elm._value = cur
37 | // avoid resetting cursor position when value is the same
38 | const strCur = isUndef(cur) ? '' : String(cur)
39 | if (shouldUpdateValue(elm, vnode, strCur)) {
40 | elm.value = strCur
41 | }
42 | } else {
43 | elm[key] = cur
44 | }
45 | }
46 | }
47 |
48 | // check platforms/web/util/attrs.js acceptValue
49 | type acceptValueElm = HTMLInputElement | HTMLSelectElement | HTMLOptionElement;
50 |
51 | function shouldUpdateValue (
52 | elm: acceptValueElm,
53 | vnode: VNodeWithData,
54 | checkVal: string
55 | ): boolean {
56 | return (!elm.composing && (
57 | vnode.tag === 'option' ||
58 | isDirty(elm, checkVal) ||
59 | isInputChanged(elm, checkVal)
60 | ))
61 | }
62 |
63 | function isDirty (elm: acceptValueElm, checkVal: string): boolean {
64 | // return true when textbox (.number and .trim) loses focus and its value is not equal to the updated value
65 | return document.activeElement !== elm && elm.value !== checkVal
66 | }
67 |
68 | function isInputChanged (elm: any, newVal: string): boolean {
69 | const value = elm.value
70 | const modifiers = elm._vModifiers // injected by v-model runtime
71 | if ((isDef(modifiers) && modifiers.number) || elm.type === 'number') {
72 | return toNumber(value) !== toNumber(newVal)
73 | }
74 | if (isDef(modifiers) && modifiers.trim) {
75 | return value.trim() !== newVal.trim()
76 | }
77 | return value !== newVal
78 | }
79 |
80 | export default {
81 | create: updateDOMProps,
82 | update: updateDOMProps
83 | }
84 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime/modules/events.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { isDef, isUndef } from 'shared/util'
4 | import { updateListeners } from 'core/vdom/helpers/index'
5 | import { isChrome, isIE, supportsPassive } from 'core/util/env'
6 | import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model'
7 |
8 | // normalize v-model event tokens that can only be determined at runtime.
9 | // it's important to place the event as the first in the array because
10 | // the whole point is ensuring the v-model callback gets called before
11 | // user-attached handlers.
12 | function normalizeEvents (on) {
13 | let event
14 | /* istanbul ignore if */
15 | if (isDef(on[RANGE_TOKEN])) {
16 | // IE input[type=range] only supports `change` event
17 | event = isIE ? 'change' : 'input'
18 | on[event] = [].concat(on[RANGE_TOKEN], on[event] || [])
19 | delete on[RANGE_TOKEN]
20 | }
21 | if (isDef(on[CHECKBOX_RADIO_TOKEN])) {
22 | // Chrome fires microtasks in between click/change, leads to #4521
23 | event = isChrome ? 'click' : 'change'
24 | on[event] = [].concat(on[CHECKBOX_RADIO_TOKEN], on[event] || [])
25 | delete on[CHECKBOX_RADIO_TOKEN]
26 | }
27 | }
28 |
29 | let target: HTMLElement
30 |
31 | function add (
32 | event: string,
33 | handler: Function,
34 | once: boolean,
35 | capture: boolean,
36 | passive: boolean
37 | ) {
38 | if (once) {
39 | const oldHandler = handler
40 | const _target = target // save current target element in closure
41 | handler = function (ev) {
42 | const res = arguments.length === 1
43 | ? oldHandler(ev)
44 | : oldHandler.apply(null, arguments)
45 | if (res !== null) {
46 | remove(event, handler, capture, _target)
47 | }
48 | }
49 | }
50 | target.addEventListener(
51 | event,
52 | handler,
53 | supportsPassive
54 | ? { capture, passive }
55 | : capture
56 | )
57 | }
58 |
59 | function remove (
60 | event: string,
61 | handler: Function,
62 | capture: boolean,
63 | _target?: HTMLElement
64 | ) {
65 | (_target || target).removeEventListener(event, handler, capture)
66 | }
67 |
68 | function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
69 | if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
70 | return
71 | }
72 | const on = vnode.data.on || {}
73 | const oldOn = oldVnode.data.on || {}
74 | target = vnode.elm
75 | normalizeEvents(on)
76 | updateListeners(on, oldOn, add, remove, vnode.context)
77 | }
78 |
79 | export default {
80 | create: updateDOMListeners,
81 | update: updateDOMListeners
82 | }
83 |
--------------------------------------------------------------------------------
/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-src/platforms/web/runtime/modules/style.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { getStyle, normalizeStyleBinding } from 'web/util/style'
4 | import { cached, camelize, extend, isDef, isUndef } from 'shared/util'
5 |
6 | const cssVarRE = /^--/
7 | const importantRE = /\s*!important$/
8 | const setProp = (el, name, val) => {
9 | /* istanbul ignore if */
10 | if (cssVarRE.test(name)) {
11 | el.style.setProperty(name, val)
12 | } else if (importantRE.test(val)) {
13 | el.style.setProperty(name, val.replace(importantRE, ''), 'important')
14 | } else {
15 | const normalizedName = normalize(name)
16 | if (Array.isArray(val)) {
17 | // Support values array created by autoprefixer, e.g.
18 | // {display: ["-webkit-box", "-ms-flexbox", "flex"]}
19 | // Set them one by one, and the browser will only set those it can recognize
20 | for (let i = 0, len = val.length; i < len; i++) {
21 | el.style[normalizedName] = val[i]
22 | }
23 | } else {
24 | el.style[normalizedName] = val
25 | }
26 | }
27 | }
28 |
29 | const prefixes = ['Webkit', 'Moz', 'ms']
30 |
31 | let testEl
32 | const normalize = cached(function (prop) {
33 | testEl = testEl || document.createElement('div')
34 | prop = camelize(prop)
35 | if (prop !== 'filter' && (prop in testEl.style)) {
36 | return prop
37 | }
38 | const upper = prop.charAt(0).toUpperCase() + prop.slice(1)
39 | for (let i = 0; i < prefixes.length; i++) {
40 | const prefixed = prefixes[i] + upper
41 | if (prefixed in testEl.style) {
42 | return prefixed
43 | }
44 | }
45 | })
46 |
47 | function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) {
48 | const data = vnode.data
49 | const oldData = oldVnode.data
50 |
51 | if (isUndef(data.staticStyle) && isUndef(data.style) &&
52 | isUndef(oldData.staticStyle) && isUndef(oldData.style)) {
53 | return
54 | }
55 |
56 | let cur, name
57 | const el: any = vnode.elm
58 | const oldStaticStyle: any = oldData.staticStyle
59 | const oldStyleBinding: any = oldData.normalizedStyle || oldData.style || {}
60 |
61 | // if static style exists, stylebinding already merged into it when doing normalizeStyleData
62 | const oldStyle = oldStaticStyle || oldStyleBinding
63 |
64 | const style = normalizeStyleBinding(vnode.data.style) || {}
65 |
66 | // store normalized style under a different key for next diff
67 | // make sure to clone it if it's reactive, since the user likley wants
68 | // to mutate it.
69 | vnode.data.normalizedStyle = isDef(style.__ob__)
70 | ? extend({}, style)
71 | : style
72 |
73 | const newStyle = getStyle(vnode, true)
74 |
75 | for (name in oldStyle) {
76 | if (isUndef(newStyle[name])) {
77 | setProp(el, name, '')
78 | }
79 | }
80 | for (name in newStyle) {
81 | cur = newStyle[name]
82 | if (cur !== oldStyle[name]) {
83 | // ie9 setting to null has no effect, must use empty string
84 | setProp(el, name, cur == null ? '' : cur)
85 | }
86 | }
87 | }
88 |
89 | export default {
90 | create: updateStyle,
91 | update: updateStyle
92 | }
93 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/runtime/node-ops.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | /*这个文件是根据平台(web或者weex)操作真实节点(如web上的Dom)的操作函数进行了一层适配,对外可以统一提供操作真实节点的接口,内部实现根据平台的变化而变化*/
4 |
5 | import { namespaceMap } from 'web/util/index'
6 |
7 | export function createElement (tagName: string, vnode: VNode): Element {
8 | const elm = document.createElement(tagName)
9 | if (tagName !== 'select') {
10 | return elm
11 | }
12 | // false or null will remove the attribute but undefined will not
13 | if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {
14 | elm.setAttribute('multiple', 'multiple')
15 | }
16 | return elm
17 | }
18 |
19 | export function createElementNS (namespace: string, tagName: string): Element {
20 | return document.createElementNS(namespaceMap[namespace], tagName)
21 | }
22 |
23 | export function createTextNode (text: string): Text {
24 | return document.createTextNode(text)
25 | }
26 |
27 | export function createComment (text: string): Comment {
28 | return document.createComment(text)
29 | }
30 |
31 | export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) {
32 | parentNode.insertBefore(newNode, referenceNode)
33 | }
34 |
35 | export function removeChild (node: Node, child: Node) {
36 | node.removeChild(child)
37 | }
38 |
39 | export function appendChild (node: Node, child: Node) {
40 | node.appendChild(child)
41 | }
42 |
43 | export function parentNode (node: Node): ?Node {
44 | return node.parentNode
45 | }
46 |
47 | export function nextSibling (node: Node): ?Node {
48 | return node.nextSibling
49 | }
50 |
51 | export function tagName (node: Element): string {
52 | return node.tagName
53 | }
54 |
55 | export function setTextContent (node: Node, text: string) {
56 | node.textContent = text
57 | }
58 |
59 | export function setAttribute (node: Element, key: string, val: string) {
60 | node.setAttribute(key, val)
61 | }
62 |
--------------------------------------------------------------------------------
/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-src/platforms/web/server-renderer.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | process.env.VUE_ENV = 'server'
4 |
5 | import modules from './server/modules/index'
6 | import baseDirectives from './server/directives/index'
7 | import { isUnaryTag, canBeLeftOpenTag } from './compiler/util'
8 |
9 | import { createRenderer as _createRenderer } from 'server/create-renderer'
10 | import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer'
11 |
12 | export function createRenderer (options?: Object = {}): {
13 | renderToString: Function,
14 | renderToStream: Function
15 | } {
16 | return _createRenderer(Object.assign({}, options, {
17 | isUnaryTag,
18 | canBeLeftOpenTag,
19 | modules,
20 | // user can provide server-side implementations for custom directives
21 | // when creating the renderer.
22 | directives: Object.assign(baseDirectives, options.directives)
23 | }))
24 | }
25 |
26 | export const createBundleRenderer = createBundleRendererCreator(createRenderer)
27 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/directives/index.js:
--------------------------------------------------------------------------------
1 | import show from './show'
2 |
3 | export default {
4 | show
5 | }
6 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/directives/show.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | /*Github:https://github.com/answershuto*/
3 | export default function show (node: VNodeWithData, dir: VNodeDirective) {
4 | if (!dir.value) {
5 | const style: any = node.data.style || (node.data.style = {})
6 | style.display = 'none'
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/modules/attrs.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { escape } from 'he'
4 |
5 | import {
6 | isDef,
7 | isUndef
8 | } from 'shared/util'
9 |
10 | import {
11 | isBooleanAttr,
12 | isEnumeratedAttr,
13 | isFalsyAttrValue
14 | } from 'web/util/attrs'
15 |
16 | export default function renderAttrs (node: VNodeWithData): string {
17 | let attrs = node.data.attrs
18 | let res = ''
19 |
20 | let parent = node.parent
21 | while (isDef(parent)) {
22 | if (isDef(parent.data) && isDef(parent.data.attrs)) {
23 | attrs = Object.assign({}, attrs, parent.data.attrs)
24 | }
25 | parent = parent.parent
26 | }
27 |
28 | if (isUndef(attrs)) {
29 | return res
30 | }
31 |
32 | for (const key in attrs) {
33 | if (key === 'style') {
34 | // leave it to the style module
35 | continue
36 | }
37 | res += renderAttr(key, attrs[key])
38 | }
39 | return res
40 | }
41 |
42 | export function renderAttr (key: string, value: string): string {
43 | if (isBooleanAttr(key)) {
44 | if (!isFalsyAttrValue(value)) {
45 | return ` ${key}="${key}"`
46 | }
47 | } else if (isEnumeratedAttr(key)) {
48 | return ` ${key}="${isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'}"`
49 | } else if (!isFalsyAttrValue(value)) {
50 | return ` ${key}="${typeof value === 'string' ? escape(value) : value}"`
51 | }
52 | return ''
53 | }
54 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/modules/class.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { escape } from 'he'
4 | import { genClassForVnode } from 'web/util/index'
5 |
6 | export default function renderClass (node: VNodeWithData): ?string {
7 | const classList = genClassForVnode(node)
8 | if (classList !== '') {
9 | return ` class="${escape(classList)}"`
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/modules/dom-props.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import VNode from 'core/vdom/vnode'
4 | import { renderAttr } from './attrs'
5 | import { isDef, isUndef } from 'shared/util'
6 | import { propsToAttrMap, isRenderableAttr } from '../util'
7 |
8 | export default function renderDOMProps (node: VNodeWithData): string {
9 | let props = node.data.domProps
10 | let res = ''
11 |
12 | let parent = node.parent
13 | while (isDef(parent)) {
14 | if (parent.data && parent.data.domProps) {
15 | props = Object.assign({}, props, parent.data.domProps)
16 | }
17 | parent = parent.parent
18 | }
19 |
20 | if (isUndef(props)) {
21 | return res
22 | }
23 |
24 | const attrs = node.data.attrs
25 | for (const key in props) {
26 | if (key === 'innerHTML') {
27 | setText(node, props[key], true)
28 | } else if (key === 'textContent') {
29 | setText(node, props[key], false)
30 | } else {
31 | const attr = propsToAttrMap[key] || key.toLowerCase()
32 | if (isRenderableAttr(attr) &&
33 | // avoid rendering double-bound props/attrs twice
34 | !(isDef(attrs) && isDef(attrs[attr]))) {
35 | res += renderAttr(attr, props[key])
36 | }
37 | }
38 | }
39 | return res
40 | }
41 |
42 | function setText (node, text, raw) {
43 | const child = new VNode(undefined, undefined, undefined, text)
44 | child.raw = raw
45 | node.children = [child]
46 | }
47 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/modules/index.js:
--------------------------------------------------------------------------------
1 | import attrs from './attrs'
2 | import domProps from './dom-props'
3 | import klass from './class'
4 | import style from './style'
5 |
6 | export default [
7 | attrs,
8 | domProps,
9 | klass,
10 | style
11 | ]
12 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/modules/style.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { escape } from 'he'
4 | import { hyphenate } from 'shared/util'
5 | import { getStyle } from 'web/util/style'
6 |
7 | function genStyleText (vnode: VNode): string {
8 | let styleText = ''
9 | const style = getStyle(vnode, false)
10 | for (const key in style) {
11 | const value = style[key]
12 | const hyphenatedKey = hyphenate(key)
13 | if (Array.isArray(value)) {
14 | for (let i = 0, len = value.length; i < len; i++) {
15 | styleText += `${hyphenatedKey}:${value[i]};`
16 | }
17 | } else {
18 | styleText += `${hyphenatedKey}:${value};`
19 | }
20 | }
21 | return styleText
22 | }
23 |
24 | export default function renderStyle (vnode: VNodeWithData): ?string {
25 | const styleText = genStyleText(vnode)
26 | if (styleText !== '') {
27 | return ` style=${JSON.stringify(escape(styleText))}`
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/server/util.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { makeMap } from 'shared/util'
4 |
5 | const isAttr = makeMap(
6 | 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' +
7 | 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' +
8 | 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' +
9 | 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' +
10 | 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' +
11 | 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' +
12 | 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' +
13 | 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' +
14 | 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' +
15 | 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' +
16 | 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' +
17 | 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' +
18 | 'target,title,type,usemap,value,width,wrap'
19 | )
20 |
21 | /* istanbul ignore next */
22 | const isRenderableAttr = (name: string): boolean => {
23 | return (
24 | isAttr(name) ||
25 | name.indexOf('data-') === 0 ||
26 | name.indexOf('aria-') === 0
27 | )
28 | }
29 | export { isRenderableAttr }
30 |
31 | export const propsToAttrMap = {
32 | acceptCharset: 'accept-charset',
33 | className: 'class',
34 | htmlFor: 'for',
35 | httpEquiv: 'http-equiv'
36 | }
37 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/attrs.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { makeMap } from 'shared/util'
4 |
5 | // these are reserved for web because they are directly compiled away
6 | // during template compilation
7 | export const isReservedAttr = makeMap('style,class')
8 |
9 | // attributes that should be using props for binding
10 | const acceptValue = makeMap('input,textarea,option,select')
11 | export const mustUseProp = (tag: string, type: ?string, attr: string): boolean => {
12 | return (
13 | (attr === 'value' && acceptValue(tag)) && type !== 'button' ||
14 | (attr === 'selected' && tag === 'option') ||
15 | (attr === 'checked' && tag === 'input') ||
16 | (attr === 'muted' && tag === 'video')
17 | )
18 | }
19 |
20 | export const isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck')
21 |
22 | export const isBooleanAttr = makeMap(
23 | 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
24 | 'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
25 | 'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
26 | 'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
27 | 'required,reversed,scoped,seamless,selected,sortable,translate,' +
28 | 'truespeed,typemustmatch,visible'
29 | )
30 |
31 | export const xlinkNS = 'http://www.w3.org/1999/xlink'
32 |
33 | export const isXlink = (name: string): boolean => {
34 | return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'
35 | }
36 |
37 | export const getXlinkProp = (name: string): string => {
38 | return isXlink(name) ? name.slice(6, name.length) : ''
39 | }
40 |
41 | export const isFalsyAttrValue = (val: any): boolean => {
42 | return val == null || val === false
43 | }
44 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/class.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { isDef, isUndef, isObject } from 'shared/util'
4 |
5 | export function genClassForVnode (vnode: VNode): string {
6 | let data = vnode.data
7 | let parentNode = vnode
8 | let childNode = vnode
9 | while (isDef(childNode.componentInstance)) {
10 | childNode = childNode.componentInstance._vnode
11 | if (childNode.data) {
12 | data = mergeClassData(childNode.data, data)
13 | }
14 | }
15 | while (isDef(parentNode = parentNode.parent)) {
16 | if (parentNode.data) {
17 | data = mergeClassData(data, parentNode.data)
18 | }
19 | }
20 | return genClassFromData(data)
21 | }
22 |
23 | function mergeClassData (child: VNodeData, parent: VNodeData): {
24 | staticClass: string,
25 | class: any
26 | } {
27 | return {
28 | staticClass: concat(child.staticClass, parent.staticClass),
29 | class: isDef(child.class)
30 | ? [child.class, parent.class]
31 | : parent.class
32 | }
33 | }
34 |
35 | function genClassFromData (data: Object): string {
36 | const dynamicClass = data.class
37 | const staticClass = data.staticClass
38 | if (isDef(staticClass) || isDef(dynamicClass)) {
39 | return concat(staticClass, stringifyClass(dynamicClass))
40 | }
41 | /* istanbul ignore next */
42 | return ''
43 | }
44 |
45 | export function concat (a: ?string, b: ?string): string {
46 | return a ? b ? (a + ' ' + b) : a : (b || '')
47 | }
48 |
49 | export function stringifyClass (value: any): string {
50 | if (isUndef(value)) {
51 | return ''
52 | }
53 | if (typeof value === 'string') {
54 | return value
55 | }
56 | let res = ''
57 | if (Array.isArray(value)) {
58 | let stringified
59 | for (let i = 0, l = value.length; i < l; i++) {
60 | if (isDef(value[i])) {
61 | if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {
62 | res += stringified + ' '
63 | }
64 | }
65 | }
66 | return res.slice(0, -1)
67 | }
68 | if (isObject(value)) {
69 | for (const key in value) {
70 | if (value[key]) res += key + ' '
71 | }
72 | return res.slice(0, -1)
73 | }
74 | /* istanbul ignore next */
75 | return res
76 | }
77 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/compat.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { inBrowser } from 'core/util/index'
4 |
5 | // check whether current browser encodes a char inside attribute values
6 | function shouldDecode (content: string, encoded: string): boolean {
7 | const div = document.createElement('div')
8 | div.innerHTML = `
`
9 | return div.innerHTML.indexOf(encoded) > 0
10 | }
11 |
12 | // #3663
13 | // IE encodes newlines inside attribute values while other browsers don't
14 | export const shouldDecodeNewlines = inBrowser ? shouldDecode('\n', '
') : false
15 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/element.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { inBrowser } from 'core/util/env'
4 | import { makeMap } from 'shared/util'
5 |
6 | export const namespaceMap = {
7 | svg: 'http://www.w3.org/2000/svg',
8 | math: 'http://www.w3.org/1998/Math/MathML'
9 | }
10 |
11 | export const isHTMLTag = makeMap(
12 | 'html,body,base,head,link,meta,style,title,' +
13 | 'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
14 | 'div,dd,dl,dt,figcaption,figure,hr,img,li,main,ol,p,pre,ul,' +
15 | 'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
16 | 's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
17 | 'embed,object,param,source,canvas,script,noscript,del,ins,' +
18 | 'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
19 | 'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
20 | 'output,progress,select,textarea,' +
21 | 'details,dialog,menu,menuitem,summary,' +
22 | 'content,element,shadow,template'
23 | )
24 |
25 | // this map is intentionally selective, only covering SVG elements that may
26 | // contain child elements.
27 | export const isSVG = makeMap(
28 | 'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
29 | 'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
30 | 'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
31 | true
32 | )
33 |
34 | export const isPreTag = (tag: ?string): boolean => tag === 'pre'
35 |
36 | export const isReservedTag = (tag: string): ?boolean => {
37 | return isHTMLTag(tag) || isSVG(tag)
38 | }
39 |
40 | export function getTagNamespace (tag: string): ?string {
41 | if (isSVG(tag)) {
42 | return 'svg'
43 | }
44 | // basic support for MathML
45 | // note it doesn't support other MathML elements being component roots
46 | if (tag === 'math') {
47 | return 'math'
48 | }
49 | }
50 |
51 | const unknownElementCache = Object.create(null)
52 | export function isUnknownElement (tag: string): boolean {
53 | /* istanbul ignore if */
54 | if (!inBrowser) {
55 | return true
56 | }
57 | if (isReservedTag(tag)) {
58 | return false
59 | }
60 | tag = tag.toLowerCase()
61 | /* istanbul ignore if */
62 | if (unknownElementCache[tag] != null) {
63 | return unknownElementCache[tag]
64 | }
65 | const el = document.createElement(tag)
66 | if (tag.indexOf('-') > -1) {
67 | // http://stackoverflow.com/a/28210364/1070244
68 | return (unknownElementCache[tag] = (
69 | el.constructor === window.HTMLUnknownElement ||
70 | el.constructor === window.HTMLElement
71 | ))
72 | } else {
73 | return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/index.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { warn } from 'core/util/index'
4 |
5 | export * from './attrs'
6 | export * from './class'
7 | export * from './element'
8 |
9 | /**
10 | * Query an element selector if it's not an element already.
11 | */
12 | /*返回一个元素的DOM实例对象*/
13 | export function query (el: string | Element): Element {
14 | if (typeof el === 'string') {
15 | const selected = document.querySelector(el)
16 | if (!selected) {
17 | process.env.NODE_ENV !== 'production' && warn(
18 | 'Cannot find element: ' + el
19 | )
20 | return document.createElement('div')
21 | }
22 | return selected
23 | } else {
24 | return el
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/vue-src/platforms/web/util/style.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { cached, extend, toObject } from 'shared/util'
4 |
5 | export const parseStyleText = cached(function (cssText) {
6 | const res = {}
7 | const listDelimiter = /;(?![^(]*\))/g
8 | const propertyDelimiter = /:(.+)/
9 | cssText.split(listDelimiter).forEach(function (item) {
10 | if (item) {
11 | var tmp = item.split(propertyDelimiter)
12 | tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim())
13 | }
14 | })
15 | return res
16 | })
17 |
18 | // merge static and dynamic style data on the same vnode
19 | function normalizeStyleData (data: VNodeData): ?Object {
20 | const style = normalizeStyleBinding(data.style)
21 | // static style is pre-processed into an object during compilation
22 | // and is always a fresh object, so it's safe to merge into it
23 | return data.staticStyle
24 | ? extend(data.staticStyle, style)
25 | : style
26 | }
27 |
28 | // normalize possible array / string values into Object
29 | export function normalizeStyleBinding (bindingStyle: any): ?Object {
30 | if (Array.isArray(bindingStyle)) {
31 | return toObject(bindingStyle)
32 | }
33 | if (typeof bindingStyle === 'string') {
34 | return parseStyleText(bindingStyle)
35 | }
36 | return bindingStyle
37 | }
38 |
39 | /**
40 | * parent component style should be after child's
41 | * so that parent component's style could override it
42 | */
43 | export function getStyle (vnode: VNode, checkChild: boolean): Object {
44 | const res = {}
45 | let styleData
46 |
47 | if (checkChild) {
48 | let childNode = vnode
49 | while (childNode.componentInstance) {
50 | childNode = childNode.componentInstance._vnode
51 | if (childNode.data && (styleData = normalizeStyleData(childNode.data))) {
52 | extend(res, styleData)
53 | }
54 | }
55 | }
56 |
57 | if ((styleData = normalizeStyleData(vnode.data))) {
58 | extend(res, styleData)
59 | }
60 |
61 | let parentNode = vnode
62 | while ((parentNode = parentNode.parent)) {
63 | if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
64 | extend(res, styleData)
65 | }
66 | }
67 | return res
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler.js:
--------------------------------------------------------------------------------
1 | export { compile } from 'weex/compiler/index'
2 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/directives/index.js:
--------------------------------------------------------------------------------
1 | import model from './model'
2 |
3 | export default {
4 | model
5 | }
6 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/directives/model.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { addHandler, addAttr } from 'compiler/helpers'
4 | import { genComponentModel, genAssignmentCode } from 'compiler/directives/model'
5 |
6 | export default function model (
7 | el: ASTElement,
8 | dir: ASTDirective,
9 | _warn: Function
10 | ): ?boolean {
11 | if (el.tag === 'input' || el.tag === 'textarea') {
12 | genDefaultModel(el, dir.value, dir.modifiers)
13 | } else {
14 | genComponentModel(el, dir.value, dir.modifiers)
15 | }
16 | }
17 |
18 | function genDefaultModel (
19 | el: ASTElement,
20 | value: string,
21 | modifiers: ?ASTModifiers
22 | ): ?boolean {
23 | const { lazy, trim, number } = modifiers || {}
24 | const event = lazy ? 'change' : 'input'
25 |
26 | let valueExpression = `$event.target.attr.value${trim ? '.trim()' : ''}`
27 | if (number) {
28 | valueExpression = `_n(${valueExpression})`
29 | }
30 |
31 | const code = genAssignmentCode(value, valueExpression)
32 | addAttr(el, 'value', `(${value})`)
33 | addHandler(el, event, code, null, true)
34 | }
35 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/index.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { genStaticKeys } from 'shared/util'
4 | import { createCompiler } from 'compiler/index'
5 |
6 | import modules from './modules/index'
7 | import directives from './directives/index'
8 |
9 | import {
10 | isUnaryTag,
11 | mustUseProp,
12 | isReservedTag,
13 | canBeLeftOpenTag,
14 | getTagNamespace
15 | } from '../util/index'
16 |
17 | export const baseOptions: CompilerOptions = {
18 | modules,
19 | directives,
20 | isUnaryTag,
21 | mustUseProp,
22 | canBeLeftOpenTag,
23 | isReservedTag,
24 | getTagNamespace,
25 | preserveWhitespace: false,
26 | staticKeys: genStaticKeys(modules)
27 | }
28 |
29 | const { compile, compileToFunctions } = createCompiler(baseOptions)
30 | export { compile, compileToFunctions }
31 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/modules/append.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | function preTransformNode (el: ASTElement, options: CompilerOptions) {
4 | if (el.tag === 'cell' && !el.attrsList.some(item => item.name === 'append')) {
5 | el.attrsMap.append = 'tree'
6 | el.attrsList.push({ name: 'append', value: 'tree' })
7 | }
8 | if (el.attrsMap.append === 'tree') {
9 | el.appendAsTree = true
10 | }
11 | }
12 |
13 | function genData (el: ASTElement): string {
14 | return el.appendAsTree ? `appendAsTree:true,` : ''
15 | }
16 |
17 | export default {
18 | staticKeys: ['appendAsTree'],
19 | preTransformNode,
20 | genData
21 | }
22 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/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 | type StaticClassResult = {
11 | dynamic: boolean,
12 | classResult: string
13 | };
14 |
15 | function transformNode (el: ASTElement, options: CompilerOptions) {
16 | const warn = options.warn || baseWarn
17 | const staticClass = getAndRemoveAttr(el, 'class')
18 | const { dynamic, classResult } = parseStaticClass(staticClass, options)
19 | if (process.env.NODE_ENV !== 'production' && dynamic && staticClass) {
20 | warn(
21 | `class="${staticClass}": ` +
22 | 'Interpolation inside attributes has been deprecated. ' +
23 | 'Use v-bind or the colon shorthand instead.'
24 | )
25 | }
26 | if (!dynamic && classResult) {
27 | el.staticClass = classResult
28 | }
29 | const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
30 | if (classBinding) {
31 | el.classBinding = classBinding
32 | } else if (dynamic) {
33 | el.classBinding = classResult
34 | }
35 | }
36 |
37 | function genData (el: ASTElement): string {
38 | let data = ''
39 | if (el.staticClass) {
40 | data += `staticClass:${el.staticClass},`
41 | }
42 | if (el.classBinding) {
43 | data += `class:${el.classBinding},`
44 | }
45 | return data
46 | }
47 |
48 | function parseStaticClass (staticClass: ?string, options: CompilerOptions): StaticClassResult {
49 | // "a b c" -> ["a", "b", "c"] => staticClass: ["a", "b", "c"]
50 | // "a {{x}} c" -> ["a", x, "c"] => classBinding: '["a", x, "c"]'
51 | let dynamic = false
52 | let classResult = ''
53 | if (staticClass) {
54 | const classList = staticClass.trim().split(' ').map(name => {
55 | const result = parseText(name, options.delimiters)
56 | if (result) {
57 | dynamic = true
58 | return result
59 | }
60 | return JSON.stringify(name)
61 | })
62 | if (classList.length) {
63 | classResult = '[' + classList.join(',') + ']'
64 | }
65 | }
66 | return { dynamic, classResult }
67 | }
68 |
69 | export default {
70 | staticKeys: ['staticClass'],
71 | transformNode,
72 | genData
73 | }
74 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/modules/index.js:
--------------------------------------------------------------------------------
1 | import klass from './class'
2 | import style from './style'
3 | import props from './props'
4 | import append from './append'
5 |
6 | export default [
7 | klass,
8 | style,
9 | props,
10 | append
11 | ]
12 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/modules/props.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { cached, camelize } from 'shared/util'
4 |
5 | const normalize = cached(camelize)
6 |
7 | function normalizeKeyName (str: string) : string {
8 | if (str.match(/^v\-/)) {
9 | return str.replace(/(v-[a-z\-]+\:)([a-z\-]+)$/i, ($, directive, prop) => {
10 | return directive + normalize(prop)
11 | })
12 | }
13 | return normalize(str)
14 | }
15 |
16 | function transformNode (el: ASTElement, options: CompilerOptions) {
17 | if (Array.isArray(el.attrsList)) {
18 | el.attrsList.forEach(attr => {
19 | if (attr.name && attr.name.match(/\-/)) {
20 | const realName = normalizeKeyName(attr.name)
21 | if (el.attrsMap) {
22 | el.attrsMap[realName] = el.attrsMap[attr.name]
23 | delete el.attrsMap[attr.name]
24 | }
25 | attr.name = realName
26 | }
27 | })
28 | }
29 | }
30 | export default {
31 | transformNode
32 | }
33 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/compiler/modules/style.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { cached, camelize } from 'shared/util'
4 | import { parseText } from 'compiler/parser/text-parser'
5 | import {
6 | getAndRemoveAttr,
7 | getBindingAttr,
8 | baseWarn
9 | } from 'compiler/helpers'
10 |
11 | type StaticStyleResult = {
12 | dynamic: boolean,
13 | styleResult: string
14 | };
15 |
16 | const normalize = cached(camelize)
17 |
18 | function transformNode (el: ASTElement, options: CompilerOptions) {
19 | const warn = options.warn || baseWarn
20 | const staticStyle = getAndRemoveAttr(el, 'style')
21 | const { dynamic, styleResult } = parseStaticStyle(staticStyle, options)
22 | if (process.env.NODE_ENV !== 'production' && dynamic) {
23 | warn(
24 | `style="${String(staticStyle)}": ` +
25 | 'Interpolation inside attributes has been deprecated. ' +
26 | 'Use v-bind or the colon shorthand instead.'
27 | )
28 | }
29 | if (!dynamic && styleResult) {
30 | el.staticStyle = styleResult
31 | }
32 | const styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
33 | if (styleBinding) {
34 | el.styleBinding = styleBinding
35 | } else if (dynamic) {
36 | el.styleBinding = styleResult
37 | }
38 | }
39 |
40 | function genData (el: ASTElement): string {
41 | let data = ''
42 | if (el.staticStyle) {
43 | data += `staticStyle:${el.staticStyle},`
44 | }
45 | if (el.styleBinding) {
46 | data += `style:${el.styleBinding},`
47 | }
48 | return data
49 | }
50 |
51 | function parseStaticStyle (staticStyle: ?string, options: CompilerOptions): StaticStyleResult {
52 | // "width: 200px; height: 200px;" -> {width: 200, height: 200}
53 | // "width: 200px; height: {{y}}" -> {width: 200, height: y}
54 | let dynamic = false
55 | let styleResult = ''
56 | if (staticStyle) {
57 | const styleList = staticStyle.trim().split(';').map(style => {
58 | const result = style.trim().split(':')
59 | if (result.length !== 2) {
60 | return
61 | }
62 | const key = normalize(result[0].trim())
63 | const value = result[1].trim()
64 | const dynamicValue = parseText(value, options.delimiters)
65 | if (dynamicValue) {
66 | dynamic = true
67 | return key + ':' + dynamicValue
68 | }
69 | return key + ':' + JSON.stringify(value)
70 | }).filter(result => result)
71 | if (styleList.length) {
72 | styleResult = '{' + styleList.join(',') + '}'
73 | }
74 | }
75 | return { dynamic, styleResult }
76 | }
77 |
78 | export default {
79 | staticKeys: ['staticStyle'],
80 | transformNode,
81 | genData
82 | }
83 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/runtime-factory.js:
--------------------------------------------------------------------------------
1 | // this entry is built and wrapped with a factory function
2 | // used to generate a fresh copy of Vue for every Weex instance.
3 |
4 | import Vue from './runtime/index'
5 |
6 | exports.Vue = Vue
7 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/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-src/platforms/weex/runtime/components/transition.js:
--------------------------------------------------------------------------------
1 | // reuse same transition component logic from web
2 | export {
3 | transitionProps,
4 | extractTransitionData
5 | } from 'web/runtime/components/transition'
6 |
7 | import Transition from 'web/runtime/components/transition'
8 |
9 | export default Transition
10 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/runtime/directives/index.js:
--------------------------------------------------------------------------------
1 | export default {
2 | }
3 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/runtime/index.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import Vue from 'core/index'
4 | import { patch } from 'weex/runtime/patch'
5 | import { mountComponent } from 'core/instance/lifecycle'
6 | import platformDirectives from 'weex/runtime/directives/index'
7 | import platformComponents from 'weex/runtime/components/index'
8 |
9 | import {
10 | query,
11 | mustUseProp,
12 | isReservedTag,
13 | isUnknownElement
14 | } from 'weex/util/index'
15 |
16 | // install platform specific utils
17 | Vue.config.mustUseProp = mustUseProp
18 | Vue.config.isReservedTag = isReservedTag
19 | Vue.config.isUnknownElement = isUnknownElement
20 |
21 | // install platform runtime directives and components
22 | Vue.options.directives = platformDirectives
23 | Vue.options.components = platformComponents
24 |
25 | // install platform patch function
26 | Vue.prototype.__patch__ = patch
27 |
28 | // wrap mount
29 | Vue.prototype.$mount = function (
30 | el?: any,
31 | hydrating?: boolean
32 | ): Component {
33 | return mountComponent(
34 | this,
35 | el && query(el, this.$document),
36 | hydrating
37 | )
38 | }
39 |
40 | export default Vue
41 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/runtime/modules/attrs.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { extend } from 'shared/util'
4 |
5 | function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
6 | if (!oldVnode.data.attrs && !vnode.data.attrs) {
7 | return
8 | }
9 | let key, cur, old
10 | const elm = vnode.elm
11 | const oldAttrs = oldVnode.data.attrs || {}
12 | let attrs = vnode.data.attrs || {}
13 | // clone observed objects, as the user probably wants to mutate it
14 | if (attrs.__ob__) {
15 | attrs = vnode.data.attrs = extend({}, attrs)
16 | }
17 |
18 | for (key in attrs) {
19 | cur = attrs[key]
20 | old = oldAttrs[key]
21 | if (old !== cur) {
22 | elm.setAttr(key, cur)
23 | }
24 | }
25 | for (key in oldAttrs) {
26 | if (attrs[key] == null) {
27 | elm.setAttr(key)
28 | }
29 | }
30 | }
31 |
32 | export default {
33 | create: updateAttrs,
34 | update: updateAttrs
35 | }
36 |
--------------------------------------------------------------------------------
/vue-src/platforms/weex/runtime/modules/class.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import { extend } from 'shared/util'
4 |
5 | function updateClass (oldVnode: VNodeWithData, vnode: VNodeWithData) {
6 | const el = vnode.elm
7 | const ctx = vnode.context
8 |
9 | const data: VNodeData = vnode.data
10 | const oldData: VNodeData = oldVnode.data
11 | if (!data.staticClass && !data.class &&
12 | (!oldData || (!oldData.staticClass && !oldData.class))) {
13 | return
14 | }
15 |
16 | const oldClassList = []
17 | // unlike web, weex vnode staticClass is an Array
18 | const oldStaticClass: any = oldData.staticClass
19 | if (oldStaticClass) {
20 | oldClassList.push.apply(oldClassList, oldStaticClass)
21 | }
22 | if (oldData.class) {
23 | oldClassList.push.apply(oldClassList, oldData.class)
24 | }
25 |
26 | const classList = []
27 | // unlike web, weex vnode staticClass is an Array
28 | const staticClass: any = data.staticClass
29 | if (staticClass) {
30 | classList.push.apply(classList, staticClass)
31 | }
32 | if (data.class) {
33 | classList.push.apply(classList, data.class)
34 | }
35 |
36 | const style = getStyle(oldClassList, classList, ctx)
37 | for (const key in style) {
38 | el.setStyle(key, style[key])
39 | }
40 | }
41 |
42 | function getStyle (oldClassList: Array, classList: Array, ctx: Component): Object {
43 | // style is a weex-only injected object
44 | // compiled from