您的当前位置:首页正文

小程序踩坑日志(三)----Labrador

2024-11-27 来源:个人技术集锦

小程序模块化开发框架—–Labrador

网址:

所以不建议使用微信开发工具去直接修改代码,今天在网上看见一个Labrador框架,所以准备研究一下,正式学习之前需要具备一些知识 redux,

Labrador的优势

  • 支持微信开发工具支持海量npm包
  • 支持es6语法,使用async/await有效避免回调地狱
  • 对小程序框架二次封装,实现组件的重用和嵌套
  • 可继承redux使用redux数据流控制,让项目逻辑清晰可维护
  • 自动化测试,非常容易编写单元测试脚本,不经任何额外配置即可自动化测试
  • Flow.js强类型检查,编写更加安全稳定的代码
  • 使用Editor Config及ESLint标准化代码风格,方便团队协作
  • 强力压缩代码,尽可能减小程序体积,让你在1M的限制内做更多的事

环境搭建

首先系统中需要nodejs和npm,然后全局安装Labrador-cli

npm install -g labrador-cli

初始化项目

labrador create demo   //新建一个项目
cd demo                //进入demo

开发流程

常用命令

labrador create <name>   //创建项目

labrador build 【opation】 //构建当前项目

labrador watch 【opation】  //编辑当前项目并检测文件改动

labrador generate 【opation】 <type> <name>
                            //创建新组建,页面,redux saga

+ labrador generate page home/home //创建文件夹和新的页面
+ labrador generate component home //创建home组件
+ labrador generate redux home     //创建redux文件
+ labrador generate saga home      //创建saga文件

wxml中支持import和include,但仅时视图模板中可用,并非组件可重用,

wxml其实基于可重用组件,但不允许自定义组件

源码中const _ = require('lodash'); 被编译为 var _ = require('./npm/lodash/lodash.js');

commonents文件夹中存放公用的组件

在 src/pages/index/index.less 中加入代码 ‘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');
  }
}
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>

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

显示全文