二、列表渲染
在列表渲染上三者也分别有不同的应用方法
1、wepy当需要循环渲染WePY组件时(类似于通过wx:for
循环渲染原生的wxml标签),必须使用WePY定义的辅助标签<repeat>
<template> <!-- 注意,使用for属性,而不是使用wx:for属性 --> <repeat for="{{list}}" key="index" index="index" item="item"> <!-- 插入<script>脚本部分所声明的child组件,同时传入item --> <child :item="item"></child> </repeat> </template> <script> import wepy from 'wepy'; // 引入child组件文件 import Child from '../components/child'; export default class Index extends wepy.component { components = { // 声明页面中要使用到的Child组件的ID为child child: Child } data = { list: [{id: 1, title: 'title1'}, {id: 2, title: 'title2'}] } } </script>
2、mpvue使用v-for与vue一致,只是需要注意一点,嵌套列表渲染,必须指定不同的索引!
mpvue使用v-for与vue一致,只是需要注意一点,嵌套列表渲染,必须指定不同的索引!
<!-- 在这种嵌套循环的时候, index 和 itemIndex 这种索引是必须指定,且别名不能相同,正确的写法如下 -->
<template> <ul v-for="(card, index) in list"> <li v-for="(item, itemIndex) in card"> {{item.value}} </li> </ul> </template>
3、taro的列表循环用法基本与react相同,有一点需要注意,在 React 中,JSX 是会编译成普通的 JS 的执行,每一个 JSX 元素,其实会通过 createElement
函数创建成一个 JavaScript 对象(React Element),因此实际上你可以这样写代码 React 也是完全能渲染的:
const list = this.state.list.map(l => { if (l.selected) { return <li>{l.text}</li> } }).filter(React.isValidElement)
但是 Taro 中,JSX 会编译成微信小程序模板字符串,因此你不能把 map
函数生成的模板当做一个数组来处理。当你需要这么做时,应该先处理需要循环的数组,再用处理好的数组来调用 map 函数。例如上例应该写成:
const list = this.state.list .filter(l => l.selected) .map(l => { return <li>{l.text}</li> })
三、事件处理
1、mpvue目前全支持小程序的事件处理器,引入了 Vue.js 的虚拟 DOM ,在前文模版中绑定的事件会被挂在到 vnode 上,同时 compiler 在 wxml 上绑定了小程序的事件,并做了相应的映射,所以你在真实点击的时候通过 runtime 中 handleProxy
通过事件类型分发到 vnode 的事件上,同 Vue 在 WEB 的机制一样,所以可以做到无损支持。同时还顺便支持了自定义事件和 $emit
机制
// 事件映射表,左侧为 WEB 事件,右侧为 小程序 对应事件 { click: 'tap', touchstart: 'touchstart', touchmove: 'touchmove', touchcancel: 'touchcancel', touchend: 'touchend', tap: 'tap', longtap: 'longtap', input: 'input', change: 'change', submit: 'submit', blur: 'blur', focus: 'focus', reset: 'reset', confirm: 'confirm', columnchange: 'columnchange', linechange: 'linechange', error: 'error', scrolltoupper: 'scrolltoupper', scrolltolower: 'scrolltolower', scroll: 'scroll' }
踩坑注意(官方文档):
- 列表中没有的原生事件也可以使用例如 bindregionchange 事件直接在 dom 上将bind改为@
@regionchange
,同时这个事件也非常特殊,它的 event type 有 begin 和 end 两个,导致我们无法在handleProxy
中区分到底是什么事件,所以你在监听此类事件的时候同时监听事件名和事件类型既
<map @regionchange="functionName" @end="functionName" @begin="functionName"><map>
- 小程序能力所致,bind 和 catch 事件同时绑定时候,只会触发 bind ,catch 不会被触发,要避免踩坑。
- 事件修饰符
.stop
的使用会阻止冒泡,但是同时绑定了一个非冒泡事件,会导致该元素上的 catchEventName 失效!.prevent
可以直接干掉,因为小程序里没有什么默认事件,比如submit并不会跳转页面.capture
支持1.0.9
.self
没有可以判断的标识.once
也不能做,因为小程序没有 removeEventListener, 虽然可以直接在 handleProxy 中处理,但非常的不优雅,违背了原意,暂不考虑
- 其他 键值修饰符 等在小程序中压根没键盘,所以。。。
2、wepy事件绑定区别于vue,根据原生小程序事件提供了语法优化
绑定事件 bindtap="click" 替换为 @tap="click", 取消冒泡 原catchtap="click"替换为@tap.stop="click"。 捕获监听事件 capture-bind:tap="click" 替换为 @tap.capture="click", 中断捕获监听 capture-catch:tap=“click"替换为 @tap.capture.stop="click"。
3、Taro 元素的事件处理和 DOM 元素的很相似。但是有一点语法上的不同:
Taro 事件绑定属性的命名采用驼峰式写法,而不是小写。如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串 (DOM 元素的写法)。例如,传统的微信小程序模板:
<button onclick="activateLasers"> Activate Lasers </button>
Taro 中稍稍有点不同:
<button onClick={this.activateLasers}> Activate Lasers </button>
在 Taro 中另一个不同是你不能使用 catchEvent
的方式阻止事件冒泡。你必须明确的使用 stopPropagation
。例如,阻止事件冒泡你可以这样写:
class Toggle extends React.Component { constructor (props) { super(props) this.state = {isToggleOn: true} } onClick = (e) => { e.stopPropagation() this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })) } render () { return ( <button onClick={this.onClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ) } }
四、request请求
1、wepy对wx.request做了接受参数的修改,值得一提的是它提供了针对全局的intercapter拦截器
wx.request({ url: 'xxx', success: function (data) { console.log(data); } });
// WePY 使用方式, 需要开启 Promise 支持,参考开发规范章节
wepy.request('xxxx').then((d) => console.log(d)); // async/await 的使用方式, 需要开启 Promise 和 async/await 支持,参考 WIKI async function request () { let d = await wepy.request('xxxxx'); console.log(d); }
拦截器
import wepy from 'wepy'; export default class extends wepy.app { constructor () { // this is not allowed before super() super(); // 拦截request请求 this.intercept('request', { // 发出请求时的回调函数 config (p) { // 对所有request请求中的OBJECT参数对象统一附加时间戳属性 p.timestamp = +new Date(); console.log('config request: ', p); // 必须返回OBJECT参数对象,否则无法发送请求到服务端 return p; }, // 请求成功后的回调函数 success (p) { // 可以在这里对收到的响应数据对象进行加工处理 console.log('request success: ', p); // 必须返回响应数据对象,否则后续无法对响应数据进行处理 return p; }, //请求失败后的回调函数 fail (p) { console.log('request fail: ', p); // 必须返回响应数据对象,否则后续无法对响应数据进行处理 return p; }, // 请求完成时的回调函数(请求成功或失败都会被执行) complete (p) { console.log('request complete: ', p); } }); } }
2、taro对request进行了二次封装,可以使用Taro.request(OBJECT)发起网络请求,支持 Promise
化使用。
import Taro from '@tarojs/taro' Taro.request({ url: 'http://localhost:8080/test', data: { foo: 'foo', bar: 10 }, header: { 'content-type': 'application/json' } }) .then(res => console.log(res.data))
mpvue没有对request做特殊优化,与原生相同,可以自己根据需要进行封装
五、状态管理
1、wepy 可引用Redux和Mbox,目前wepy的脚手架内已经集成了redux,选择需要即可;
2、mpVue使用vuex
3、taro使用Redux
如何选择适合自己的项目
- 如果只需要做一个微信小程序则根据自己的擅长框架选择mpvue或taro
- 如果是当前老项目想像向程序迁移同时老项目又是使用vue开发,建议使用mpvue或wepy
- 如果是老项目使用react开发且需要部分迁移小程序,建议使用taro
- 如果是新项目且新项目需要同时支持微信小程序和支付宝小程序, 建议使用原生开发,因为目前框架的转译支付宝小程序支持并不是很好,且出了问题不好定位修改, 但如果是小demo不涉及太多逻辑的项目都可以使用框架作为尝鲜; 但如果是涉及太多交互逻辑的则不建议使用框架转译,由于支付宝小程序在视图层基本与小程序一致所以建议手动更改替换部分方法和全局替换一些属性或文件名,如wxml替换为axml这种, 手动转换时间比大概是四比一; 当然如果人手足够一端开发一个是最好的...
交流
我是小礼,公众号「进军全栈攻城狮」作者 ,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!