Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Velpro187
uni-app
提交
52c12fce
U
uni-app
项目概览
Velpro187
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
52c12fce
编写于
3月 29, 2022
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix(mp): v-model with modifiers (#3381)
上级
bc78cc6d
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
205 addition
and
10 deletion
+205
-10
packages/uni-mp-compiler/__tests__/vModel.spec.ts
packages/uni-mp-compiler/__tests__/vModel.spec.ts
+60
-0
packages/uni-mp-compiler/src/runtimeHelpers.ts
packages/uni-mp-compiler/src/runtimeHelpers.ts
+3
-1
packages/uni-mp-compiler/src/transforms/vModel.ts
packages/uni-mp-compiler/src/transforms/vModel.ts
+72
-6
packages/uni-mp-vue/dist/vue.runtime.esm.js
packages/uni-mp-vue/dist/vue.runtime.esm.js
+27
-2
packages/uni-mp-vue/src/helpers/index.ts
packages/uni-mp-vue/src/helpers/index.ts
+6
-0
packages/uni-mp-vue/src/helpers/vOn.ts
packages/uni-mp-vue/src/helpers/vOn.ts
+1
-1
packages/uni-mp-vue/src/helpers/withModelModifiers.ts
packages/uni-mp-vue/src/helpers/withModelModifiers.ts
+36
-0
未找到文件。
packages/uni-mp-compiler/__tests__/vModel.spec.ts
浏览文件 @
52c12fce
...
...
@@ -22,6 +22,39 @@ describe('compiler: transform v-model', () => {
}
)
})
test
(
`component v-model with number`
,
()
=>
{
assert
(
`<Comp v-model.number="model" />`
,
`<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _o(_m($event => _ctx.model = $event, { number: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`
,
{
cacheHandlers
:
true
,
}
)
})
test
(
`component v-model with trim`
,
()
=>
{
assert
(
`<Comp v-model.trim="model" />`
,
`<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _o(_m($event => _ctx.model = $event, { trim: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`
,
{
cacheHandlers
:
true
,
}
)
})
test
(
`component v-model with number and trim`
,
()
=>
{
assert
(
`<Comp v-model.trim.number="model" />`
,
`<comp u-i="2a9ec0b0-0" bindupdateModelValue="{{a}}" u-p="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _o(_m($event => _ctx.model = $event, { trim: true, number: true }, true)), b: _p({ modelValue: _ctx.model }) }
}`
)
})
test
(
`input,textarea v-model`
,
()
=>
{
assert
(
`<input v-model="model" />`
,
...
...
@@ -44,6 +77,33 @@ describe('compiler: transform v-model', () => {
`<input bindinput="{{a}}" value="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _o([$event => _ctx.model = $event.detail.value, _ctx.input]), b: _ctx.model }
}`
)
})
test
(
`input v-model with number`
,
()
=>
{
assert
(
`<input v-model.number="model" />`
,
`<input value="{{a}}" bindinput="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _ctx.model, b: _o(_m($event => _ctx.model = $event.detail.value, { number: true })) }
}`
)
})
test
(
`input v-model with number and trim`
,
()
=>
{
assert
(
`<input v-model.trim.number="model" />`
,
`<input value="{{a}}" bindinput="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _ctx.model, b: _o(_m($event => _ctx.model = $event.detail.value, { trim: true, number: true })) }
}`
)
})
test
(
`input v-model.number + v-on`
,
()
=>
{
assert
(
`<input @input="input" v-model.number="model" />`
,
`<input bindinput="{{a}}" value="{{b}}"/>`
,
`(_ctx, _cache) => {
return { a: _o([_m($event => _ctx.model = $event.detail.value, { number: true }), _ctx.input]), b: _ctx.model }
}`
)
})
...
...
packages/uni-mp-compiler/src/runtimeHelpers.ts
浏览文件 @
52c12fce
...
...
@@ -13,6 +13,7 @@ export const WITH_SCOPED_SLOT = Symbol(`withScopedSlot`)
export
const
STRINGIFY_STYLE
=
Symbol
(
`stringifyStyle`
)
export
const
NORMALIZE_CLASS
=
Symbol
(
`normalizeClass`
)
export
const
TO_DISPLAY_STRING
=
Symbol
(
`toDisplayString`
)
export
const
WITH_MODEL_MODIFIERS
=
Symbol
(
`withModelModifiers`
)
registerRuntimeHelpers
({
[
V_ON
]:
'
o
'
,
[
V_FOR
]:
'
f
'
,
...
...
@@ -26,5 +27,6 @@ registerRuntimeHelpers({
[
WITH_SCOPED_SLOT
]:
'
w
'
,
[
STRINGIFY_STYLE
]:
'
s
'
,
[
NORMALIZE_CLASS
]:
'
n
'
,
[
TO_DISPLAY_STRING
]:
`t`
,
[
TO_DISPLAY_STRING
]:
'
t
'
,
[
WITH_MODEL_MODIFIERS
]:
'
m
'
,
})
packages/uni-mp-compiler/src/transforms/vModel.ts
浏览文件 @
52c12fce
...
...
@@ -12,6 +12,11 @@ import {
createCompoundExpression
,
DirectiveTransform
,
TransformContext
as
VueTransformContext
,
isSimpleIdentifier
,
isStaticExp
,
createObjectProperty
,
createSimpleExpression
,
ConstantTypes
,
}
from
'
@vue/compiler-core
'
import
{
DOMErrorCodes
,
createDOMCompilerError
}
from
'
@vue/compiler-dom
'
...
...
@@ -19,8 +24,9 @@ import {
createBindDirectiveNode
,
createOnDirectiveNode
,
ATTR_DATASET_EVENT_OPTS
,
isSimpleExpressionNode
,
}
from
'
@dcloudio/uni-cli-shared
'
import
{
V_ON
}
from
'
../runtimeHelpers
'
import
{
V_ON
,
WITH_MODEL_MODIFIERS
}
from
'
../runtimeHelpers
'
import
{
genExpr
}
from
'
../codegen
'
import
{
TransformContext
}
from
'
../transform
'
import
{
DirectiveTransformResult
}
from
'
./transformElement
'
...
...
@@ -75,6 +81,29 @@ export const transformModel: DirectiveTransform = (
)
}
if
(
dir
.
modifiers
.
length
)
{
const
arg
=
dir
.
arg
const
modifiers
=
dir
.
modifiers
.
map
((
m
)
=>
(
isSimpleIdentifier
(
m
)
?
m
:
JSON
.
stringify
(
m
))
+
`: true`
)
.
join
(
`, `
)
const
modifiersKey
=
arg
?
isStaticExp
(
arg
)
?
`
${
arg
.
content
}
Modifiers`
:
createCompoundExpression
([
arg
,
'
+ "Modifiers"
'
])
:
`modelModifiers`
baseResult
.
props
.
push
(
createObjectProperty
(
modifiersKey
,
createSimpleExpression
(
`{
${
modifiers
}
}`
,
false
,
dir
.
loc
,
ConstantTypes
.
CAN_HOIST
)
)
)
}
return
transformElementVModel
(
baseResult
.
props
,
node
,
...
...
@@ -98,6 +127,7 @@ function transformElementVModel(
context
:
TransformContext
)
{
const
dirs
=
transformVModel
(
props
,
node
,
context
,
{
isComponent
:
false
,
binding
:
'
value
'
,
event
:
'
input
'
,
formatEventCode
(
code
)
{
...
...
@@ -230,6 +260,7 @@ function transformComponentVModel(
)
{
return
{
props
:
transformVModel
(
props
,
node
,
context
,
{
isComponent
:
true
,
formatEventCode
(
code
)
{
return
code
},
...
...
@@ -242,16 +273,18 @@ function transformVModel(
node
:
ElementNode
,
context
:
TransformContext
,
{
isComponent
,
binding
,
event
,
formatEventCode
,
}:
{
isComponent
:
boolean
binding
?:
string
event
?:
string
formatEventCode
:
(
code
:
string
)
=>
string
}
)
{
if
(
props
.
length
!==
2
)
{
if
(
props
.
length
<
2
)
{
return
[]
}
const
{
key
:
modelValueArg
,
value
:
modelValeExpr
}
=
props
[
0
]
...
...
@@ -270,15 +303,22 @@ function transformVModel(
binding
||
modelValueArg
.
content
,
genExpr
(
modelValeExpr
as
ExpressionNode
)
)
const
modifiers
=
parseVModelModifiers
(
props
[
2
])
// onUpdateExpr 通常是 ExpressionNode 或者被 cache 的 ExpressionNode
const
vOnValue
=
(
onUpdateExpr
.
type
===
NodeTypes
.
JS_CACHE_EXPRESSION
?
onUpdateExpr
.
value
:
onUpdateExpr
)
as
ExpressionNode
const
vOnUpdate
=
createOnDirectiveNode
(
event
||
camelize
(
onUpdateArg
.
content
.
replace
(
'
onUpdate:
'
,
'
update-
'
)),
formatEventCode
(
genExpr
(
wrapperVOn
(
// onUpdateExpr 通常是 ExpressionNode 或者被 cache 的 ExpressionNode
(
onUpdateExpr
.
type
===
NodeTypes
.
JS_CACHE_EXPRESSION
?
onUpdateExpr
.
value
:
onUpdateExpr
)
as
ExpressionNode
,
modifiers
?
wrapperVModelModifiers
(
vOnValue
,
modifiers
,
context
,
isComponent
)
:
vOnValue
,
node
,
context
)
...
...
@@ -287,3 +327,29 @@ function transformVModel(
)
return
[
vBindModelValue
,
vOnUpdate
]
}
function
parseVModelModifiers
(
property
?:
Property
)
{
if
(
property
&&
isSimpleExpressionNode
(
property
.
key
)
&&
property
.
key
.
content
.
endsWith
(
'
Modifiers
'
)
&&
isSimpleExpressionNode
(
property
.
value
)
)
{
return
property
.
value
.
content
}
}
function
wrapperVModelModifiers
(
exp
:
ExpressionNode
,
modifiers
:
string
,
context
:
TransformContext
,
isComponent
=
false
)
{
return
createCompoundExpression
([
`
${
context
.
helperString
(
WITH_MODEL_MODIFIERS
)}
(`
,
exp
,
'
,
'
,
modifiers
,
`
${
isComponent
?
`, true`
:
``
}
`
,
`)`
,
])
}
packages/uni-mp-vue/dist/vue.runtime.esm.js
浏览文件 @
52c12fce
...
...
@@ -5563,6 +5563,30 @@ function setRef(ref, id, opts = {}) {
$templateRefs
.
push
({
i
:
id
,
r
:
ref
,
k
:
opts
.
k
,
f
:
opts
.
f
});
}
function
withModelModifiers
(
fn
,
{
number
,
trim
},
isComponent
=
false
)
{
if
(
isComponent
)
{
return
(...
args
)
=>
{
if
(
trim
)
{
args
=
args
.
map
((
a
)
=>
a
.
trim
());
}
else
if
(
number
)
{
args
=
args
.
map
(
toNumber
);
}
return
fn
(...
args
);
};
}
return
(
event
)
=>
{
const
value
=
event
.
detail
.
value
;
if
(
trim
)
{
event
.
detail
.
value
=
value
.
trim
();
}
else
if
(
number
)
{
event
.
detail
.
value
=
toNumber
(
value
);
}
return
fn
(
event
);
};
}
function
setupDevtoolsPlugin
()
{
// noop
}
...
...
@@ -5579,7 +5603,8 @@ const h = (str) => hyphenate(str);
const
n
=
(
value
)
=>
normalizeClass
(
value
);
const
t
=
(
val
)
=>
toDisplayString
(
val
);
const
p
=
(
props
)
=>
renderProps
(
props
);
const
sr
=
(
ref
,
id
,
opts
)
=>
setRef
(
ref
,
id
,
opts
);
const
sr
=
(
ref
,
id
,
opts
)
=>
setRef
(
ref
,
id
,
opts
);
const
m
=
(
fn
,
modifiers
,
isComponent
=
false
)
=>
withModelModifiers
(
fn
,
modifiers
,
isComponent
);
function
createApp
(
rootComponent
,
rootProps
=
null
)
{
rootComponent
&&
(
rootComponent
.
mpType
=
'
app
'
);
...
...
@@ -5587,4 +5612,4 @@ function createApp(rootComponent, rootProps = null) {
}
const
createSSRApp
=
createApp
;
export
{
EffectScope
,
Fragment
,
ReactiveEffect
,
Text
,
c
,
callWithAsyncErrorHandling
,
callWithErrorHandling
,
computed$1
as
computed
,
createApp
,
createSSRApp
,
createVNode$1
as
createVNode
,
createVueApp
,
customRef
,
d
,
defineAsyncComponent
,
defineComponent
,
defineEmits
,
defineExpose
,
defineProps
,
diff
,
e
,
effect
,
effectScope
,
f
,
findComponentPropsData
,
getCurrentInstance
,
getCurrentScope
,
getExposeProxy
,
guardReactiveProps
,
h
,
inject
,
injectHook
,
invalidateJob
,
isInSSRComponentSetup
,
isProxy
,
isReactive
,
isReadonly
,
isRef
,
logError
,
markRaw
,
mergeDefaults
,
mergeProps
,
n
,
nextTick
,
o
,
onActivated
,
onBeforeMount
,
onBeforeUnmount
,
onBeforeUpdate
,
onDeactivated
,
onErrorCaptured
,
onMounted
,
onRenderTracked
,
onRenderTriggered
,
onScopeDispose
,
onServerPrefetch
,
onUnmounted
,
onUpdated
,
p
,
patch
,
provide
,
proxyRefs
,
pruneComponentPropsCache
,
queuePostFlushCb
,
r
,
reactive
,
readonly
,
ref
,
resolveComponent
,
resolveDirective
,
resolveFilter
,
s
,
setCurrentRenderingInstance
,
setTemplateRef
,
setupDevtoolsPlugin
,
shallowReactive
,
shallowReadonly
,
shallowRef
,
sr
,
stop
,
t
,
toHandlers
,
toRaw
,
toRef
,
toRefs
,
triggerRef
,
unref
,
updateProps
,
useAttrs
,
useCssModule
,
useCssVars
,
useSSRContext
,
useSlots
,
version
,
w
,
warn$1
as
warn
,
watch
,
watchEffect
,
watchPostEffect
,
watchSyncEffect
,
withAsyncContext
,
withCtx
,
withDefaults
,
withDirectives
,
withModifiers
,
withScopeId
};
export
{
EffectScope
,
Fragment
,
ReactiveEffect
,
Text
,
c
,
callWithAsyncErrorHandling
,
callWithErrorHandling
,
computed$1
as
computed
,
createApp
,
createSSRApp
,
createVNode$1
as
createVNode
,
createVueApp
,
customRef
,
d
,
defineAsyncComponent
,
defineComponent
,
defineEmits
,
defineExpose
,
defineProps
,
diff
,
e
,
effect
,
effectScope
,
f
,
findComponentPropsData
,
getCurrentInstance
,
getCurrentScope
,
getExposeProxy
,
guardReactiveProps
,
h
,
inject
,
injectHook
,
invalidateJob
,
isInSSRComponentSetup
,
isProxy
,
isReactive
,
isReadonly
,
isRef
,
logError
,
m
,
m
arkRaw
,
mergeDefaults
,
mergeProps
,
n
,
nextTick
,
o
,
onActivated
,
onBeforeMount
,
onBeforeUnmount
,
onBeforeUpdate
,
onDeactivated
,
onErrorCaptured
,
onMounted
,
onRenderTracked
,
onRenderTriggered
,
onScopeDispose
,
onServerPrefetch
,
onUnmounted
,
onUpdated
,
p
,
patch
,
provide
,
proxyRefs
,
pruneComponentPropsCache
,
queuePostFlushCb
,
r
,
reactive
,
readonly
,
ref
,
resolveComponent
,
resolveDirective
,
resolveFilter
,
s
,
setCurrentRenderingInstance
,
setTemplateRef
,
setupDevtoolsPlugin
,
shallowReactive
,
shallowReadonly
,
shallowRef
,
sr
,
stop
,
t
,
toHandlers
,
toRaw
,
toRef
,
toRefs
,
triggerRef
,
unref
,
updateProps
,
useAttrs
,
useCssModule
,
useCssVars
,
useSSRContext
,
useSlots
,
version
,
w
,
warn$1
as
warn
,
watch
,
watchEffect
,
watchPostEffect
,
watchSyncEffect
,
withAsyncContext
,
withCtx
,
withDefaults
,
withDirectives
,
withModifiers
,
withScopeId
};
packages/uni-mp-vue/src/helpers/index.ts
浏览文件 @
52c12fce
...
...
@@ -13,6 +13,7 @@ import { stringifyStyle } from './style'
import
{
dynamicSlot
}
from
'
./dynamicSlot
'
import
{
setRef
}
from
'
./ref
'
import
{
renderProps
}
from
'
./renderProps
'
import
{
withModelModifiers
}
from
'
./withModelModifiers
'
export
{
setupDevtoolsPlugin
}
from
'
./devtools
'
...
...
@@ -38,3 +39,8 @@ export const n: typeof normalizeClass = (value) => normalizeClass(value)
export
const
t
:
typeof
toDisplayString
=
(
val
)
=>
toDisplayString
(
val
)
export
const
p
:
typeof
renderProps
=
(
props
)
=>
renderProps
(
props
)
export
const
sr
:
typeof
setRef
=
(
ref
,
id
,
opts
)
=>
setRef
(
ref
,
id
,
opts
)
export
const
m
:
typeof
withModelModifiers
=
(
fn
,
modifiers
,
isComponent
=
false
)
=>
withModelModifiers
(
fn
,
modifiers
,
isComponent
)
packages/uni-mp-vue/src/helpers/vOn.ts
浏览文件 @
52c12fce
...
...
@@ -56,7 +56,7 @@ export function vOn(value: EventValue | undefined, key?: number | string) {
return
name
}
interface
MPEvent
extends
WechatMiniprogram
.
BaseEvent
{
export
interface
MPEvent
extends
WechatMiniprogram
.
BaseEvent
{
detail
:
Record
<
string
,
any
>
&
{
__args__
?:
unknown
[]
}
...
...
packages/uni-mp-vue/src/helpers/withModelModifiers.ts
0 → 100644
浏览文件 @
52c12fce
import
{
toNumber
}
from
'
@vue/shared
'
import
type
{
MPEvent
}
from
'
./vOn
'
interface
VModelFn
{
(...
args
:
unknown
[]):
unknown
modifiers
?:
VModelModifiers
}
interface
VModelModifiers
{
number
?:
boolean
trim
?:
boolean
}
export
function
withModelModifiers
(
fn
:
VModelFn
,
{
number
,
trim
}:
VModelModifiers
,
isComponent
=
false
)
{
if
(
isComponent
)
{
return
(...
args
:
any
[])
=>
{
if
(
trim
)
{
args
=
args
.
map
((
a
)
=>
a
.
trim
())
}
else
if
(
number
)
{
args
=
args
.
map
(
toNumber
)
}
return
fn
(...
args
)
}
}
return
(
event
:
MPEvent
)
=>
{
const
value
:
string
=
event
.
detail
.
value
if
(
trim
)
{
event
.
detail
.
value
=
value
.
trim
()
}
else
if
(
number
)
{
event
.
detail
.
value
=
toNumber
(
value
)
}
return
fn
(
event
)
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录