Closed jsLyLeeHi closed 3 years ago
@jsLyLeeHi 提供一下详细代码
提供一点额外的信息。
这个问题 h5 不受影响,只有小程序存在这个问题。跟 taro 版本更新没直接关系,taro 3.1.4
存在同样的问题。
使用 @vue/compiler-sfc@3.0.9
编译,slot 表现正常。
使用 @vue/compiler-sfc@^3.0.10
编译,slot
节点会被编译成静态节点。
例如:
<view>
<slot name="header">default content</slot>
</view>
使用 @vue/compiler-sfc@3.0.9
编译的结果:
var _hoisted_1 = /*#__PURE__*/Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createVNode */ "i"])("view", null, "slot test", -1
/* HOISTED */
);
function render(_ctx, _cache, $props, $setup, $data, $options) {
return Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* openBlock */ "r"])(), Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createBlock */ "e"])("view", null, [_hoisted_1, Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* renderSlot */ "s"])(_ctx.$slots, "header", {}, function () {
return ["default content"];
})]);
}
使用 @vue/compiler-sfc@^3.0.10
编译的结果:
var _hoisted_1 = /*#__PURE__*/Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createVNode */ "i"])("view", null, "slot test", -1
/* HOISTED */
);
var _hoisted_2 = /*#__PURE__*/Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createVNode */ "i"])("slot", {
name: "header"
}, "default content", -1
/* HOISTED */
);
function render(_ctx, _cache, $props, $setup, $data, $options) {
return Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* openBlock */ "r"])(), Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createBlock */ "e"])("view", null, [_hoisted_1, _hoisted_2]);
}
使用 vue 3.0 render function 不受影响,例如,下面的写法 slot 表现正常:
h('view', null, {default: () => [
h('view', null, { default: () => 'another slot check'}),
slots.default?.() || 'default content'
]})
将 @vue/compiler-sfc
固定在 3.0.9
, Taro 升级到最新版本是可以正常运行的。
问题在于 Vue 创建了 slot
节点去实现此功能:
Object(vue__WEBPACK_IMPORTED_MODULE_0__[/* createVNode */ "i"])("slot", {
name: "header"
}, "default content", -1
/* HOISTED */
);
而小程序的 slot 和 H5 的表现不一致,比较难搞
@Chen-jj
这个问题是 vue-loader
的 compilerOptions.nodeTransforms
设置导致的。
经 @vue/compiler-sfc
编译后的 node 是正常的:
{
type: 1,
ns: 0,
tag: 'slot',
tagType: 2,
props: [],
isSelfClosing: false,
children: [ { type: 2, content: 'default content', loc: [Object] } ],
loc: {
start: { column: 5, line: 3, offset: 16 },
end: { column: 33, line: 3, offset: 44 },
source: '<slot>default content</slot>'
},
codegenNode: {
type: 14,
loc: {
start: [Object],
end: [Object],
source: '<slot>default content</slot>'
},
callee: Symbol(renderSlot),
arguments: [ '_ctx.$slots', '"default"', '{}', [Object] ]
}
}
但在 vue-loader 的 compilerOptions.nodeTransforms
中,slot 节点的 codegenNode
传丢了。
// taro-mini-runner/src/webpack/vue3.ts line 49 -59
compilerOptions: {
// https://github.com/vuejs/vue-next/blob/master/packages/compiler-core/src/options.ts
nodeTransforms: [(node: RootNode | TemplateChildNode) => {
if (node.type === 1 /* ELEMENT */) {
node = node as ElementNode
const nodeName = node.tag
if (capitalize(toCamelCase(nodeName)) in internalComponents) {
node.tagType = 0 // Root Cause ???
componentConfig.includes.add(nodeName)
}
//...
}
如果不把带有 codegenNode
的节点交给 nodeTransforms
处理,slot 就能正常使用了,但不知道是否会对其他情况产生副作用或造成新问题?
if (node.type === 1 /* ELEMENT */ && !node.codegenNode) {
// ...
}
目前,应该是最近@compiler-sfc升级到3.0.11出现的类似问题,暂时最简单的解决办法是把@compiler-sfc版本固定到3.0.9即可!!
感谢大佬 @b2nil 贡献,3.2.1 修复~
相关平台
微信小程序
小程序基础库: 2.16.0 使用框架: Vue 3
复现代码
https://github.com/jsLyLeeHi/taro-slot-issue-.git
复现步骤
使用 taro3.1.5 新建一个 vue3.0 的项目然后使用插槽slot
期望结果
插槽slot能正常使用
实际结果
插槽slot的内容无法正确显示
环境信息