diff --git a/packages/weex-vue-framework/factory.js b/packages/weex-vue-framework/factory.js index 8bcfb675ba9..fb30d12bbbd 100644 --- a/packages/weex-vue-framework/factory.js +++ b/packages/weex-vue-framework/factory.js @@ -5797,7 +5797,7 @@ function createPatchFunction (backend) { } } - function removeVnodes (parentElm, vnodes, startIdx, endIdx) { + function removeVnodes (vnodes, startIdx, endIdx) { for (; startIdx <= endIdx; ++startIdx) { var ch = vnodes[startIdx]; if (isDef(ch)) { @@ -5908,7 +5908,7 @@ function createPatchFunction (backend) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm; addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue); } else if (newStartIdx > newEndIdx) { - removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx); + removeVnodes(oldCh, oldStartIdx, oldEndIdx); } } @@ -5985,7 +5985,7 @@ function createPatchFunction (backend) { if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); } addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { - removeVnodes(elm, oldCh, 0, oldCh.length - 1); + removeVnodes(oldCh, 0, oldCh.length - 1); } else if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); } @@ -6216,7 +6216,7 @@ function createPatchFunction (backend) { // destroy old node if (isDef(parentElm$1)) { - removeVnodes(parentElm$1, [oldVnode], 0, 0); + removeVnodes([oldVnode], 0, 0); } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode); } diff --git a/src/compiler/error-detector.js b/src/compiler/error-detector.js index 22c3b75d3aa..9893aa4a47a 100644 --- a/src/compiler/error-detector.js +++ b/src/compiler/error-detector.js @@ -36,6 +36,8 @@ function checkNode (node: ASTNode, warn: Function) { const range = node.rawAttrsMap[name] if (name === 'v-for') { checkFor(node, `v-for="${value}"`, warn, range) + } else if (name === 'v-slot' || name[0] === '#') { + checkFunctionParameterExpression(value, `${name}="${value}"`, warn, range) } else if (onRE.test(name)) { checkEvent(value, `${name}="${value}"`, warn, range) } else { @@ -111,3 +113,16 @@ function checkExpression (exp: string, text: string, warn: Function, range?: Ran } } } + +function checkFunctionParameterExpression (exp: string, text: string, warn: Function, range?: Range) { + try { + new Function(exp, '') + } catch (e) { + warn( + `invalid function parameter expression: ${e.message} in\n\n` + + ` ${exp}\n\n` + + ` Raw expression: ${text.trim()}\n`, + range + ) + } +} diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index fb258752179..cdeb257eda4 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -23,8 +23,8 @@ import { export const onRE = /^@|^v-on:/ export const dirRE = process.env.VBIND_PROP_SHORTHAND - ? /^v-|^@|^:|^\./ - : /^v-|^@|^:/ + ? /^v-|^@|^:|^\.|^#/ + : /^v-|^@|^:|^#/ export const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/ export const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/ const stripParensRE = /^\(|\)$/g diff --git a/src/core/util/env.js b/src/core/util/env.js index eff1d21dc75..820bacdb405 100644 --- a/src/core/util/env.js +++ b/src/core/util/env.js @@ -87,11 +87,10 @@ if (typeof Set !== 'undefined' && isNative(Set)) { } } -interface SimpleSet { +export interface SimpleSet { has(key: string | number): boolean; add(key: string | number): mixed; clear(): void; } export { _Set } -export type { SimpleSet } diff --git a/src/core/vdom/create-element.js b/src/core/vdom/create-element.js index 46027084b51..ba36e15b12d 100644 --- a/src/core/vdom/create-element.js +++ b/src/core/vdom/create-element.js @@ -98,6 +98,12 @@ export function _createElement ( ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag) if (config.isReservedTag(tag)) { // platform built-in elements + if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) { + warn( + `The .native modifier for v-on is only valid on components but it was used on <${tag}>.`, + context + ) + } vnode = new VNode( config.parsePlatformTagName(tag), data, children, undefined, undefined, context diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 9746bb794f8..95a4db47298 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -16,6 +16,7 @@ import { SSR_ATTR } from 'shared/constants' import { registerRef } from './modules/ref' import { traverse } from '../observer/traverse' import { activeInstance } from '../instance/lifecycle' +import { inBrowser } from '../util/index'; import { isTextInputType } from 'web/util/element' import { @@ -32,6 +33,8 @@ export const emptyNode = new VNode('', {}, []) const hooks = ['create', 'activate', 'update', 'remove', 'destroy'] +const customElements = inBrowser ? window.customElements : undefined + function sameVnode (a, b) { return ( a.key === b.key && ( @@ -106,6 +109,7 @@ export function createPatchFunction (backend) { function isUnknownElement (vnode, inVPre) { return ( + !(customElements && customElements.get(vnode.tag)) && !inVPre && !vnode.ns && !( @@ -358,7 +362,7 @@ export function createPatchFunction (backend) { } } - function removeVnodes (parentElm, vnodes, startIdx, endIdx) { + function removeVnodes (vnodes, startIdx, endIdx) { for (; startIdx <= endIdx; ++startIdx) { const ch = vnodes[startIdx] if (isDef(ch)) { @@ -469,7 +473,7 @@ export function createPatchFunction (backend) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue) } else if (newStartIdx > newEndIdx) { - removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx) + removeVnodes(oldCh, oldStartIdx, oldEndIdx) } } @@ -561,7 +565,7 @@ export function createPatchFunction (backend) { if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '') addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue) } else if (isDef(oldCh)) { - removeVnodes(elm, oldCh, 0, oldCh.length - 1) + removeVnodes(oldCh, 0, oldCh.length - 1) } else if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, '') } @@ -790,7 +794,7 @@ export function createPatchFunction (backend) { // destroy old node if (isDef(parentElm)) { - removeVnodes(parentElm, [oldVnode], 0, 0) + removeVnodes([oldVnode], 0, 0) } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode) } diff --git a/test/e2e/nightwatch.config.js b/test/e2e/nightwatch.config.js index 2004f92b45b..8ec592494fe 100644 --- a/test/e2e/nightwatch.config.js +++ b/test/e2e/nightwatch.config.js @@ -50,7 +50,8 @@ module.exports = { 'desiredCapabilities': { 'browserName': 'phantomjs', 'javascriptEnabled': true, - 'acceptSslCerts': true + 'acceptSslCerts': true, + 'phantomjs.binary.path': require('phantomjs-prebuilt').path } } } diff --git a/test/unit/features/component/component-scoped-slot.spec.js b/test/unit/features/component/component-scoped-slot.spec.js index f8a0f11b7fa..28369814f48 100644 --- a/test/unit/features/component/component-scoped-slot.spec.js +++ b/test/unit/features/component/component-scoped-slot.spec.js @@ -759,6 +759,22 @@ describe('Component scoped slot', () => { }).$mount() expect(`Unexpected mixed usage of different slot syntaxes`).toHaveBeenWarned() }) + + it('should warn invalid parameter expression', () => { + new Vue({ + template: ``, + components: { Foo } + }).$mount(); + expect('invalid function parameter expression').toHaveBeenWarned() + }) + + it('should allow destructuring props with default value', () => { + new Vue({ + template: ``, + components: { Foo } + }).$mount(); + expect('invalid function parameter expression').not.toHaveBeenWarned() + }) } // run tests for both full syntax and shorthand diff --git a/test/unit/features/directives/on.spec.js b/test/unit/features/directives/on.spec.js index a97ddaa8947..b7801a82f22 100644 --- a/test/unit/features/directives/on.spec.js +++ b/test/unit/features/directives/on.spec.js @@ -460,6 +460,20 @@ describe('Directive v-on', () => { expect(spy).toHaveBeenCalled() }) + it('should throw a warning if native modifier is used on native HTML element', () => { + vm = new Vue({ + el, + template: ` + + `, + methods: { foo: spy }, + }) + + triggerEvent(vm.$el, 'click') + expect(`The .native modifier for v-on is only valid on components but it was used on