fix(v-model): allow v-model usage on declared custom elements

fix #1699
This commit is contained in:
Evan You 2020-07-27 17:09:21 -04:00
parent 2a633c84ff
commit 71c3c6e2a0
5 changed files with 43 additions and 3 deletions

View File

@ -28,7 +28,7 @@ export interface ParserOptions {
/** /**
* Separate option for end users to extend the native elements list * Separate option for end users to extend the native elements list
*/ */
isCustomElement?: (tag: string) => boolean isCustomElement?: (tag: string) => boolean | void
/** /**
* Get tag namespace * Get tag namespace
*/ */
@ -83,6 +83,10 @@ export interface TransformOptions {
* for them. * for them.
*/ */
isBuiltInComponent?: (tag: string) => symbol | void isBuiltInComponent?: (tag: string) => symbol | void
/**
* Used by some transforms that expects only native elements
*/
isCustomElement?: (tag: string) => boolean | void
/** /**
* Transform expressions like {{ foo }} to `_ctx.foo`. * Transform expressions like {{ foo }} to `_ctx.foo`.
* If this option is false, the generated code will be wrapped in a * If this option is false, the generated code will be wrapped in a

View File

@ -117,6 +117,7 @@ export function createTransformContext(
directiveTransforms = {}, directiveTransforms = {},
transformHoist = null, transformHoist = null,
isBuiltInComponent = NOOP, isBuiltInComponent = NOOP,
isCustomElement = NOOP,
expressionPlugins = [], expressionPlugins = [],
scopeId = null, scopeId = null,
ssr = false, ssr = false,
@ -134,6 +135,7 @@ export function createTransformContext(
directiveTransforms, directiveTransforms,
transformHoist, transformHoist,
isBuiltInComponent, isBuiltInComponent,
isCustomElement,
expressionPlugins, expressionPlugins,
scopeId, scopeId,
ssr, ssr,

View File

@ -1,5 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`compiler: transform v-model errors should allow custom element 1`] = `
"const _Vue = Vue
return function render(_ctx, _cache) {
with (_ctx) {
const { vModelText: _vModelText, createVNode: _createVNode, withDirectives: _withDirectives, openBlock: _openBlock, createBlock: _createBlock } = _Vue
return _withDirectives((_openBlock(), _createBlock(\\"my-input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelText, model]
])
}
}"
`;
exports[`compiler: transform v-model input w/ dynamic v-bind 1`] = ` exports[`compiler: transform v-model input w/ dynamic v-bind 1`] = `
"const _Vue = Vue "const _Vue = Vue

View File

@ -115,6 +115,17 @@ describe('compiler: transform v-model', () => {
) )
}) })
test('should allow usage on custom element', () => {
const onError = jest.fn()
const root = transformWithModel('<my-input v-model="model" />', {
onError,
isCustomElement: tag => tag.startsWith('my-')
})
expect(root.helpers).toContain(V_MODEL_TEXT)
expect(onError).not.toHaveBeenCalled()
expect(generate(root).code).toMatchSnapshot()
})
test('should raise error if used file input element', () => { test('should raise error if used file input element', () => {
const onError = jest.fn() const onError = jest.fn()
transformWithModel(`<input type="file" v-model="test"/>`, { transformWithModel(`<input type="file" v-model="test"/>`, {

View File

@ -44,7 +44,12 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
} }
const { tag } = node const { tag } = node
if (tag === 'input' || tag === 'textarea' || tag === 'select') { if (
tag === 'input' ||
tag === 'textarea' ||
tag === 'select' ||
context.isCustomElement(tag)
) {
let directiveToUse = V_MODEL_TEXT let directiveToUse = V_MODEL_TEXT
let isInvalidType = false let isInvalidType = false
if (tag === 'input') { if (tag === 'input') {
@ -86,7 +91,9 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
} }
} else if (tag === 'select') { } else if (tag === 'select') {
directiveToUse = V_MODEL_SELECT directiveToUse = V_MODEL_SELECT
} else if (tag === 'textarea') { }
{
// textarea or custom elements
__DEV__ && checkDuplicatedValue() __DEV__ && checkDuplicatedValue()
} }
// inject runtime directive // inject runtime directive