mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 12:07:39 +08:00
component wip
This commit is contained in:
parent
102b6f12ce
commit
f2c8880041
@ -7,9 +7,9 @@ export function generate (ast) {
|
||||
}
|
||||
|
||||
function genElement (el) {
|
||||
if (el['for']) {
|
||||
if (el.for) {
|
||||
return genFor(el)
|
||||
} else if (el['if']) {
|
||||
} else if (el.if) {
|
||||
return genIf(el)
|
||||
} else if (el.tag === 'template') {
|
||||
return genChildren(el)
|
||||
@ -21,15 +21,15 @@ function genElement (el) {
|
||||
}
|
||||
|
||||
function genIf (el) {
|
||||
const exp = el['if']
|
||||
el['if'] = false // avoid recursion
|
||||
const exp = el.if
|
||||
el.if = false // avoid recursion
|
||||
return `(${exp}) ? ${genElement(el)} : null`
|
||||
}
|
||||
|
||||
function genFor (el) {
|
||||
const exp = el['for']
|
||||
const exp = el.for
|
||||
const alias = el.alias
|
||||
el['for'] = false // avoid recursion
|
||||
el.for = false // avoid recursion
|
||||
return `(${exp}) && (${exp}).map(function (${alias}, $index) {return ${genElement(el)}})`
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ function processFor (el) {
|
||||
console.error(`Invalid v-for expression: ${exp}`)
|
||||
}
|
||||
el.alias = inMatch[1].trim()
|
||||
el['for'] = inMatch[2].trim()
|
||||
el.for = inMatch[2].trim()
|
||||
if ((exp = getAndRemoveAttr(el, 'track-by'))) {
|
||||
el.key = exp === '$index'
|
||||
? exp
|
||||
@ -146,7 +146,7 @@ function processFor (el) {
|
||||
function processIf (el) {
|
||||
let exp = getAndRemoveAttr(el, 'v-if')
|
||||
if (exp) {
|
||||
el['if'] = exp
|
||||
el.if = exp
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import config from './config'
|
||||
import * as util from './util/index'
|
||||
import h from './vdom/h'
|
||||
import { createElement } from './vdom/index'
|
||||
import {
|
||||
set,
|
||||
del,
|
||||
@ -15,7 +15,7 @@ import {
|
||||
} from './util/index'
|
||||
|
||||
export function initGlobalAPI (Vue) {
|
||||
Vue.h = h
|
||||
Vue.h = Vue.createElement = createElement
|
||||
Vue.config = config
|
||||
Vue.util = util
|
||||
Vue.set = set
|
||||
@ -98,12 +98,9 @@ export function initGlobalAPI (Vue) {
|
||||
*/
|
||||
|
||||
function createClass (name) {
|
||||
/* eslint-disable no-new-func */
|
||||
return new Function(
|
||||
'return function ' + classify(name) +
|
||||
' (options) { this._init(options) }'
|
||||
`return function ${classify(name)} (options) { this._init(options) }`
|
||||
)()
|
||||
/* eslint-enable no-new-func */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,10 @@ import { nextTick, mergeOptions } from '../util/index'
|
||||
let uid = 0
|
||||
|
||||
export default function Vue (options) {
|
||||
this._init(options)
|
||||
}
|
||||
|
||||
Vue.prototype._init = function (options) {
|
||||
// a uid
|
||||
this._uid = uid++
|
||||
// a flag to avoid this being observed
|
||||
@ -32,11 +36,11 @@ export default function Vue (options) {
|
||||
initRender(this)
|
||||
}
|
||||
|
||||
Vue.prototype.$nextTick = function (fn) {
|
||||
nextTick(fn, this)
|
||||
}
|
||||
|
||||
stateMixin(Vue)
|
||||
eventsMixin(Vue)
|
||||
lifecycleMixin(Vue)
|
||||
renderMixin(Vue)
|
||||
|
||||
Vue.prototype.$nextTick = function (fn) {
|
||||
nextTick(fn, this)
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
import Watcher from '../observer/watcher'
|
||||
import { query, resolveAsset } from '../util/index'
|
||||
import { h, patch } from '../vdom/index'
|
||||
import { query, resolveAsset, hyphenate } from '../util/index'
|
||||
import { createElement, patch } from '../vdom/index'
|
||||
import { callHook } from './lifecycle'
|
||||
|
||||
export function initRender (vm) {
|
||||
vm._vnode = null
|
||||
vm._mounted = false
|
||||
// TODO: handle _renderData and _renderChildren
|
||||
const el = vm.$options.el
|
||||
if (el) {
|
||||
vm.$mount(el)
|
||||
@ -13,33 +15,55 @@ export function initRender (vm) {
|
||||
|
||||
export function renderMixin (Vue) {
|
||||
// shorthands used in render functions
|
||||
Vue.prototype.__h__ = h
|
||||
Vue.prototype.__h__ = createElement
|
||||
Vue.prototype.__d__ = function (id) {
|
||||
return resolveAsset(this.$options, 'directives', id, true)
|
||||
}
|
||||
|
||||
Vue.prototype._update = function (vtree) {
|
||||
Vue.prototype._update = function (vnode) {
|
||||
callHook(this, 'beforeUpdate')
|
||||
if (!this._tree) {
|
||||
this.$el = patch(this.$el, vtree)
|
||||
if (!this._vnode) {
|
||||
this.$el = patch(this.$el, vnode)
|
||||
} else {
|
||||
this.$el = patch(this._tree, vtree)
|
||||
this.$el = patch(this._vnode, vnode)
|
||||
}
|
||||
this._tree = vtree
|
||||
this._vnode = vnode
|
||||
callHook(this, 'updated')
|
||||
}
|
||||
|
||||
Vue.prototype._tryUpdate = function (data, children) {
|
||||
if (children) {
|
||||
// TODO: handle content slots
|
||||
this.$forceUpdate()
|
||||
return
|
||||
}
|
||||
// check props
|
||||
const props = this.$options.props
|
||||
if (props && data.attrs) {
|
||||
for (let key in props) {
|
||||
let oldVal = this[key]
|
||||
let newVal = data.attrs[key] || data.attrs[hyphenate(key)]
|
||||
if (oldVal !== newVal) {
|
||||
this.$forceUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.prototype.$mount = function (el) {
|
||||
callHook(this, 'beforeMount')
|
||||
this.$el = el ? query(el) : document.createElement('div')
|
||||
this.$el.innerHTML = ''
|
||||
this.$el = el && query(el)
|
||||
if (this.$el) {
|
||||
this.$el.innerHTML = ''
|
||||
}
|
||||
this._watcher = new Watcher(this, this.$options.render, this._update)
|
||||
this._update(this._watcher.value)
|
||||
callHook(this, 'mounted')
|
||||
this._mounted = true
|
||||
return this
|
||||
}
|
||||
|
||||
Vue.prototype.$forceUpdate = function () {
|
||||
this._watcher.run()
|
||||
this._watcher.update()
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,17 @@ import {
|
||||
|
||||
export function initState (vm) {
|
||||
vm._watchers = []
|
||||
initProps(vm)
|
||||
initData(vm)
|
||||
initComputed(vm)
|
||||
initMethods(vm)
|
||||
initWatch(vm)
|
||||
}
|
||||
|
||||
function initProps (vm) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
function initData (vm) {
|
||||
var data = vm.$options.data
|
||||
data = vm._data = typeof data === 'function'
|
||||
|
@ -257,29 +257,30 @@ function guardComponents (options) {
|
||||
*/
|
||||
|
||||
function guardProps (options) {
|
||||
var props = options.props
|
||||
var i, val
|
||||
const res = {}
|
||||
const props = options.props
|
||||
let i, val
|
||||
if (isArray(props)) {
|
||||
options.props = {}
|
||||
i = props.length
|
||||
while (i--) {
|
||||
val = props[i]
|
||||
if (typeof val === 'string') {
|
||||
options.props[val] = null
|
||||
res[camelize(val)] = null
|
||||
} else if (val.name) {
|
||||
options.props[val.name] = val
|
||||
res[camelize(val.name)] = val
|
||||
}
|
||||
}
|
||||
} else if (isPlainObject(props)) {
|
||||
var keys = Object.keys(props)
|
||||
const keys = Object.keys(props)
|
||||
i = keys.length
|
||||
while (i--) {
|
||||
val = props[keys[i]]
|
||||
if (typeof val === 'function') {
|
||||
props[keys[i]] = { type: val }
|
||||
}
|
||||
res[camelize(keys[i])] = typeof val === 'function'
|
||||
? { type: val }
|
||||
: val
|
||||
}
|
||||
}
|
||||
options.props = res
|
||||
}
|
||||
|
||||
function guardDirectives (options) {
|
||||
|
45
src/runtime/vdom/component.js
Normal file
45
src/runtime/vdom/component.js
Normal file
@ -0,0 +1,45 @@
|
||||
import Vue from '../instance/index'
|
||||
|
||||
export default function Component (Ctor, data, children) {
|
||||
if (typeof Ctor === 'object') {
|
||||
Ctor = Vue.extend(Ctor)
|
||||
}
|
||||
// return a placeholder vnode
|
||||
return {
|
||||
sel: 'component',
|
||||
data: {
|
||||
hooks: { init, prepatch, destroy },
|
||||
Ctor, data, children
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init (vnode) {
|
||||
const data = vnode.data
|
||||
const child = new data.Ctor({
|
||||
_renderData: data.data,
|
||||
_renderChildren: data.children
|
||||
}).$mount()
|
||||
data.child = child
|
||||
data.vnode = child._vnode
|
||||
}
|
||||
|
||||
function prepatch (oldVnode, vnode) {
|
||||
const old = oldVnode.data
|
||||
const cur = vnode.data
|
||||
if (cur.Ctor !== old.Ctor) {
|
||||
// component changed, teardown and create new
|
||||
// TODO: keep-alive?
|
||||
old.child.$destroy()
|
||||
init(vnode)
|
||||
} else {
|
||||
// try re-render child. the child may optimize it
|
||||
// and just does nothing.
|
||||
old.child._tryUpdate(cur.data, cur.children)
|
||||
cur.vnode = old.child._vnode
|
||||
}
|
||||
}
|
||||
|
||||
function destroy (vnode) {
|
||||
vnode.data.childComponent.$destroy()
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import VNode from './vnode'
|
||||
import Component from './component'
|
||||
import { isPrimitive, isArray } from '../util/index'
|
||||
|
||||
export default function h (tag, data, children) {
|
||||
export default function createElement (tag, data, children) {
|
||||
if (isArray(children)) {
|
||||
let _children = children
|
||||
children = []
|
||||
@ -22,5 +23,9 @@ export default function h (tag, data, children) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return VNode(tag, data, children, undefined, undefined)
|
||||
if (typeof tag === 'string') {
|
||||
return VNode(tag, data, children)
|
||||
} else {
|
||||
return Component(tag, data, children)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import createPatchFunction from './patch'
|
||||
import h from './h'
|
||||
import createElement from './create-element'
|
||||
import classes from './modules/class'
|
||||
import style from './modules/style'
|
||||
import props from './modules/props'
|
||||
@ -22,4 +22,4 @@ const patch = createPatchFunction([
|
||||
directives
|
||||
])
|
||||
|
||||
export { patch, h }
|
||||
export { patch, createElement }
|
||||
|
@ -2,7 +2,7 @@ import VNode from './vnode'
|
||||
import * as dom from './dom'
|
||||
import { isPrimitive } from '../util/index'
|
||||
|
||||
const emptyNode = VNode('', {}, [], undefined, undefined)
|
||||
const emptyNode = VNode('', {}, [])
|
||||
const hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post']
|
||||
const svgNS = 'http://www.w3.org/2000/svg'
|
||||
|
||||
@ -241,21 +241,25 @@ export default function createPatchFunction (modules, api) {
|
||||
var insertedVnodeQueue = []
|
||||
for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]()
|
||||
|
||||
if (isUndef(oldVnode.sel)) {
|
||||
oldVnode = emptyNodeAt(oldVnode)
|
||||
}
|
||||
|
||||
if (sameVnode(oldVnode, vnode)) {
|
||||
patchVnode(oldVnode, vnode, insertedVnodeQueue)
|
||||
} else {
|
||||
elm = oldVnode.elm
|
||||
parent = api.parentNode(elm)
|
||||
|
||||
if (!oldVnode) {
|
||||
createElm(vnode, insertedVnodeQueue)
|
||||
} else {
|
||||
if (isUndef(oldVnode.sel)) {
|
||||
oldVnode = emptyNodeAt(oldVnode)
|
||||
}
|
||||
|
||||
if (parent !== null) {
|
||||
api.insertBefore(parent, vnode.elm, api.nextSibling(elm))
|
||||
removeVnodes(parent, [oldVnode], 0, 0)
|
||||
if (sameVnode(oldVnode, vnode)) {
|
||||
patchVnode(oldVnode, vnode, insertedVnodeQueue)
|
||||
} else {
|
||||
elm = oldVnode.elm
|
||||
parent = api.parentNode(elm)
|
||||
|
||||
createElm(vnode, insertedVnodeQueue)
|
||||
|
||||
if (parent !== null) {
|
||||
api.insertBefore(parent, vnode.elm, api.nextSibling(elm))
|
||||
removeVnodes(parent, [oldVnode], 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
29
src/runtime/vdom/thunk.js
Normal file
29
src/runtime/vdom/thunk.js
Normal file
@ -0,0 +1,29 @@
|
||||
import createElement from './create-element'
|
||||
|
||||
function init (thunk) {
|
||||
var i, cur = thunk.data
|
||||
cur.vnode = cur.fn.apply(undefined, cur.args)
|
||||
}
|
||||
|
||||
function prepatch (oldThunk, thunk) {
|
||||
var i, old = oldThunk.data, cur = thunk.data
|
||||
var oldArgs = old.args, args = cur.args
|
||||
cur.vnode = old.vnode
|
||||
if (old.fn !== cur.fn || oldArgs.length !== args.length) {
|
||||
cur.vnode = cur.fn.apply(undefined, args)
|
||||
return
|
||||
}
|
||||
for (i = 0; i < args.length; ++i) {
|
||||
if (oldArgs[i] !== args[i]) {
|
||||
cur.vnode = cur.fn.apply(undefined, args)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function thunk (name, fn, args) {
|
||||
return createElement('thunk' + name, {
|
||||
hook: { init, prepatch },
|
||||
fn, args
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user