Mpx的学习之基础语法了解

什么是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下对应平台的目录,对小程序进行预览、调试。
![在这里插入图片描述](https://img-blog.csdnimg.cn/f0fe8511683543a492cc5be833aacecf.png
我们打开微信小程序就可以看到这样的样式
在这里插入图片描述
快速建成项目成功,接下来我们继续了解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-eventwx: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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值