diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js
index 4fd183b5dab..937e037cb50 100644
--- a/src/compiler/codegen/index.js
+++ b/src/compiler/codegen/index.js
@@ -85,7 +85,9 @@ function genStatic (el: ASTElement): string {
// v-once
function genOnce (el: ASTElement): string {
el.onceProcessed = true
- if (el.staticInFor) {
+ if (el.if && !el.ifProcessed) {
+ return genIf(el)
+ } else if (el.staticInFor) {
let key = ''
let parent = el.parent
while (parent) {
@@ -107,10 +109,11 @@ function genOnce (el: ASTElement): string {
}
}
+// v-if with v-once shuold generate code like (a)?_m(0):_m(1)
function genIf (el: any): string {
const exp = el.if
el.ifProcessed = true // avoid recursion
- return `(${exp})?${genElement(el)}:${genElse(el)}`
+ return `(${exp})?${el.once ? genOnce(el) : genElement(el)}:${genElse(el)}`
}
function genElse (el: ASTElement): string {
diff --git a/src/compiler/optimizer.js b/src/compiler/optimizer.js
index 991a677e137..7caecbe9903 100644
--- a/src/compiler/optimizer.js
+++ b/src/compiler/optimizer.js
@@ -59,7 +59,12 @@ function markStaticRoots (node: ASTNode, isInFor: boolean) {
}
if (node.children) {
for (let i = 0, l = node.children.length; i < l; i++) {
- markStaticRoots(node.children[i], isInFor || !!node.for)
+ const child = node.children[i]
+ isInFor = isInFor || !!node.for
+ markStaticRoots(child, isInFor)
+ if (child.type === 1 && child.elseBlock) {
+ markStaticRoots(child.elseBlock, isInFor)
+ }
}
}
}
diff --git a/test/unit/features/directives/once.spec.js b/test/unit/features/directives/once.spec.js
index b7ada2f4584..50791edcdbe 100644
--- a/test/unit/features/directives/once.spec.js
+++ b/test/unit/features/directives/once.spec.js
@@ -15,10 +15,11 @@ describe('Directive v-once', () => {
it('should not rerender self and child component', done => {
const vm = new Vue({
- template: `
- {{ a }}
-
-
`,
+ template: `
+
+ {{ a }}
+
+
`,
data: { a: 'hello' },
components: {
item: {
@@ -39,10 +40,11 @@ describe('Directive v-once', () => {
it('should rerender parent but not self', done => {
const vm = new Vue({
- template: `
- {{ a }}
-
-
`,
+ template: `
+
+ {{ a }}
+
+
`,
data: { a: 'hello' },
components: {
item: {
@@ -63,11 +65,12 @@ describe('Directive v-once', () => {
it('should not rerender static sub nodes', done => {
const vm = new Vue({
- template: `
- {{ a }}
-
- {{ suffix }}
-
`,
+ template: `
+
+ {{ a }}
+
+ {{ suffix }}
+
`,
data: {
a: 'hello',
suffix: '?'
@@ -92,6 +95,39 @@ describe('Directive v-once', () => {
}).then(done)
})
+ it('should work with v-if', done => {
+ const vm = new Vue({
+ data: {
+ tester: true,
+ yes: 'y',
+ no: 'n'
+ },
+ template: `
+
+
{{ yes }}
+
{{ no }}
+
{{ yes }}
+
{{ no }}
+
{{ yes }}
+
{{ no }}
+
{{ yes }}
+
{{ no }}
+
+ `
+ }).$mount()
+ expectTextContent(vm, 'yyyy')
+ vm.yes = 'yes'
+ waitForUpdate(() => {
+ expectTextContent(vm, 'yesyyesy')
+ vm.tester = false
+ }).then(() => {
+ expectTextContent(vm, 'nnnn')
+ vm.no = 'no'
+ }).then(() => {
+ expectTextContent(vm, 'nononn')
+ }).then(done)
+ })
+
it('should work with v-for', done => {
const vm = new Vue({
data: {
@@ -140,6 +176,43 @@ describe('Directive v-once', () => {
}).then(done)
})
+ it('should work inside v-for with v-if', done => {
+ const vm = new Vue({
+ data: {
+ list: [
+ { id: 0, text: 'a', tester: true, truthy: 'y' }
+ ]
+ },
+ template: `
+
+
+ {{ i.truthy }}
+ {{ i.text }}
+ {{ i.truthy }}
+ {{ i.text }}
+ {{ i.truthy }}
+ {{ i.text }}
+ {{ i.truthy }}
+ {{ i.text }}
+
+
+ `
+ }).$mount()
+
+ expectTextContent(vm, 'yyyy')
+
+ vm.list[0].truthy = 'yy'
+ waitForUpdate(() => {
+ expectTextContent(vm, 'yyyyyy')
+ vm.list[0].tester = false
+ }).then(() => {
+ expectTextContent(vm, 'aaaa')
+ vm.list[0].text = 'nn'
+ }).then(() => {
+ expectTextContent(vm, 'annann')
+ }).then(done)
+ })
+
it('should warn inside non-keyed v-for', () => {
const vm = new Vue({
data: {
@@ -162,3 +235,7 @@ describe('Directive v-once', () => {
expect(`v-once can only be used inside v-for that is keyed.`).toHaveBeenWarned()
})
})
+
+function expectTextContent (vm, text) {
+ expect(vm.$el.textContent.replace(/\r?\n|\r|\s/g, '')).toBe(text)
+}