From 26105034da4fcce7ac883c899d781f016559310d Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 8 Nov 2018 00:38:48 +0800 Subject: switch to vuepress --- .../vue/src/platforms/web/runtime/class-util.js | 61 ++++ .../src/platforms/web/runtime/components/index.js | 7 + .../web/runtime/components/transition-group.js | 180 +++++++++++ .../platforms/web/runtime/components/transition.js | 194 ++++++++++++ .../src/platforms/web/runtime/directives/index.js | 7 + .../src/platforms/web/runtime/directives/model.js | 147 +++++++++ .../src/platforms/web/runtime/directives/show.js | 60 ++++ .../vue/src/platforms/web/runtime/index.js | 77 +++++ .../vue/src/platforms/web/runtime/modules/attrs.js | 118 +++++++ .../vue/src/platforms/web/runtime/modules/class.js | 48 +++ .../src/platforms/web/runtime/modules/dom-props.js | 95 ++++++ .../src/platforms/web/runtime/modules/events.js | 87 ++++++ .../vue/src/platforms/web/runtime/modules/index.js | 15 + .../vue/src/platforms/web/runtime/modules/style.js | 93 ++++++ .../platforms/web/runtime/modules/transition.js | 343 +++++++++++++++++++++ .../vue/src/platforms/web/runtime/node-ops.js | 59 ++++ .../vue/src/platforms/web/runtime/patch.js | 12 + .../src/platforms/web/runtime/transition-util.js | 185 +++++++++++ 18 files changed, 1788 insertions(+) create mode 100644 node_modules/vue/src/platforms/web/runtime/class-util.js create mode 100644 node_modules/vue/src/platforms/web/runtime/components/index.js create mode 100644 node_modules/vue/src/platforms/web/runtime/components/transition-group.js create mode 100644 node_modules/vue/src/platforms/web/runtime/components/transition.js create mode 100644 node_modules/vue/src/platforms/web/runtime/directives/index.js create mode 100644 node_modules/vue/src/platforms/web/runtime/directives/model.js create mode 100644 node_modules/vue/src/platforms/web/runtime/directives/show.js create mode 100644 node_modules/vue/src/platforms/web/runtime/index.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/attrs.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/class.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/dom-props.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/events.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/index.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/style.js create mode 100644 node_modules/vue/src/platforms/web/runtime/modules/transition.js create mode 100644 node_modules/vue/src/platforms/web/runtime/node-ops.js create mode 100644 node_modules/vue/src/platforms/web/runtime/patch.js create mode 100644 node_modules/vue/src/platforms/web/runtime/transition-util.js (limited to 'node_modules/vue/src/platforms/web/runtime') diff --git a/node_modules/vue/src/platforms/web/runtime/class-util.js b/node_modules/vue/src/platforms/web/runtime/class-util.js new file mode 100644 index 00000000..709526c2 --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/class-util.js @@ -0,0 +1,61 @@ +/* @flow */ + +/** + * Add class with compatibility for SVG since classList is not supported on + * SVG elements in IE + */ +export function addClass (el: HTMLElement, cls: ?string) { + /* istanbul ignore if */ + if (!cls || !(cls = cls.trim())) { + return + } + + /* istanbul ignore else */ + if (el.classList) { + if (cls.indexOf(' ') > -1) { + cls.split(/\s+/).forEach(c => el.classList.add(c)) + } else { + el.classList.add(cls) + } + } else { + const cur = ` ${el.getAttribute('class') || ''} ` + if (cur.indexOf(' ' + cls + ' ') < 0) { + el.setAttribute('class', (cur + cls).trim()) + } + } +} + +/** + * Remove class with compatibility for SVG since classList is not supported on + * SVG elements in IE + */ +export function removeClass (el: HTMLElement, cls: ?string) { + /* istanbul ignore if */ + if (!cls || !(cls = cls.trim())) { + return + } + + /* istanbul ignore else */ + if (el.classList) { + if (cls.indexOf(' ') > -1) { + cls.split(/\s+/).forEach(c => el.classList.remove(c)) + } else { + el.classList.remove(cls) + } + if (!el.classList.length) { + el.removeAttribute('class') + } + } else { + let cur = ` ${el.getAttribute('class') || ''} ` + const tar = ' ' + cls + ' ' + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' ') + } + cur = cur.trim() + if (cur) { + el.setAttribute('class', cur) + } else { + el.removeAttribute('class') + } + } +} diff --git a/node_modules/vue/src/platforms/web/runtime/components/index.js b/node_modules/vue/src/platforms/web/runtime/components/index.js new file mode 100644 index 00000000..6bfe5780 --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/components/index.js @@ -0,0 +1,7 @@ +import Transition from './transition' +import TransitionGroup from './transition-group' + +export default { + Transition, + TransitionGroup +} diff --git a/node_modules/vue/src/platforms/web/runtime/components/transition-group.js b/node_modules/vue/src/platforms/web/runtime/components/transition-group.js new file mode 100644 index 00000000..219ff01c --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/components/transition-group.js @@ -0,0 +1,180 @@ +/* @flow */ + +// Provides transition support for list items. +// supports move transitions using the FLIP technique. + +// Because the vdom's children update algorithm is "unstable" - i.e. +// it doesn't guarantee the relative positioning of removed elements, +// we force transition-group to update its children into two passes: +// in the first pass, we remove all nodes that need to be removed, +// triggering their leaving transition; in the second pass, we insert/move +// into the final desired state. This way in the second pass removed +// nodes will remain where they should be. + +import { warn, extend } from 'core/util/index' +import { addClass, removeClass } from '../class-util' +import { transitionProps, extractTransitionData } from './transition' + +import { + hasTransition, + getTransitionInfo, + transitionEndEvent, + addTransitionClass, + removeTransitionClass +} from '../transition-util' + +const props = extend({ + tag: String, + moveClass: String +}, transitionProps) + +delete props.mode + +export default { + props, + + render (h: Function) { + const tag: string = this.tag || this.$vnode.data.tag || 'span' + const map: Object = Object.create(null) + const prevChildren: Array = this.prevChildren = this.children + const rawChildren: Array = this.$slots.default || [] + const children: Array = this.children = [] + const transitionData: Object = extractTransitionData(this) + + for (let i = 0; i < rawChildren.length; i++) { + const c: VNode = rawChildren[i] + if (c.tag) { + if (c.key != null && String(c.key).indexOf('__vlist') !== 0) { + children.push(c) + map[c.key] = c + ;(c.data || (c.data = {})).transition = transitionData + } else if (process.env.NODE_ENV !== 'production') { + const opts: ?VNodeComponentOptions = c.componentOptions + const name: string = opts ? (opts.Ctor.options.name || opts.tag || '') : c.tag + warn(` children must be keyed: <${name}>`) + } + } + } + + if (prevChildren) { + const kept: Array = [] + const removed: Array = [] + for (let i = 0; i < prevChildren.length; i++) { + const c: VNode = prevChildren[i] + c.data.transition = transitionData + c.data.pos = c.elm.getBoundingClientRect() + if (map[c.key]) { + kept.push(c) + } else { + removed.push(c) + } + } + this.kept = h(tag, null, kept) + this.removed = removed + } + + return h(tag, null, children) + }, + + beforeUpdate () { + // force removing pass + this.__patch__( + this._vnode, + this.kept, + false, // hydrating + true // removeOnly (!important, avoids unnecessary moves) + ) + this._vnode = this.kept + }, + + updated () { + const children: Array = this.prevChildren + const moveClass: string = this.moveClass || ((this.name || 'v') + '-move') + if (!children.length || !this.hasMove(children[0].elm, moveClass)) { + return + } + + // we divide the work into three loops to avoid mixing DOM reads and writes + // in each iteration - which helps prevent layout thrashing. + children.forEach(callPendingCbs) + children.forEach(recordPosition) + children.forEach(applyTranslation) + + // force reflow to put everything in position + // assign to this to avoid being removed in tree-shaking + // $flow-disable-line + this._reflow = document.body.offsetHeight + + children.forEach((c: VNode) => { + if (c.data.moved) { + var el: any = c.elm + var s: any = el.style + addTransitionClass(el, moveClass) + s.transform = s.WebkitTransform = s.transitionDuration = '' + el.addEventListener(transitionEndEvent, el._moveCb = function cb (e) { + if (!e || /transform$/.test(e.propertyName)) { + el.removeEventListener(transitionEndEvent, cb) + el._moveCb = null + removeTransitionClass(el, moveClass) + } + }) + } + }) + }, + + methods: { + hasMove (el: any, moveClass: string): boolean { + /* istanbul ignore if */ + if (!hasTransition) { + return false + } + /* istanbul ignore if */ + if (this._hasMove) { + return this._hasMove + } + // Detect whether an element with the move class applied has + // CSS transitions. Since the element may be inside an entering + // transition at this very moment, we make a clone of it and remove + // all other transition classes applied to ensure only the move class + // is applied. + const clone: HTMLElement = el.cloneNode() + if (el._transitionClasses) { + el._transitionClasses.forEach((cls: string) => { removeClass(clone, cls) }) + } + addClass(clone, moveClass) + clone.style.display = 'none' + this.$el.appendChild(clone) + const info: Object = getTransitionInfo(clone) + this.$el.removeChild(clone) + return (this._hasMove = info.hasTransform) + } + } +} + +function callPendingCbs (c: VNode) { + /* istanbul ignore if */ + if (c.elm._moveCb) { + c.elm._moveCb() + } + /* istanbul ignore if */ + if (c.elm._enterCb) { + c.elm._enterCb() + } +} + +function recordPosition (c: VNode) { + c.data.newPos = c.elm.getBoundingClientRect() +} + +function applyTranslation (c: VNode) { + const oldPos = c.data.pos + const newPos = c.data.newPos + const dx = oldPos.left - newPos.left + const dy = oldPos.top - newPos.top + if (dx || dy) { + c.data.moved = true + const s = c.elm.style + s.transform = s.WebkitTransform = `translate(${dx}px,${dy}px)` + s.transitionDuration = '0s' + } +} diff --git a/node_modules/vue/src/platforms/web/runtime/components/transition.js b/node_modules/vue/src/platforms/web/runtime/components/transition.js new file mode 100644 index 00000000..6111d8cb --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/components/transition.js @@ -0,0 +1,194 @@ +/* @flow */ + +// Provides transition support for a single element/component. +// supports transition mode (out-in / in-out) + +import { warn } from 'core/util/index' +import { camelize, extend, isPrimitive } from 'shared/util' +import { + mergeVNodeHook, + isAsyncPlaceholder, + getFirstComponentChild +} from 'core/vdom/helpers/index' + +export const transitionProps = { + name: String, + appear: Boolean, + css: Boolean, + mode: String, + type: String, + enterClass: String, + leaveClass: String, + enterToClass: String, + leaveToClass: String, + enterActiveClass: String, + leaveActiveClass: String, + appearClass: String, + appearActiveClass: String, + appearToClass: String, + duration: [Number, String, Object] +} + +// in case the child is also an abstract component, e.g. +// we want to recursively retrieve the real component to be rendered +function getRealChild (vnode: ?VNode): ?VNode { + const compOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions + if (compOptions && compOptions.Ctor.options.abstract) { + return getRealChild(getFirstComponentChild(compOptions.children)) + } else { + return vnode + } +} + +export function extractTransitionData (comp: Component): Object { + const data = {} + const options: ComponentOptions = comp.$options + // props + for (const key in options.propsData) { + data[key] = comp[key] + } + // events. + // extract listeners and pass them directly to the transition methods + const listeners: ?Object = options._parentListeners + for (const key in listeners) { + data[camelize(key)] = listeners[key] + } + return data +} + +function placeholder (h: Function, rawChild: VNode): ?VNode { + if (/\d-keep-alive$/.test(rawChild.tag)) { + return h('keep-alive', { + props: rawChild.componentOptions.propsData + }) + } +} + +function hasParentTransition (vnode: VNode): ?boolean { + while ((vnode = vnode.parent)) { + if (vnode.data.transition) { + return true + } + } +} + +function isSameChild (child: VNode, oldChild: VNode): boolean { + return oldChild.key === child.key && oldChild.tag === child.tag +} + +export default { + name: 'transition', + props: transitionProps, + abstract: true, + + render (h: Function) { + let children: any = this.$slots.default + if (!children) { + return + } + + // filter out text nodes (possible whitespaces) + children = children.filter((c: VNode) => c.tag || isAsyncPlaceholder(c)) + /* istanbul ignore if */ + if (!children.length) { + return + } + + // warn multiple elements + if (process.env.NODE_ENV !== 'production' && children.length > 1) { + warn( + ' can only be used on a single element. Use ' + + ' for lists.', + this.$parent + ) + } + + const mode: string = this.mode + + // warn invalid mode + if (process.env.NODE_ENV !== 'production' && + mode && mode !== 'in-out' && mode !== 'out-in' + ) { + warn( + 'invalid mode: ' + mode, + this.$parent + ) + } + + const rawChild: VNode = children[0] + + // if this is a component root node and the component's + // parent container node also has transition, skip. + if (hasParentTransition(this.$vnode)) { + return rawChild + } + + // apply transition data to child + // use getRealChild() to ignore abstract components e.g. keep-alive + const child: ?VNode = getRealChild(rawChild) + /* istanbul ignore if */ + if (!child) { + return rawChild + } + + if (this._leaving) { + return placeholder(h, rawChild) + } + + // ensure a key that is unique to the vnode type and to this transition + // component instance. This key will be used to remove pending leaving nodes + // during entering. + const id: string = `__transition-${this._uid}-` + child.key = child.key == null + ? child.isComment + ? id + 'comment' + : id + child.tag + : isPrimitive(child.key) + ? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key) + : child.key + + const data: Object = (child.data || (child.data = {})).transition = extractTransitionData(this) + const oldRawChild: VNode = this._vnode + const oldChild: VNode = getRealChild(oldRawChild) + + // mark v-show + // so that the transition module can hand over the control to the directive + if (child.data.directives && child.data.directives.some(d => d.name === 'show')) { + child.data.show = true + } + + if ( + oldChild && + oldChild.data && + !isSameChild(child, oldChild) && + !isAsyncPlaceholder(oldChild) && + // #6687 component root is a comment node + !(oldChild.componentInstance && oldChild.componentInstance._vnode.isComment) + ) { + // replace old child transition data with fresh one + // important for dynamic transitions! + const oldData: Object = oldChild.data.transition = extend({}, data) + // handle transition mode + if (mode === 'out-in') { + // return placeholder node and queue update when leave finishes + this._leaving = true + mergeVNodeHook(oldData, 'afterLeave', () => { + this._leaving = false + this.$forceUpdate() + }) + return placeholder(h, rawChild) + } else if (mode === 'in-out') { + if (isAsyncPlaceholder(child)) { + return oldRawChild + } + let delayedLeave + const performLeave = () => { delayedLeave() } + mergeVNodeHook(data, 'afterEnter', performLeave) + mergeVNodeHook(data, 'enterCancelled', performLeave) + mergeVNodeHook(oldData, 'delayLeave', leave => { delayedLeave = leave }) + } + } + + return rawChild + } +} diff --git a/node_modules/vue/src/platforms/web/runtime/directives/index.js b/node_modules/vue/src/platforms/web/runtime/directives/index.js new file mode 100644 index 00000000..b673f11a --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/index.js @@ -0,0 +1,7 @@ +import model from './model' +import show from './show' + +export default { + model, + show +} diff --git a/node_modules/vue/src/platforms/web/runtime/directives/model.js b/node_modules/vue/src/platforms/web/runtime/directives/model.js new file mode 100644 index 00000000..cba8ded0 --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/model.js @@ -0,0 +1,147 @@ +/** + * Not type checking this file because flow doesn't like attaching + * properties to Elements. + */ + +import { isTextInputType } from 'web/util/element' +import { looseEqual, looseIndexOf } from 'shared/util' +import { mergeVNodeHook } from 'core/vdom/helpers/index' +import { warn, isIE9, isIE, isEdge } from 'core/util/index' + +/* istanbul ignore if */ +if (isIE9) { + // http://www.matts411.com/post/internet-explorer-9-oninput/ + document.addEventListener('selectionchange', () => { + const el = document.activeElement + if (el && el.vmodel) { + trigger(el, 'input') + } + }) +} + +const directive = { + inserted (el, binding, vnode, oldVnode) { + if (vnode.tag === 'select') { + // #6903 + if (oldVnode.elm && !oldVnode.elm._vOptions) { + mergeVNodeHook(vnode, 'postpatch', () => { + directive.componentUpdated(el, binding, vnode) + }) + } else { + setSelected(el, binding, vnode.context) + } + el._vOptions = [].map.call(el.options, getValue) + } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) { + el._vModifiers = binding.modifiers + if (!binding.modifiers.lazy) { + el.addEventListener('compositionstart', onCompositionStart) + el.addEventListener('compositionend', onCompositionEnd) + // Safari < 10.2 & UIWebView doesn't fire compositionend when + // switching focus before confirming composition choice + // this also fixes the issue where some browsers e.g. iOS Chrome + // fires "change" instead of "input" on autocomplete. + el.addEventListener('change', onCompositionEnd) + /* istanbul ignore if */ + if (isIE9) { + el.vmodel = true + } + } + } + }, + + componentUpdated (el, binding, vnode) { + if (vnode.tag === 'select') { + setSelected(el, binding, vnode.context) + // in case the options rendered by v-for have changed, + // it's possible that the value is out-of-sync with the rendered options. + // detect such cases and filter out values that no longer has a matching + // option in the DOM. + const prevOptions = el._vOptions + const curOptions = el._vOptions = [].map.call(el.options, getValue) + if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) { + // trigger change event if + // no matching option found for at least one value + const needReset = el.multiple + ? binding.value.some(v => hasNoMatchingOption(v, curOptions)) + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions) + if (needReset) { + trigger(el, 'change') + } + } + } + } +} + +function setSelected (el, binding, vm) { + actuallySetSelected(el, binding, vm) + /* istanbul ignore if */ + if (isIE || isEdge) { + setTimeout(() => { + actuallySetSelected(el, binding, vm) + }, 0) + } +} + +function actuallySetSelected (el, binding, vm) { + const value = binding.value + const isMultiple = el.multiple + if (isMultiple && !Array.isArray(value)) { + process.env.NODE_ENV !== 'production' && warn( + `