Skip to content

Commit 0257afb

Browse files
committed
proper component update diff
1 parent d1fc82d commit 0257afb

File tree

1 file changed

+119
-81
lines changed

1 file changed

+119
-81
lines changed

Diff for: src/runtime/instance/render.js

+119-81
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Watcher from '../observer/watcher'
2-
import { extend, query, resolveAsset, hasOwn } from '../util/index'
2+
import { extend, query, resolveAsset, hasOwn, isArray, isObject } from '../util/index'
33
import { createElement, patch, updateListeners } from '../vdom/index'
44
import { callHook } from './lifecycle'
55
import { getPropValue } from './state'
@@ -18,78 +18,6 @@ export function initRender (vm) {
1818
}
1919
}
2020

21-
function resolveSlots (vm, children) {
22-
if (children) {
23-
children = children.slice()
24-
const slots = { default: children }
25-
let i = children.length
26-
let name, child
27-
while (i--) {
28-
child = children[i]
29-
if ((name = child.data && child.data.slot)) {
30-
let slot = (slots[name] || (slots[name] = []))
31-
if (child.tag === 'template') {
32-
slot.push.apply(slot, child.children)
33-
} else {
34-
slot.push(child)
35-
}
36-
children.splice(i, 1)
37-
}
38-
}
39-
vm.$slots = slots
40-
}
41-
}
42-
43-
function mergeParentData (vm, data, parentData) {
44-
const props = vm.$options.props
45-
if (parentData.attrs) {
46-
const attrs = data.attrs || (data.attrs = {})
47-
for (let key in parentData.attrs) {
48-
if (!hasOwn(props, key)) {
49-
attrs[key] = parentData.attrs[key]
50-
}
51-
}
52-
}
53-
if (parentData.props) {
54-
const props = data.props || (data.props = {})
55-
for (let key in parentData.props) {
56-
if (!hasOwn(props, key)) {
57-
props[key] = parentData.props[key]
58-
}
59-
}
60-
}
61-
if (parentData.staticClass) {
62-
data.staticClass = data.staticClass
63-
? data.staticClass + ' ' + parentData.staticClass
64-
: parentData.staticClass
65-
}
66-
if (parentData.class) {
67-
extend((data.class || (data.class = {})), parentData.class)
68-
}
69-
if (parentData.style) {
70-
extend((data.style || (data.style = {})), parentData.style)
71-
}
72-
if (parentData.directives) {
73-
data.directives = parentData.directives.conact(data.directives || [])
74-
}
75-
if (parentData.on) {
76-
updateListeners(parentData.on, data.on || {}, (event, handler) => {
77-
vm.$on(event, handler)
78-
})
79-
}
80-
}
81-
82-
function updateProps (vm, data) {
83-
if (data.attrs || data.props) {
84-
for (let key in vm.$options.props) {
85-
let newVal = getPropValue(data, key)
86-
if (vm[key] !== newVal) {
87-
vm[key] = newVal
88-
}
89-
}
90-
}
91-
}
92-
9321
export function renderMixin (Vue) {
9422
// shorthands used in render functions
9523
Vue.prototype.__h__ = createElement
@@ -112,21 +40,21 @@ export function renderMixin (Vue) {
11240
}
11341
}
11442

115-
Vue.prototype._tryUpdate = function (data, children, key) {
43+
Vue.prototype._tryUpdate = function (parentData, children, key) {
44+
const oldParentData = this.$options._renderData
11645
this.$options._renderKey = key
117-
this.$options._renderData = data
46+
this.$options._renderData = parentData
11847
this.$options._renderChildren = children
119-
// set props - this will trigger update if any of them changed
120-
// but not guaranteed
121-
if (data) {
122-
updateProps(this, data)
48+
// update props and listeners
49+
if (parentData) {
50+
updateProps(this, parentData)
51+
updateEvents(this, parentData)
12352
}
12453
// for now, if the component has content it always updates
12554
// because we don't know whether the children have changed.
12655
// need to optimize in the future.
127-
if (children) {
56+
if (children || diffParentData(parentData, oldParentData)) {
12857
this.$forceUpdate()
129-
return
13058
}
13159
}
13260

@@ -172,3 +100,113 @@ export function renderMixin (Vue) {
172100
this._watcher.update()
173101
}
174102
}
103+
104+
function resolveSlots (vm, children) {
105+
if (children) {
106+
children = children.slice()
107+
const slots = { default: children }
108+
let i = children.length
109+
let name, child
110+
while (i--) {
111+
child = children[i]
112+
if ((name = child.data && child.data.slot)) {
113+
let slot = (slots[name] || (slots[name] = []))
114+
if (child.tag === 'template') {
115+
slot.push.apply(slot, child.children)
116+
} else {
117+
slot.push(child)
118+
}
119+
children.splice(i, 1)
120+
}
121+
}
122+
vm.$slots = slots
123+
}
124+
}
125+
126+
function diffParentData (data, oldData) {
127+
let key, old, cur
128+
for (key in oldData) {
129+
cur = data[key]
130+
old = oldData[key]
131+
if (key === 'on') continue
132+
if (!cur) return true
133+
if (isArray(old)) {
134+
if (!isArray(cur)) return true
135+
if (cur.length !== old.length) return true
136+
for (let i = 0; i < old.length; i++) {
137+
if (isObject(old[i])) {
138+
if (!isObject(cur[i])) return true
139+
if (diffObject(cur, old)) return true
140+
} else if (old[i] !== cur[i]) {
141+
return true
142+
}
143+
}
144+
} else if (diffObject(cur, old)) {
145+
return true
146+
}
147+
}
148+
}
149+
150+
function diffObject (cur, old) {
151+
for (var key in old) {
152+
if (cur[key] !== old[key]) return true
153+
}
154+
}
155+
156+
function mergeParentData (vm, data, parentData) {
157+
const props = vm.$options.props
158+
if (parentData.attrs) {
159+
const attrs = data.attrs || (data.attrs = {})
160+
for (let key in parentData.attrs) {
161+
if (!hasOwn(props, key)) {
162+
attrs[key] = parentData.attrs[key]
163+
}
164+
}
165+
}
166+
if (parentData.props) {
167+
const props = data.props || (data.props = {})
168+
for (let key in parentData.props) {
169+
if (!hasOwn(props, key)) {
170+
props[key] = parentData.props[key]
171+
}
172+
}
173+
}
174+
if (parentData.staticClass) {
175+
data.staticClass = data.staticClass
176+
? data.staticClass + ' ' + parentData.staticClass
177+
: parentData.staticClass
178+
}
179+
if (parentData.class) {
180+
if (!data.class) {
181+
data.class = parentData.class
182+
} else {
183+
data.class = (isArray(data.class) ? data.class : []).concat(parentData.class)
184+
}
185+
}
186+
if (parentData.style) {
187+
if (!data.style) {
188+
data.style = parentData.style
189+
} else {
190+
extend(data.style, parentData.style)
191+
}
192+
}
193+
if (parentData.directives) {
194+
data.directives = parentData.directives.conact(data.directives || [])
195+
}
196+
}
197+
198+
function updateProps (vm, data) {
199+
if (data.attrs || data.props) {
200+
for (let key in vm.$options.props) {
201+
vm[key] = getPropValue(data, key)
202+
}
203+
}
204+
}
205+
206+
function updateEvents (vm, data) {
207+
if (data.on) {
208+
updateListeners(data.on, vm._vnode.data.on || {}, (event, handler) => {
209+
vm.$on(event, handler)
210+
})
211+
}
212+
}

0 commit comments

Comments
 (0)