Skip to content

Commit cf8aedd

Browse files
committed
fix v-once with v-for and remove unused _t method (fix vuejs#3155)
1 parent 3f91f65 commit cf8aedd

File tree

10 files changed

+47
-51
lines changed

10 files changed

+47
-51
lines changed

flow/compiler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ declare type ASTElement = {
6565

6666
static?: boolean,
6767
staticRoot?: boolean,
68+
staticProcessed?: boolean,
6869

6970
text?: string,
7071
attrs?: Array<{ name: string, value: string }>,

flow/component.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ declare interface Component {
8787
data?: Object,
8888
namespace?: string
8989
) => VNode | void;
90-
// renderText
91-
_t: (
92-
str?: string
93-
) => string;
9490
// renderStaticTree
9591
_m: (
9692
index?: number

src/compiler/codegen.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ export function generate (
3939
}
4040

4141
function genElement (el: ASTElement): string {
42-
if (el.for && !el.forProcessed) {
42+
if (el.staticRoot && !el.staticProcessed) {
43+
// hoist static sub-trees out
44+
el.staticProcessed = true
45+
staticRenderFns.push(`with(this){return ${genElement(el)}}`)
46+
return `_m(${staticRenderFns.length - 1})`
47+
} else if (el.for && !el.forProcessed) {
4348
return genFor(el)
4449
} else if (el.if && !el.ifProcessed) {
4550
return genIf(el)
@@ -66,11 +71,6 @@ function genElement (el: ASTElement): string {
6671
})${
6772
children ? `,${children}` : '' // children
6873
})`
69-
if (el.staticRoot) {
70-
// hoist static sub-trees out
71-
staticRenderFns.push(`with(this){return ${code}}`)
72-
code = `_m(${staticRenderFns.length - 1})`
73-
}
7474
}
7575
// module transforms
7676
for (let i = 0; i < transforms.length; i++) {
@@ -239,8 +239,8 @@ function genNode (node: ASTNode) {
239239

240240
function genText (text: ASTText | ASTExpression): string {
241241
return text.type === 2
242-
? `(${text.expression})`
243-
: '_t(' + JSON.stringify(text.text) + ')'
242+
? text.expression // no need for () because already wrapped in _s()
243+
: JSON.stringify(text.text)
244244
}
245245

246246
function genSlot (el: ASTElement): string {

src/core/instance/render.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import VNode, { emptyVNode } from '../vdom/vnode'
55
import { normalizeChildren } from '../vdom/helpers'
66
import {
77
warn, bind, isObject, toObject,
8-
nextTick, resolveAsset, renderString, toNumber
8+
nextTick, resolveAsset, _toString, toNumber
99
} from '../util/index'
1010

1111
import {
1212
renderElement,
1313
renderElementWithChildren,
14-
renderText,
1514
renderStatic
1615
} from '../vdom/create-element'
1716

@@ -91,11 +90,9 @@ export function renderMixin (Vue: Class<Component>) {
9190
// shorthands used in render functions
9291
Vue.prototype._h = renderElementWithChildren
9392
Vue.prototype._e = renderElement
94-
Vue.prototype._t = renderText
9593
Vue.prototype._m = renderStatic
96-
9794
// toString for mustaches
98-
Vue.prototype._s = renderString
95+
Vue.prototype._s = _toString
9996
// number conversion
10097
Vue.prototype._n = toNumber
10198

src/core/vdom/create-element.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ export function renderElement (
9898
}
9999
}
100100

101-
export function renderText (str?: string): string {
102-
return str || ''
103-
}
104-
105101
export function renderStatic (index?: number): Object | void {
106102
return this._staticTrees[index] || (
107103
this._staticTrees[index] = this.$options.staticRenderFns[index].call(

src/core/vdom/patch.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import VNode from './vnode'
11-
import { isPrimitive, renderString, warn } from '../util/index'
11+
import { isPrimitive, _toString, warn } from '../util/index'
1212

1313
const emptyNode = new VNode('', {}, [])
1414
const hooks = ['create', 'update', 'postpatch', 'remove', 'destroy']
@@ -349,7 +349,7 @@ export function createPatchFunction (backend) {
349349
)
350350
}
351351
} else {
352-
return renderString(vnode.text) === node.data
352+
return _toString(vnode.text) === node.data
353353
}
354354
}
355355

src/shared/util.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* Convert a value to a string that is actually rendered.
55
*/
6-
export function renderString (val: any): string {
6+
export function _toString (val: any): string {
77
return val == null
88
? ''
99
: typeof val === 'object'

test/unit/features/directives/once.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,18 @@ describe('Directive v-once', () => {
9191
.toBe('<span>hello</span> <div>world</div> <span>!</span>')
9292
}).then(done)
9393
})
94+
95+
it('should work with v-for', done => {
96+
const vm = new Vue({
97+
data: {
98+
list: [1, 2, 3]
99+
},
100+
template: `<div><div v-for="i in list" v-once>{{i}}</div></div>`
101+
}).$mount()
102+
expect(vm.$el.textContent).toBe('123')
103+
vm.list.reverse()
104+
waitForUpdate(() => {
105+
expect(vm.$el.textContent).toBe('123')
106+
}).then(done)
107+
})
94108
})

test/unit/modules/compiler/codegen.spec.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ describe('codegen', () => {
5757
it('generate v-if directive', () => {
5858
assertCodegen(
5959
'<p v-if="show">hello</p>',
60-
`with(this){return (show)?_h(_e('p'),[_t("hello")]):void 0}`
60+
`with(this){return (show)?_h(_e('p'),["hello"]):void 0}`
6161
)
6262
})
6363

6464
it('generate v-else directive', () => {
6565
assertCodegen(
6666
'<div><p v-if="show">hello</p><p v-else>world</p></div>',
67-
`with(this){return _h(_e('div'),[(show)?_h(_e('p'),[_t("hello")]):_h(_e('p'),[_t("world")])])}`
67+
`with(this){return _h(_e('div'),[(show)?_h(_e('p'),["hello"]):_h(_e('p'),["world"])])}`
6868
)
6969
})
7070

@@ -91,15 +91,15 @@ describe('codegen', () => {
9191

9292
it('generate template tag', () => {
9393
assertCodegen(
94-
'<template><p>hello world</p></template>',
95-
`with(this){return [_h(_e('p'),[_t("hello world")])]}`
94+
'<template><p>{{hello}}</p></template>',
95+
`with(this){return [_h(_e('p'),[_s(hello)])]}`
9696
)
9797
})
9898

9999
it('generate svg tag', () => {
100100
assertCodegen(
101101
'<svg><text>hello world</text></svg>',
102-
`with(this){return _h(_e('svg',void 0,'svg'),[_h(_e('text',void 0,'svg'),[_t("hello world")])])}`
102+
`with(this){return _h(_e('svg',void 0,'svg'),[_h(_e('text',void 0,'svg'),["hello world"])])}`
103103
)
104104
})
105105

@@ -131,14 +131,14 @@ describe('codegen', () => {
131131
assertCodegen(
132132
'<slot><div>hi</div></slot>',
133133
`with(this){return ($slots["default"]||[_m(0)])}`,
134-
[`with(this){return _h(_e('div'),[_t("hi")])}`]
134+
[`with(this){return _h(_e('div'),["hi"])}`]
135135
)
136136
})
137137

138138
it('generate slot target', () => {
139139
assertCodegen(
140140
'<p slot="one">hello world</p>',
141-
`with(this){return _h(_e('p',{slot:"one"}),[_t("hello world")])}`
141+
`with(this){return _h(_e('p',{slot:"one"}),["hello world"])}`
142142
)
143143
})
144144

@@ -147,40 +147,40 @@ describe('codegen', () => {
147147
assertCodegen(
148148
'<p class="class1">hello world</p>',
149149
'with(this){return _m(0)}',
150-
[`with(this){return _h(_e('p',{staticClass:"class1"}),[_t("hello world")])}`]
150+
[`with(this){return _h(_e('p',{staticClass:"class1"}),["hello world"])}`]
151151
)
152152
// dynamic
153153
assertCodegen(
154154
'<p :class="class1">hello world</p>',
155-
`with(this){return _h(_e('p',{class:class1}),[_t("hello world")])}`
155+
`with(this){return _h(_e('p',{class:class1}),["hello world"])}`
156156
)
157157
})
158158

159159
it('generate style binding', () => {
160160
assertCodegen(
161161
'<p :style="error">hello world</p>',
162-
`with(this){return _h(_e('p',{style:(error)}),[_t("hello world")])}`
162+
`with(this){return _h(_e('p',{style:(error)}),["hello world"])}`
163163
)
164164
})
165165

166166
it('generate transition', () => {
167167
assertCodegen(
168168
'<p transition="expand">hello world</p>',
169-
`with(this){return _h(_e('p',{transition:"expand"}),[_t("hello world")])}`
169+
`with(this){return _h(_e('p',{transition:"expand"}),["hello world"])}`
170170
)
171171
})
172172

173173
it('generate dynamic transition with transition on appear', () => {
174174
assertCodegen(
175175
`<p :transition="{name:'expand',appear:true}">hello world</p>`,
176-
`with(this){return _h(_e('p',{transition:{name:'expand',appear:true}}),[_t("hello world")])}`
176+
`with(this){return _h(_e('p',{transition:{name:'expand',appear:true}}),["hello world"])}`
177177
)
178178
})
179179

180180
it('generate v-show directive', () => {
181181
assertCodegen(
182182
'<p v-show="shown">hello world</p>',
183-
`with(this){return _h(_e('p',{directives:[{name:"show",value:(shown),expression:"shown"}],show:true}),[_t("hello world")])}`
183+
`with(this){return _h(_e('p',{directives:[{name:"show",value:(shown),expression:"shown"}],show:true}),["hello world"])}`
184184
)
185185
})
186186

@@ -292,7 +292,7 @@ describe('codegen', () => {
292292
assertCodegen(
293293
'<my-component name="mycomponent1" :msg="msg" @notify="onNotify"><div>hi</div></my-component>',
294294
`with(this){return _h(_e('my-component',{attrs:{"msg":msg},staticAttrs:{"name":"mycomponent1"},on:{"notify":onNotify}}),function(){return [_m(0)]})}`,
295-
[`with(this){return _h(_e('div'),[_t("hi")])}`]
295+
[`with(this){return _h(_e('div'),["hi"])}`]
296296
)
297297
})
298298

@@ -311,7 +311,7 @@ describe('codegen', () => {
311311
// have "inline-template'"
312312
assertCodegen(
313313
'<my-component inline-template><p>hello world</p></my-component>',
314-
`with(this){return _h(_e('my-component',{inlineTemplate:{render:function(){with(this){return _m(0)}},staticRenderFns:[function(){with(this){return _h(_e('p'),[_t("hello world")])}}]}}))}`
314+
`with(this){return _h(_e('my-component',{inlineTemplate:{render:function(){with(this){return _m(0)}},staticRenderFns:[function(){with(this){return _h(_e('p'),["hello world"])}}]}}))}`
315315
)
316316
// "have inline-template attrs, but not having extactly one child element
317317
assertCodegen(
@@ -330,7 +330,7 @@ describe('codegen', () => {
330330
it('not specified directives option', () => {
331331
assertCodegen(
332332
'<p v-if="show">hello world</p>',
333-
`with(this){return (show)?_h(_e('p'),[_t("hello world")]):void 0}`,
333+
`with(this){return (show)?_h(_e('p'),["hello world"]):void 0}`,
334334
{ isReservedTag }
335335
)
336336
})
@@ -341,7 +341,7 @@ describe('codegen', () => {
341341
assertCodegen(
342342
'<div><p>hello world</p></div>',
343343
`with(this){return _m(0)}`,
344-
[`with(this){return _h(_e('div'),function(){return [_h(_e('p'),function(){return [_t("hello world")]})]})}`],
344+
[`with(this){return _h(_e('div'),function(){return [_h(_e('p'),function(){return ["hello world"]})]})}`],
345345
{ directives }
346346
)
347347
})

test/unit/modules/vdom/create-element.spec.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { renderState } from 'core/instance/render'
33
import {
44
renderElement,
55
renderElementWithChildren,
6-
renderText,
76
renderStatic
87
} from 'core/vdom/create-element'
98
import { emptyVNode } from 'core/vdom/vnode'
@@ -107,11 +106,6 @@ describe('create-element', () => {
107106
expect('createElement cannot be called outside of component').toHaveBeenWarned()
108107
})
109108

110-
it('renderText', () => {
111-
expect(renderText('hello')).toBe('hello')
112-
expect(renderText()).toBe('')
113-
})
114-
115109
it('renderStatic', done => {
116110
const vm = new Vue({
117111
template: '<p>hello world</p>'
@@ -130,12 +124,11 @@ describe('create-element', () => {
130124

131125
it('render vnode with renderElementWithChildren', () => {
132126
const vm = new Vue({})
133-
const _t = renderText
134127
const _e = bind(renderElement, vm)
135128
const _h = bind(renderElementWithChildren, vm)
136129
renderState.activeInstance = vm
137130
const parent = _e('p', {})
138-
const children = [_e('br'), _t('hello world'), _e('br')]
131+
const children = [_e('br'), 'hello world', _e('br')]
139132
const vnode = _h(parent, children)
140133
expect(vnode.children[0].tag).toBe('br')
141134
expect(vnode.children[1].text).toBe('hello world')
@@ -151,12 +144,11 @@ describe('create-element', () => {
151144
}
152145
}
153146
})
154-
const _t = renderText
155147
const _e = bind(renderElement, vm)
156148
const _h = bind(renderElementWithChildren, vm)
157149
renderState.activeInstance = vm
158150
const parent = _e('my-component', { props: { msg: vm.message }})
159-
const children = [_e('br'), _t('hello world'), _e('br')]
151+
const children = [_e('br'), 'hello world', _e('br')]
160152
const vnode = _h(parent, children)
161153
expect(vnode.componentOptions.children[0].tag).toBe('br')
162154
expect(vnode.componentOptions.children[1]).toBe('hello world')

0 commit comments

Comments
 (0)