微信开发者工具开发微信遇到的问题
1~~~无法调用npm包
虽然微信小程序开发工具打包时实现require函数加载依赖,但并不是完整的commonJS依赖管理。因为require函数仅仅能够加载项目中的JS文件,必须严格的定义文件路径
2~~~无法使用Babel转码
无法使用babel的根本原因还是无法加载npm包,也就是不能使用es6的新语法,得和无尽的callback作斗争。
3~~~无法重用组件
wxml中支持import和include,但仅时视图模板中可用,并非组件可重用,
wxml其实基于可重用组件,但不允许自定义组件
重要的是,只有真正用到的js文件才被labrador命令加入到项目目录中。这样一个小小的改进象征着我们的小程序可以便捷调用NPM仓库中海量的扩展库!
源码中const _ = require('lodash'); 被编译为 var _ = require('./npm/lodash/lodash.js');
commonents文件夹中存放公用的组件
在 src/pages/index/index.less 中加入代码 @import ‘list’ 即可调用list组件的样式,如果在src/components/list中找不到list.less,那么编译命令将在NPM包中寻找 node_modules/list/index.less 。
在 src/pages/index/index.xml 中加入代码 即可调用list组件的模板文件,component 是Labrador自定义的组件,编译后对应生成 import 和 template。如果在src/components/list中找不到list.xml,那么编译命令将在NPM包中寻找 node_modules/list/index.xml
页面(pages)也是组件
默认首页的示例代码
index.js
import wx, { Component } from 'labrador';
import List from '../../components/list/list';
import Title from '../../components/title/title';
import Counter from '../../components/counter/counter';
export default class Index extends wx.Component {
state = {
userInfo: {},
mottoTitle: 'Hello World',
count: 0
};
children() {
return {
list: {
component: List
},
motto: {
component: Title,
props: {
text: this.state.mottoTitle
}
},
counter: {
component: Counter,
props: {
count: this.state.count,
onChange: this.handleCountChange
}
}
};
}
handleCountChange(count) {
this.setState({ count });
}
//事件处理函数
handleViewTap() {
wx.navigateTo({
url: '../logs/logs'
});
}
async onLoad() {
try {
//调用应用实例的方法获取全局数据
let userInfo = await wx.app.getUserInfo();
//更新数据
this.setState({ userInfo });
this.update();
} catch (error) {
console.error(error.stack);
}
}
onReady() {
this.setState('mottoTitle', 'Labrador');
}
}
js中export default会导出一个默认的类,不可手动调用Page(),因为在编译之后pages目录下所有的js全会自动调用Page()方法声明页面。
children()方法
children()方法返回该组件依赖,包含的其他自定义组件,
以上的代码中包含了三个自定义组件list ,title,counter
children()方法包含两个属性,component属性定义了组件类,props属性定义了父组件向子组件传递的props属性对象,
页面也是组件,所有的组件都拥有一样的生命周期函数onLoad, onReady, onShow, onHide, onUnload,onUpdate 以及setState函数。
注意所有的组件生命周期都支持async,但默认的是普通函数,如果函数内没有异步操作,建议采用普通函数,async函数会有一定的性能开销,可能无法顺畅的执行
components和pages两个目录的区别在于,components中存放的组件能够被智能加载,重用,pages目录中的组件在编译时加上pages()调用,所以pages目录中的组件不能被重复调用,也就是说不可被其他组件调用,否则会报错,
布局index.xml
<view class="container">
<view class="userinfo" catchtap="handleViewTap">
<image class="userinfo-avatar" src="{{ state.userInfo.avatarUrl }}" background-size="cover"/>
<text class="userinfo-nickname">{{ state.userInfo.nickName }}</text>
</view>
<view class="usermotto">
<component key="motto" name="title"/>
</view>
<component key="list"/>
<component key="counter"/>
</view>
以上这段代码中使用了labrador提供的 标签,此标签的作用是导入一个自定义组件的布局文件。标签有两个属性,分别是key(必须)和name(可选,默认是key的值)。key与js逻辑代码中的组件key对应,name是 组件的目录名。
key用来绑定组件js逻辑对象的children中对应的数据,name用于在src/components和node_moudles目录中寻找子组件模板。
labrador支持多层组件嵌套
自定义组件列表
逻辑 src/components/list/list.js
import wx, { Component } from 'labrador';
import Title from '../title/title';
import Item from '../item/item';
import { sleep } from '../../utils/util';
export default class List extends Component {
constructor(props){
super(props);
this.state = {
items: [
{ id:1, title: 'Labrador' },
{ id:2, title: 'Alaska' }
]
};
}
children (){
return {
title:{
component: Title,
props: { text: 'The List Title' }
},
listItems: this.state.items.map((item) => {
return {
component: Item,
key: item.id,
props: {
item: item,
title: item.title,
isNew: item.isNew,
onChange: (title) => { this.handleChange(item, title) }
}
};
})
};
}
async onLoad() {
await sleep(1000);
this.setState({
items: [{ id:3, title: 'Collie', isNew: true }].concat(this.data.items)
});
}
handleChange(item, title) {
let items = this.state.items.map((i) => {
if(item.id == i.id){
return Object.assign({},i,{ title });
}
return i;
});
this.setState({ items });
}
}
以上代码中children()返回的listItem子组件定义时,是一个组件数组,数组的每一项都是一个子组件的定义,并且需要每一项的key属性,key属性将用于模板渲染性能优化,建议将唯一且不宜变化的值设为子组件的key