HBuilderX 3.8.12+版本更新:自动生成 generic:scoped-slots-itemView,解决编译问题

2024-07-23
来源:网络整理

最新情况(截至2024-03)

经确认,3.8.12+以后,你不再需要按照本文内容手动处理“--=”my-“操作了,可以放心使用了,这个版本编译出来的wxml文件已经自动生成了上述内容。

本文所述方法经验证:

<template> <view> 。。其他内容。。。。 <CommonList> <MyComponent slot="itemView" slot-scope="{item}" :item="item">MyComponent> CommonList> view> template> ...... script>

或者

<template> <view> <CommonList> <view slot="itemView" slot-scope="{item}"> 只显示ID:{{item.id}} view> CommonList> view> template> ...... script>

它们都可以正确地编译成这种形式:--。

PS: 为什么要用 Vue2 那种老套的写法呢?因为我发现用 v-slot 或者 Vue3 都会有各种奇怪的问题,这里就不细说了,大家自己考虑怎么用吧。

背景

众所周知,大部分开发微信小程序的同学肯定会遇到这样的问题:用Vue开开心心的写一个v-for,然后在v-for里打一个插槽,结果用的时候,H5没问题,但是微信小程序只渲染了第一个。

例如,我有一个名为的组件

这个组件内部有一个v-for,v-for内部有一个slot,通过循环的方式来处理渲染。

<template> 。。其他内容。。。。 <view class="lists"> <view class="data-item" v-for="(item, index) in products" :key="index"> <text>标题text> <slot name="itemView" :item="item"> <view> <text>{{item}}text> view> slot> view> view> 。。其他内容。。。。 template>

现在我有一个页面需要使用此组件

<template> <view> 。。其他内容。。。。 <CommonList> <view slot="itemView" slot-scope="{item}"> 只显示ID:{{item.id}} view> CommonList> view> template > import CommonList from './commonlist' export default { components: { CommonList } } script>

然后不出意外的话,程序在H5里是正常的,但是在小程序里,不管上面有多少个,都只有第一个会被渲染出来(因为不是槽位,所以会正常渲染)

如果 v-for 中不能使用 slot,那么开发就会很痛苦!这个大家应该都知道。

先说结论吧(有兴趣可以看下面的过程)

=================

微信小程序中v-for+slot需要使用小程序虚拟组件进行slot渲染

=================

例如,在 中,v-for 作用于原生组件视图

提供v-for+slot组件,正常写就行,比如在使用组件的页面(或者组件)中,如果内容不变,就使用微信虚拟节点完成渲染,那么我们需要先做一个虚拟节点组件,假设调用(注意这个要有接受slot的参数),然后在H5中正常使用,如果是微信小程序,就使用:xxxx方法,搭配专门的slot即可完成渲染

:这是使用组件修改后的页面

<template> <view> 。。其他内容。。。。 <CommonList generic:scoped-slots-itemView="my-component"> <view slot="itemView" style="display: none"> <MyComponent slot="itemView" slot-scope="{item}" :item="item">MyComponent> CommonList> view> template > import CommonList from './commonlist' import MyComponent'./my-component' export default { components: { CommonList, MyComponent} } script>

:这是

<template> <view> 。。。。其他内容。。。。 <view>只显示ID:{{item.id}}view> 。。。。其他内容。。。。 view> template > 。。。。其他内容。。。。 export default { name: 'FeeListItem', props: ['item'], //特别注意这个,这是接受slot参数的属性 } 。。。。其他内容。。。。 script>

重点是

1. 在组件上使用 `:--= "my-"

2.使用

在上述内容中:

:表示使用虚拟节点,这样写就可以了

-slos-是编译后的具体内容,也就是--+v-for中的slot的名字

my- 是编译后的虚拟组件,对应json文件中的组件声明,注意写法(做vue的就明白)

主要目的是让wx:if="{{$slot.}}"在编译出来的wxml中生效(任何控件都可以)

===========================折腾的过程===========================

分析

如果你在网上搜索“小程序v-for槽位”,你会发现,官方没有回应。

这么大的院子难道处理不了这种事??

怀着这个想法,我决定看看哪里出了问题。

小软件开发工具_开发支持小程序的app_开发应用小程序

看看微信小程序本身

通过查阅官方资料,我们发现:

在小程序中,槽点的灵活性远不如h5,例如

可以看到,组件中要使用多个插槽,必须进行配置。小程序中,wx:for 本身不支持插槽的循环渲染。可以搜索到很多类似的问题,比如插槽能和 wx:for 一起使用吗?

我也问过自己类似的问题:规模这么大,微信难道不知道不能循环分发代码带来的效率和耦合问题吗?

编译的小程序代码

从我截取的片段来看

<view class="data-v-282ea8d0"> <block wx:if="{{$slots.itemView}}"> <slot name="itemView">slot> <scoped-slots-itemView item="{{item.$orig}}" class="scoped-ref">scoped-slots-itemView> block> <block wx:else> <view class="data-v-282ea8d0"><text class="data-v-282ea8d0">{{item.$orig}}text>view> block> view>

这里我们可以看到slot确实是编译通过了,但是由于上面的情况,微信本身不支持在wx:for中渲染N个slot,所以我们的组件在使用的时候就会出现问题

但我们发现它还有一个

<scoped-slots-itemView item="{{item.$orig}}" class="scoped-ref">scoped-slots-itemView>

这是什么?

微信小程序虚拟节点

从官方文档这里:抽象节点可以知道,微信其实对组件的控制相当死板,每个组件的插槽都是只为组件本身量身定制的(可以说给设备打的只能是物理的洞,不允许打逻辑的洞),所以创造了一个虚拟组件。

虚拟组件本身就是一个组件,不会受到 v-for + slot 的影响。所以如果在 v-for 中将数据传递给虚拟组件,然后在虚拟组件中使用 slot,就能完成之前的工作。

微信小程序中使用虚拟节点+自定义组件

查看了抽象节点的主要逻辑后,我们可以得出以下结论:

1.如果使用微信原生开发,必须在组件中声明虚拟节点,如上图

。。。 <block wx:for="products" > <itemView>。。。。itemView> block> 。。。

对应的.json需要声明虚拟节点

{ 。。。 "componentGenerics": { "itemView": true } }

2. 使用组件时需要注意

。。。 <CommnList generic:itemView="你的组件名"> 。。。

现在我看到刚才那个 - 它不可能是一个虚拟节点吗?

通过查看编译后的 .json,你可以看到

"component": true, "componentGenerics": { "scoped-slots-itemView": true }

看起来在编译期间,v-for 中的插槽变成了虚拟节点。

===========================================

正确渲染虚拟节点

有了以上官方技术支持,我们可以考虑做如下处理:

在Vue代码中,直接使用组件的地方写:=

那么页面代码就变成:

。。其他内容。。。。 <CommonList generic:scoped-slots-itemView="my-component"> CommonList > 。。其他内容。。。。 <script> import CommonList from './commonlist' import MyComponent'./my-component' export default { components: { CommonList, MyComponent} } script>

这里的my-是虚拟组件,--是根据编译后的wxml中的虚拟节点名获取的,其实观察一下就可以发现,它的规则是:--+v-for中slot的名字

写完之后编译并查看编译后的页面,会发现在对应的wxml中,-list组件确实有属性:--="my-",并且在json中也可以看到对应的my-声明

OK,直接编译运行到小程序模拟器上,结果发现my-没有被加载。

有了上述结论,为什么我们在小程序中看不到正确的结果呢??

显然所有条件都满足:

1. 在编译后的.json文件中声明虚拟节点

分享