From 09a4ba84a9e4a0219423c85599fea87c1d34737d Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 16 Apr 2016 17:18:12 -0400 Subject: [PATCH] refs --- src/compiler/codegen/directives/el.js | 4 ++++ src/compiler/codegen/directives/index.js | 11 +++++++-- src/compiler/codegen/directives/ref.js | 3 +++ src/compiler/codegen/index.js | 29 ++++++++++++++---------- src/compiler/parser/index.js | 15 ++++++++---- src/compiler/parser/text-parser.js | 2 +- src/runtime/instance/lifecycle.js | 13 +++++++++-- src/runtime/instance/render.js | 10 ++++---- src/runtime/vdom/component.js | 11 ++++----- src/runtime/vdom/create-element.js | 4 ++-- 10 files changed, 69 insertions(+), 33 deletions(-) create mode 100644 src/compiler/codegen/directives/el.js create mode 100644 src/compiler/codegen/directives/ref.js diff --git a/src/compiler/codegen/directives/el.js b/src/compiler/codegen/directives/el.js new file mode 100644 index 000000000..7d92cdc17 --- /dev/null +++ b/src/compiler/codegen/directives/el.js @@ -0,0 +1,4 @@ +export function el (el, dir) { + console.log(el) + console.log(dir) +} diff --git a/src/compiler/codegen/directives/index.js b/src/compiler/codegen/directives/index.js index 268dbd1ba..90630a63c 100644 --- a/src/compiler/codegen/directives/index.js +++ b/src/compiler/codegen/directives/index.js @@ -1,11 +1,15 @@ import { model } from './model' import { show } from './show' import { html } from './html' +import { ref } from './ref' +import { el } from './el' export const directives = { model, show, html, + ref, + el, cloak: function () {} // noop } @@ -13,8 +17,9 @@ export function genDirectives (el) { const dirs = el.directives let res = 'directives:[' let hasRuntime = false - for (let i = 0; i < dirs.length; i++) { - let dir = dirs[i] + let i, l, dir + for (i = 0, l = dirs.length; i < l; i++) { + dir = dirs[i] let gen = directives[dir.name] if (gen) { // compile-time directive that manipulates AST @@ -24,6 +29,8 @@ export function genDirectives (el) { hasRuntime = true res += `{def:__d__("${dir.name}")${ dir.value ? `,value:(${dir.value})` : '' + }${ + dir.arg ? `,arg:"${dir.arg}"` : '' }${ dir.modifiers ? `,modifiers:${JSON.stringify(dir.modifiers)}` : '' }},` diff --git a/src/compiler/codegen/directives/ref.js b/src/compiler/codegen/directives/ref.js new file mode 100644 index 000000000..8cfa210a3 --- /dev/null +++ b/src/compiler/codegen/directives/ref.js @@ -0,0 +1,3 @@ +export function ref (el, dir) { + el.ref = dir.arg +} diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index 72fcec488..57b60bffe 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -52,24 +52,29 @@ function genData (el) { let data = '{' - // key - if (el.key) { - data += `key:${el.key},` - } - // slot names - if (el.attrsMap.slot) { - data += `slot:"${el.attrsMap.slot}",` - } - // svg - if (el.svg) { - data += 'svg:true,' - } // directives first. // directives may mutate the el's other properties before they are generated. if (el.directives) { let dirs = genDirectives(el) if (dirs) data += dirs + ',' } + + // svg + if (el.svg) { + data += 'svg:true,' + } + // key + if (el.key) { + data += `key:${el.key},` + } + // ref + if (el.ref) { + data += `ref:"${el.ref}",` + } + // slot names + if (el.attrsMap.slot) { + data += `slot:"${el.attrsMap.slot}",` + } // class if (el.staticClass) { data += `staticClass:"${el.staticClass}",` diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index b82bb170a..2a31d98b9 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -6,6 +6,7 @@ import { addHandler } from '../helpers' const dirRE = /^v-|^@|^:/ const bindRE = /^:|^v-bind:/ const onRE = /^@|^v-on:/ +const argRE = /:(.*)$/ const modifierRE = /\.[^\.]+/g const mustUsePropsRE = /^(value|selected|checked|muted)$/ const forAliasRE = /([a-zA-Z_][\w]*)\s+(?:in|of)\s+(.*)/ @@ -213,12 +214,13 @@ function processStyleBinding (el) { function processAttributes (el) { const list = el.attrsList - for (let i = 0; i < list.length; i++) { - let name = list[i].name - let value = list[i].value + let i, l, name, value, arg, modifiers + for (i = 0, l = list.length; i < l; i++) { + name = list[i].name + value = list[i].value if (dirRE.test(name)) { // modifiers - const modifiers = parseModifiers(name) + modifiers = parseModifiers(name) if (modifiers) { name = name.replace(modifierRE, '') } @@ -234,9 +236,14 @@ function processAttributes (el) { addHandler((el.events || (el.events = {})), name, value, modifiers) } else { // normal directives name = name.replace(dirRE, '') + // parse arg + if ((arg = name.match(argRE)) && (arg = arg[1])) { + name = name.slice(0, -(arg.length + 1)) + } ;(el.directives || (el.directives = [])).push({ name, value, + arg, modifiers }) } diff --git a/src/compiler/parser/text-parser.js b/src/compiler/parser/text-parser.js index 43aacd915..219e4a654 100644 --- a/src/compiler/parser/text-parser.js +++ b/src/compiler/parser/text-parser.js @@ -15,7 +15,7 @@ export function parseText (text) { } // tag token const exp = match[1].trim() - tokens.push(`((${exp})==null?'':${exp})`) + tokens.push(`((${exp})==null?'':__s__(${exp}))`) lastIndex = index + match[0].length } if (lastIndex < text.length) { diff --git a/src/runtime/instance/lifecycle.js b/src/runtime/instance/lifecycle.js index 488c335e5..1f03f1eb6 100644 --- a/src/runtime/instance/lifecycle.js +++ b/src/runtime/instance/lifecycle.js @@ -14,11 +14,17 @@ export function callHook (vm, hook) { export function initLifecycle (vm) { const options = vm.$options + // parent vm.$parent = options.parent vm.$root = vm.$parent ? vm.$parent.$root : vm if (vm.$parent) { vm.$parent.$children.push(vm) - // TODO: handle ref + } + // context & ref + vm._context = options._context + vm._ref = options._renderData && options._renderData.ref + if (vm._ref) { + vm._context.$refs[vm._ref] = vm } vm.$children = [] vm.$refs = {} @@ -58,7 +64,10 @@ export function lifecycleMixin (Vue) { const parent = this.$parent if (parent && !parent._isBeingDestroyed) { parent.$children.$remove(this) - // TODO: handle ref + } + // unregister ref + if (this._ref) { + this._context.$refs[this._ref] = undefined } // teardown watchers let i = this._watchers.length diff --git a/src/runtime/instance/render.js b/src/runtime/instance/render.js index 98c03534e..4376f7abe 100644 --- a/src/runtime/instance/render.js +++ b/src/runtime/instance/render.js @@ -25,6 +25,11 @@ export function renderMixin (Vue) { return resolveAsset(this.$options, 'directives', id, true) } + Vue.prototype.__s__ = function (val) { + console.log(val) + return typeof val === 'string' ? val : JSON.stringify(val) + } + Vue.prototype._update = function (vnode) { if (this._mounted) { callHook(this, 'beforeUpdate') @@ -42,7 +47,6 @@ export function renderMixin (Vue) { Vue.prototype._updateFromParent = function (parentData, children, key) { const oldParentData = this.$options._renderData - this.$options._renderKey = key this.$options._renderData = parentData this.$options._renderChildren = children // update props and listeners @@ -77,7 +81,7 @@ export function renderMixin (Vue) { Vue.prototype._render = function () { const prev = renderState.activeInstance renderState.activeInstance = this - const { render, _renderKey, _renderData, _renderChildren } = this.$options + const { render, _renderData, _renderChildren } = this.$options // resolve slots. becaues slots are rendered in parent scope, // we set the activeInstance to parent. if (_renderChildren) { @@ -85,8 +89,6 @@ export function renderMixin (Vue) { } // render self const vnode = render.call(this) - // set key - vnode.key = _renderKey // update parent data if (_renderData) { mergeParentData(this, vnode.data, _renderData) diff --git a/src/runtime/vdom/component.js b/src/runtime/vdom/component.js index 722443c54..e41422790 100644 --- a/src/runtime/vdom/component.js +++ b/src/runtime/vdom/component.js @@ -1,18 +1,17 @@ import Vue from '../instance/index' import { callHook } from '../instance/lifecycle' -export default function Component (Ctor, data, parent, children) { +export default function Component (Ctor, data, parent, children, context) { if (typeof Ctor === 'object') { Ctor = Vue.extend(Ctor) } // return a placeholder vnode - const key = data && data.key return { tag: 'component', - key, + key: data && data.key, data: { hook: { init, insert, prepatch, destroy }, - Ctor, data, parent, children + Ctor, data, parent, children, context } } } @@ -21,9 +20,9 @@ function init (vnode) { const data = vnode.data const child = new data.Ctor({ parent: data.parent, + _context: data.context, _renderData: data.data, - _renderChildren: data.children, - _renderKey: vnode.key + _renderChildren: data.children }) child.$mount() data.child = child diff --git a/src/runtime/vdom/create-element.js b/src/runtime/vdom/create-element.js index 3fed807cd..c5b0a1c1c 100644 --- a/src/runtime/vdom/create-element.js +++ b/src/runtime/vdom/create-element.js @@ -17,7 +17,7 @@ export default function createElement (tag, data, children) { if (isReservedTag(tag)) { return VNode(tag, data, flatten(children)) } else if ((Ctor = resolveAsset(context.$options, 'components', tag))) { - return Component(Ctor, data, parent, children) + return Component(Ctor, data, parent, children, context) } else { if (process.env.NODE_ENV !== 'production' && !data.svg) { warn( @@ -29,7 +29,7 @@ export default function createElement (tag, data, children) { return VNode(tag, data, flatten(children && children())) } } else { - return Component(tag, data, parent, children) + return Component(tag, data, parent, children, context) } }