文章目录
什么是Mpx?
Mpx是一款致力于提高小程序开发体验和开发效率的增强型小程序框架。
Mpx的核心设计理念在于增强,这意味着Mpx是对小程序原生开发标准的增强和扩充,同时也兼容了原生开发标准。
Mpx 提供了单文件开发(SFC)、数据响应、增强的模板语法、极致性能、状态管理、编译构建、跨平台能力、完善的周边能力等能力。
对比其他小程序框架
- 目前业内的小程序主要分为两类,一类是以uni-app,taro2为代表的静态编译型框架,这类框架以静态编译为主要手段,将React和Vue开发的业务源码转换到小程序环境中进行适配运行。这类框架的主要优点在于web项目迁移方便,跨端能力较强。但是由于React/Vue等web框架的DSL与小程序本身存在较大差距,无法完善支持原web框架的全部能力,开发的时候容易踩坑。
- 另一类是以kbone、taro3为代表的运行时框架,这类框架利用小程序本身提供的动态渲染能力,在小程序中模拟出web的运行时环境,让React/Vue等框架直接在上层运行。这类框架的优点在于web项目迁移方便,且在web框架语法能力的支持上比静态编译型的框架要强很多,开发时遇到的坑也会少很多。但是由于模拟的web运行时环境带来了巨大的性能开销,这类框架并不适合用于大型复杂的小程序开发。
- 不同于上面两类框架,Mpx以小程序本身的DSL为基础,通过编译和运行时手段结合对其进行了一系列拓展增强,没有复杂庞大的转译和环境抹平,在提升用户开发体验和效率的同时,既能保障开发的稳定和可预期性,又能保障接近原生的良好性能,非常适合开发大型复杂的小程序应用。
快速开始
1、安装脚手架
npm i -g @mpxjs/cli
2、创建项目安装依赖
mpx init mpx-project(项目名) //注意命令是mpx
也可以使用npx,不在全局安装脚手架的情况下创建项目
npx @mpxjs/cli init mpx-project
执行命令后会弹出一系列问题进行项目初始配置,比如项目名、项目描述、项目作者、以及项目需要的一些依赖包,根据我们自身的需求进行选择。
项目目录进行依赖安装
npm install
3、编译构建
开发模式下我们执行watch命令,将项目源码构建输出到dist/${平台目录}下,并且监听源码的改动进行重新编译。
npm run watch
4、预览调试
使用微信开发者工具打开dist下对应平台的目录,对小程序进行预览、调试。
我们打开微信小程序就可以看到这样的样式
快速建成项目成功,接下来我们继续了解mpx的其他操作。
单文件开发
小程序规范中每个页面和组件都是由四个文件描述组成的,wxml/js/wxss/json,分别描述了 wxml—组件/页面的视图模板
,js—执行逻辑
,wxss—样式
和json—配置
。
由于这四个部分彼此之间存在相关性,比如模板中的组件需要在json中注册,数据需要在js中定义,这种离散的文件结构在实际开发的时候体验并不理想;受Vue单文件开发的启发,Mpx也提供了类似的单文件开发模式,拓展名为.mpx。
.mpx中的四个区块分别对应了原生规范中的四个文件,Mpx在执行编译构建时会通过内置的mpx-loader收集依赖,并将.mpx的文件转换输出为原生规范中的四个文件。
例子:
<!--对应wxml文件-->
<template>
<list></list>
</template>
<!--对应js文件-->
<script>
import { createPage } from '@mpxjs/core'
createPage({
onLoad () {
},
onReady () {
}
})
</script>
<!--对应wxss文件-->
<style lang="stylus">
</style>
<!--对应json文件-->
<script type="application/json">
{
"usingComponents": {
"list": "../components/list"
}
}
</script>
模板语法
Mpx中的模板语法以小程序模板语法为基础,支持小程序的全部模板语法,同时提供了一系列增强的模板指令及语法。
补充:
小程序的WXML语法和WXS语法我们可以先简单的了解一下
1、WXML语法参考:
数据绑定{{ }}
<!-- 1、-->
<view> {{ message }} </view>
<view wx:if="{{condition}}"> </view>
<!-- 2、-->
<view hidden="{{flag ? true : false}}"> Hidden </view>
<view>{{"hello" + name}}</view>
<view>{{object.key}} {{array[0]}}</view>
<!-- 3、-->
<!--最终组合成数组[0, 1, 2, 3, 4]-->
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
<!-- 最终组合成的对象是 {a: 1, b: 2, c: 3, d: 4, e: 5}。-->
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
c: 3,
d: 4
}
}
})
<!-- 存在变量名相同,后面覆盖前面-->
<!--最终组合成的对象是 {a: 5, b: 3, c: 6}-->
<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
Page({
data: {
obj1: {
a: 1,
b: 2
},
obj2: {
b: 3,
c: 4
},
a: 5
}
})
1、简单绑定:
使用双大括号将变量包起来,可以作用于内容、组件属性、控制属性,关键字(后三者都需要在双引号之内)。
2、运算:可以在{{}} 内进行简单的运算,有三元运算、算术运算、逻辑判断、字符串运算、数据路径运算。
3、组合:可以在{{}} 内直接进行组合,构成新的对象或者数组
在对 对象进行组合的时候我们可以使用扩展运算符将一个对象展开,如果在遇到相同的变量名的时候,后面的会覆盖前面。
注意:花括号如果与引号之间有空格,将最终被解析成为字符串
列表渲染wx:for
在组件使用wx:for
控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件,默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
使用
wx:for-item
可以指定数组当前元素的变量名
使用wx:for-index
可以指定数组当前下标的变量名
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
wx:for可以嵌套,下边是一个九九乘法表
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
<view wx:if="{{i <= j}}">
{{i}} * {{j}} = {{i * j}}
</view>
</view>
</view>
block wx:for
类似 block wx:if,也可以将 wx:for 用在标签上,以渲染一个包含多节点的结构块。例如:
<block wx:for="{{[1, 2, 3]}}">
<view> {{index}}: </view>
<view> {{item}} </view>
</block>
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供:
1、字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
2、保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。
当数据改变触发渲染层重新渲染的时候,会校正带有key的组件,框架会确保他们被重新排序
,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率
。
如果不提供 wx:key
,会报一个warning,如果明确知道该列表使静态,或者不必关注其顺序,可以选择忽略。
注意事项:当 wx:for 的值为字符串,会将字符串解析成字符串数组。
<view wx:for="array">
{{item}}
</view>
等同于
<view wx:for="{{['a','r','r','a','y']}}">
{{item}}
</view>
条件渲染wx:if
在框架中,使用 wx:if=“” 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}"> True </view>
也可以用 wx:elif 和 wx:else 来添加一个 else 块:
<view wx:if="{{length > 5}}">11</view>
<view wx:elif="{{length > 2}}">22</view>
<view wx:else>33</view>
block wx:if
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注意: 并不是一个组件,它仅仅是一个包装元素,不会再页面中做任何渲染,只接受控制属性。
wx:if vs hidden
因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if 有更高的切换消耗 而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情境下,用hidden更好,如果在运行时条件不大可能改变则wx:if较好。
模板
WXML提供模板,可以在模板中定义代码片段,然后在不同的地方调用。
定义模板
使用name属性,作为模板的名字。然后在 内定义代码片段,如:
<!--
index: int
msg: string
time: string
-->
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
使用模板
使用 is 属性,声明需要的使用的模板,然后将模板所需要的data传入,如:
<template is="msgItem" data="{{...item}}"/>
Page({
data: {
item: {
index: 0,
msg: 'this is a template',
time: '2016-09-15'
}
}
})
is 属性可以使用{{}} Mustache语法,来动态决定具体需要渲染哪个模板:
<template name="odd">
<view> odd </view>
</template>
<template name="even">
<view> even </view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
模板的作用域
模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 模块。
引用
WXML 提供两种文件引用方式import和include。
import
import 可以在该文件中使用目标文件定义的 template,如:
在item.wxml
中定义了一个叫 item 的template:
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在index.wxml中引入了 item.wxml,就可以使用item模板:
<import src="item.wxml" />
<template is="item" data="{{text:'forbar'}}" />
import 的作用域
import 有作用域的概念,即只会import目标文件中定义的template,而不会import 目标文件 import的template。
如:C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template。
<!-- A.wxml -->
<template name="A">
<text> A template </text>
</template>
<!-- B.wxml -->
<import src="a.wxml"/>
<template name="B">
<text> B template </text>
</template>
<!-- C.wxml -->
<import src="b.wxml"/>
<template is="A"/> <!-- Error! Can not use tempalte when not import A. -->
<template is="B"/>
include
include 可以将目标文件除了 <template/ > <wsx/ > 外的整个代码引入,相当于是拷贝到include位置,如:
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
2、WXS 语法参考
WXS 是小程序的一套脚本语言,结合 WXML , 可以构建出页面的结构。
WXS 与 JS 是不同的语言,有自己的语法,并不和 JS 一致。
WXS包括:WXS模块、变量、注释、运算符、语句、数据类型、基础类库。这里我们不做过多深入,类似于JS的语法,一些差别我们在编写的时候再进行总结。
3、Mpx模板语法
Mpx中的模板语法以小程序模板语法为基础,支持小程序的全部模板语法,同时提供了一系列增强的模板指令
及语法
。
Mpx提供的增强指令语法如下:
- wx:style 动态样式
- wx:class 动态类名
- wx:model 双向绑定
- wx:model-prop 双向绑定属性
- wx:model-event 双向绑定事件
- wx:model-value-path双向绑定数据路径
- wx:model-filter双向绑定过滤器
- wx:ref获取实例
- wx:show隐藏显示
- component动态组件
- 事件处理内联传参
- 模板条件编译
CSS处理
CSS预编译
mpx 支持CSS预编译处理,你可以通过在style标签上设置lang属性,来指定使用的CSS预处理器,此外需要在对应的 webpack 配置文件中加入对应的loader 配置。
(注意:要导入需要的loader的依赖)
<!-- 使用 less -->
<style lang="less">
.size {
width: 100px;
height: 80px
}
.nav {
.size();
color: #f90;
&:hover {
background-color: #f40;
color: #fff
}
}
</style>
// getRules 配置文件
rules: [
{
test: /\.less$/,
use: [
'css-loader',
'less-loader'
]
}
]
公共样式复用
- style src 复用
通过给style
标签添加src
属性引入外部样式,最终公共样式代码只会打包一份
<!-- index.mpx -->
<style lang="stylus" src="../styles/common.styl"></style>
<!-- list.mpx -->
<style lang="stylus" src="../styles/common.styl"></style>
mpx 将 common.styl 中的代码经过loader编译后生成一份单独的wxss文件,这样即实现了样式抽离,又能节省打包后的代码体积。
- @import 复用
如果指定 style 标签的 lang 属性并且使用 @import 导入样式,那么这个文件经过对应的 loader 处理之后的内容会重复打包到引用它的文件目录下,并不会抽离成单独的文件,这样无形中增加了代码体积
。
<!-- index.mpx -->
<style lang="stylus">
@import "../styles/mixin.styl"
</style>
<!-- list.mpx -->
<style lang="less">
@import "../styles/mixin.less";
</style>
但是如果导入的使一份css文件,则最终打包后的效果与 style src 一致。
// styles/mixin.css
.header-css {
width: 100%;
height: 100px;
background-color: #f00;
}
<!-- index.mpx -->
<style>
@import "../styles/mixin.css";
</style>
<!-- list.mpx -->
<style>
@import "../styles/mixin.css";
</style>
总结,公共样式复用:对于多个页面或组件公用的样式,建议使用style src形式引入,避免一份样式被内联打成多份,同时还能使用less、scss等提升编码效率。
数据响应
2.5.x 之前通过mobx实现内部和核心数据响应。
2.5.x 之后通过vue2的双向绑定
来实现数据响应,移除了对mobx的依赖。
在新的响应系统中,所有的使用方法和使用限制都和Vue保持一致。
<template>
<view>
<view>Num: {{num}}</view>
<view>Minus num: {{mnum}}</view>
<view>Num plus: {{nump}}</view>
<view>{{info.name}}</view>
<view wx:if="{{info.age}}">{{info.age}}</view>
</view>
</template>
<script>
import { createPage } from '@mpxjs/core'
createPage({
// data中定义的数据会在初始化时进行数据响应处理
data: {
num: 1,
info: {
name: 'test'
}
},
// 配置中直接定义watch
watch: {
num (val) {
console.log(val)
}
},
// 定义计算属性,模板中可以直接访问
computed: {
mnum () {
return -this.num
},
nump: {
get () {
return this.num + 1
},
// 支持计算属性的setter
set (val) {
this.num = val - 1
}
}
},
onReady () {
// 使用实例方法定义watch,可以传递追踪函数更加灵活
this.$watch(() => {
return this.nump - this.mnum
}, (val) => {
console.log(val)
})
// 每隔一秒进行一次更新,相关watcher会被触发,视图也会发生更新
setInterval(() => {
this.num++
}, 1000)
// 使用$set新增响应属性,视图同样能够得到更新
setTimeout(() => {
this.$set(this.info, 'age', 23)
}, 1000)
}
})
</script>
类名样式绑定
mpx利用wxs完整实现了Vue中的类名样式绑定,性能优良且没有任何使用限制(很多小程序框架基于字符串解析来实现该能力,只支持在模板上写简单的字面量,大大限制了使用场景)
类名绑定
类名绑定的增强指令是wx:class,可以与普通的class属性同时存在,在视图渲染中进行合成。
对象语法
wx:class 中传入对象,key值为类名,value值控制该类名是否生效。
<template>
<!--支持传入对象字面量,此处视图的class="outer active"-->
<view class="outer" wx:class="{{ {active:active, disabled:disabled} }}">
<!--直接直接传入对象数据,此处视图的class="inner selected"-->
<view class="inner" wx:class="{{innerClass}}"></view>
</view>
</template>
<script>
import { createPage } from '@mpxjs/core'
createPage({
data: {
active: true,
disable: false,
innerClass: {
selected: true
}
}
})
</script>
数组语法
wx:class 中传入字符串数组,字符串为类名
<template>
<!--支持传入数组字面量,此处视图的class="outer active danger"-->
<view class="outer" wx:class="{{ ['active', 'danger'] }}">
<!--直接直接传入数组数据,此处视图的class="inner selected"-->
<view class="inner" wx:class="{{innerClass}}"></view>
</view>
</template>
<script>
import { createPage } from '@mpxjs/core'
createPage({
data: {
innerClass: ['selected']
}
})
</script>
样式绑定
样式的增强指令是wx:style,可以与普通的style属性同时存在,在视图渲染中进行合成
对象语法
<template>
<!--支持传入对象字面量,模板会显得杂乱,此处视图的style="color:red;font-size:16px;font-weight:bold;"-->
<view style="color:red;" wx:style="{{ {fontSize:'16px', fontWeight:'bold'} }}">
<!--更好的方式是直接传入对象数据,此处视图的style="color:blue;font-size:14px;"-->
<view wx:style="{{innerStyle}}"></view>
</view>
</template>
<script>
import { createPage } from '@mpxjs/core'
createPage({
data: {
innerStyle: {
color: 'blue',
fontSize: '14px'
}
}
})
</script>
数组语法
wx:style同样支持传入数组将多个样式合成应用到视图上
<template>
<!--此处视图的style="color:blue;font-size:14px;background-color:red;"-->
<view wx:style="{{ [baseStyle, activeStyle] }}">
</view>
</template>
<script>
import { createPage } from '@mpxjs/core'
createPage({
data: {
baseStyle: {
color: 'blue',
fontSize: '14px'
},
activeStyle:{
backgroundColor: 'red'
}
}
})
</script>
条件渲染、列表渲染
Mpx中的条件渲染和列表渲染与原生小程序中完全一致,可以参考上文的wx:if的条件渲染使用,以及wx:for 的列表渲染
事件处理
Mpx在事件处理上基于原生小程序,支持原生小程序的全部事件处理技术规范,在此基础上新增了事件处理内联传参的增强机制。
增强:
- 增强的内联传参能力对于传递参数的个数和类型没有特殊限制
- 可以传递各种字面量,可以传递组件数据
- 可以传递for中的item和index
- 当内联事件处理器中需要访问原始事件对象时,可以传递
$event
特殊关键字作为参数,在事件处理器的对应参数位置即可获取。
<template>
<view>
<!--原生小程序语法,通过dataset进行传参-->
<button data-name="a" bindtap="handleTap">a</button>
<!--Mpx增强语法,模板内联传参,方便简洁-->
<button bindtap="handleTapInline('b')">b</button>
<!--参数支持传递字面量和组件数据-->
<button bindtap="handleTapInline(name)"></button>
<!--参数同样支持传递for作用域下的item/index-->
<button wx:for="{{names}}" bindtap="handleTapInline(item)">{{item}}</button>
<!--需要使用原始事件对象时可以传递$event特殊关键字-->
<button bindtap="handleTapInlineWithEvent('g', $event)">g</button>
</view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
createComponent({
data: {
name: 'c',
names: ['d', 'e', 'f']
},
methods: {
handleTap (e) {
console.log('name:', e.target.dataset.name)
},
// 直接通过参数获取数据,直观方便
handleTapInline (name) {
console.log('name:', name)
},
handleTapInlineWithEvent (name, e) {
console.log('name:', name)
console.log('event:', e)
}
}
})
</script>
效果如下:
双向绑定
Mpx针对表单组件提供了wx:model 双向绑定指令,类似于v-model, 该指令是一个语法糖指令。监听了组件抛出的输入事件并对绑定的数据进行更新,默认情况下会监听表单组件的input事件,并将并将event.detail.value中的数据更新到组件的value属性上。
简单实例
<view>
<input type="text" wx:model="{{message}}"/>
<!--view中的文案会随着用户对输入框进行输入而实时更新-->
<view>{{message}}</view>
</view>
对自定义组件使用
对自定义组件使用双向绑定时用法与原生小程序组件完全一致
<view>
<custom-input type="text" wx:model="{{message}}"/>
<!--此处的文案会随着输入框输入实时更新-->
<view>{{message}}</view>
</view>
更改双向绑定的监听事件及数据属性
如前文所述,wx:model 指令默认监听组件抛出的 input 事件,并将声明的数据绑定到组件的 value 属性上,该行为在一些原生组件和自定义组件上并不成立,因为这些组件可能不存在input事件或 value属性。
mpx提供了wx:model-event
和wx:model-prop
指令来修改双向绑定的监听事件和数据属性
简单的例子:
<view>
<!--原生组件picker中没有input事件,通过wx:model-event指令将双向绑定监听事件改为change事件-->
<picker mode="selector" range="{{countryRange}}" wx:model="{{country}}" wx:model-event="change">
<view class="picker">
当前选择: {{country}}
</view>
</picker>
<!--通过wx:model-event和wx:model-prop将该自定义组件的双向绑定监听事件和数据属性修改为customInput/customValue-->
<custom-input wx:model="{{message}}" wx:model-event="customInput" wx:model-prop="customValue"/>
<view>{{message}}</view>
</view>
更改双向绑定事件数据路径
Mpx中双向绑定默认使用event对象中的event.detail.value作为用户输入来更新组件数据,该行为在一些原生组件和自定义组件中也不成立,例如vant中的field输入框组件,用户的输入直接存储在event.detail当中,当然用户也可以将其存放在detail中的其他数据路径下,对此,我们提供了wx:model-value-path指令让用户声明在事件当中应该访问的数据路径。
由于小程序triggerEvent的Api设计,事件的用户数据都只能存放在event.detail中,因此wx:model-value-path的值都是相对于event.detail的数据路径,我们支持两种形式进行声明:
- 一种是点语法,如传入current.value时框架会从event.detail.current.value中取值作为用户输入,为空字符串时wx:model-value-path=""代表直接使用event.detail作为用户输入;
- 第二种是数组字面量的JSON字符串,如[“current”, “value”]与上面的current.value等价,传入[]时与上面的空字符串等价。
使用:
<view>
<!--wx:model-value-path传入[]直接使用event.detail作为用户输入,使vant-field中双向绑定能够生效-->
<van-field wx:model="{{username}}" wx:model-value-path="[]" label="用户名" placeholder="请输入用户名"/>
</view>
双向绑定过滤器
用户可以使用wx:model-filter指令定义双向绑定过滤器,在修改数据之前对用户输入进行过滤,来实现特定的效果,框架内置了trim过滤器对用户输入进行trim操作,传入其他字符串时会使用当前组件中的同名方法作为自定义过滤器,使用示例如下:
<view>
<!--以下示例中,用户输入的首尾空格将被过滤-->
<input wx:model="{{message}}" wx:model-filter="trim"/>
<view>{{message}}</view>
</view>
自定义组件
动态组件
Mpx中提供了使用方法类似于 Vue 的动态组件能力,这是一个基于 wx:if 实现的语法。通过对 is 属性
进行动态绑定,可以实现在同一个挂载点切换多个组件,前提需要动态切换的组件已经在全局或者组件中完成注册。 使用示例如下:
<view>
<!-- current为组件名称字符串,可选范围为局部注册的自定义组件和全局注册的自定义组件 -->
<!-- 当 `current`改变时,组件也会跟着切换 -->
<component is="{{current}}"></component>
</view>
<script>
import {createComponent} from '@mpxjs/core'
createComponent({
data: {
current: 'test'
},
ready () {
setTimeout(() => {
this.current = 'list'
}, 3000)
}
})
</script>
<script type="application/json">
{
"usingComponents": {
"list": "../components/list",
"test": "../components/test"
}
}
</script>
slot
在组件中使用 slot 可以是我们封装的组件更具有可扩展性,Mpx完全支持原生插槽的使用。
<!-- 组件模板 -->
<!-- components/mySlot.mpx -->
<view>
<view>这是组件模板</view>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
</view>
下面是引入mySlot 组件的页面
<!-- index.mpx -->
<template>
<view>
<my-slot>
<view slot="slot1">我是slot1中的内容</view>
<view slot="slot2">我是slot2中的内容</view>
</my-slot>
</view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
createComponent({
options: {
multipleSlots: true // 启用多slot支持
},
// ...
})
</script>
<script type="application/json">
{
"usingComponents": {
"my-slot": "components/mySlot"
}
}
</script>
获取组件实例/节点信息
微信小程序中原生提供selectComponent/SelectorQuery.select方法获取自定义组件实例和wxml节点信息,但是该api使用起来不太方便,并且不具备平台无关性,我们提供了增强指令wx:ref用于获取组件实例及节点信息,该指令的使用方式同vue中的ref类似,在模板中声明了wx:ref
后,在组件ready后用户可以通过 this.$refs
获取对应的组件实例或节点查询对象(NodeRefs),调用响应的组件方法或者获取视图节点信息。
<template>
<view class="container">
<!-- my-header 为一个组件,组件内部定义了一个 show 方法 -->
<my-header wx:ref="myHeader"></my-header>
<view wx:ref="content"></view>
</view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
createComponent({
ready() {
// 通过 this.$refs 获取view的节点查询对象
this.$refs.content.fields({size: true},function (res){
// res 就是我们要拿到的节点大小
}).exec()
// 通过 this.$refs 可直接获取组件实例
this.$refs.myHeader.show() // 拿到组件实例,调用组件内部的方法
}
})
</script>
在列表渲染中使用 wx:ref
在列表渲染中定义的wx:ref存在多个实例/节点,Mpx会在模板编译中判断某个wx:ref是否存在于列表渲染wx:for中,是的情况下在注入this.$refs时会通过selectAllComponents/SelectQuery.selectAll方法获取组件实例数组或数组节点查询对象,确保开发者能拿到列表渲染中所有的组件实例/节点信息。
<template>
<view>
<!-- list 组件 -->
<list wx:ref="list" wx:for="{{listData}}" data="{{item.name}}" wx:key="id"></list>
<!-- view 节点 -->
<view wx:ref="test" wx:for="{{listData}}" wx:key="id">{{item.name}}</view>
</view>
</template>
<script>
import { createComponent } from '@mpxjs/core'
createComponent({
data: {
listData: [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'},
]
},
ready () {
// 通过 this.$refs.list 获取的是组件实例的数组
this.$refs.list.forEach(item => {
// 对每一个组件实例的操作...
})
// 通过 this.$refs.test 获取的是节点查询对象,通过相关的方法操作节点
this.$refs.test.fields({size: true}, function (res) {
// 此处拿到的 res 是一个数组,包含了列表渲染中的所有节点的大小信息
}).exec()
}
})
</script>