微信小程序组件化开发框架WePY

作者: 魔王哪吒 | 来源:发表于2019-06-09 15:23 被阅读45次

    compilers: compilers为1.3.1版本之后的功能,如果需要使用其它语法,请先配置compilers,然后再安装相应的compilers。目前支持wepy-compiler-less, wepy-compiler-postcss,wepy-compiler-sass、wepy-compiler-babel、wepy-compiler-pug,其他compiler持续开发中......

    plugins: plugins为1.1.6版本之后的功能,目前支持js压缩wepy-plugin-ugliyjs、图片压缩wepy-plugin-imagemin,其他plugin持续开发中......

    lang决定了其代码编译过程,src决定是否外联代码

    <style lang="less" src="page1.less"></style>
    <template lang="wxml" src="page1.wxml"></template>
    <script>
        // some code
    </script>
    
    <script>
    import wepy from 'wepy';
    export default class extends wepy.app {
        config = {
            "pages":[
                "pages/index/index"
            ],
            "window":{
                "backgroundTextStyle": "light",
                "navigationBarBackgroundColor": "#fff",
                "navigationBarTitleText": "WeChat",
                "navigationBarTextStyle": "black"
            }
        };
        onLaunch() {
            console.log(this);
        }
    }
    </script>
    
    <style lang="less">
    /** less **/
    </style>
    
    <script>
    import wepy from 'wepy';
    import Counter from '../components/counter';
    
    export default class Page extends wepy.page {
        config = {};
        components = {counter1: Counter};
    
        data = {};
        methods = {};
    
        events = {};
        onLoad() {};
        // Other properties
    }
    </script>
    
    <template lang="wxml">
        <view>
        </view>
        <counter1></counter1>
    </template>
    
    <style lang="less">
    /** less **/
    </style>
    
    <template lang="wxml">
        <view>  </view>
    </template>
    
    <script>
    import wepy from 'wepy';
    export default class Com extends wepy.component {
        components = {};
    
        data = {};
        methods = {};
    
        events = {};
        // Other properties
    }
    </script>
    
    <style lang="less">
    /** less **/
    </style>
    
    import wepy from 'wepy';
    
    // 声明一个App小程序实例
    export default class MyAPP extends wepy.app {
    }
    
    // 声明一个Page页面实例
    export default class IndexPage extends wepy.page {
    }
    
    // 声明一个Component组件实例
    export default class MyComponent extends wepy.component {
    }
    
    import wepy from 'wepy';
    
    export default class MyAPP extends wepy.app {
        customData = {};
    
        customFunction () { }
    
        onLaunch () {}
    
        onShow () {}
    
        config = {}  // 对应 app.json 文件
    
        globalData = {}
    }
    

    在Page页面实例中,可以通过this.$parent来访问App实例。

    import wepy from 'wepy';
    
    export default class MyPage extends wepy.page {
    // export default class MyComponent extends wepy.component {
        customData = {}  // 自定义数据
    
        customFunction () {}  //自定义方法
    
        onLoad () {}  // 在Page和Component共用的生命周期函数
    
        onShow () {}  // 只在Page中存在的页面生命周期函数
    
        config = {};  // 只在Page实例中存在的配置数据,对应于原生的page.json文件
    
        data = {};  // 页面所需数据均需在这里声明,可用于模板数据绑定
    
        components = {};  // 声明页面中所引用的组件,或声明组件中所引用的子组件
    
        mixins = [];  // 声明页面所引用的Mixin实例
    
        computed = {};  // 声明计算属性(详见后文介绍)
    
        watch = {};  // 声明数据watcher(详见后文介绍)
    
        methods = {};  // 声明页面wxml中标签的事件处理函数。注意,此处只用于声明页面wxml中标签的bind、catch事件,自定义方法需以自定义方法的方式声明
    
        events = {};  // 声明组件之间的事件处理函数
    }
    
    // 错误示例
    
    import wepy from 'wepy';
    
    export default class MyComponent extends wepy.component {
        methods = {
            bindtap () {
                let rst = this.commonFunc();
                // doSomething
            },
    
            bindinput () {
                let rst = this.commonFunc();
                // doSomething
            },
    
            //错误:普通自定义方法不能放在methods对象中
            customFunction () {
                return 'sth.';
            }
        };
    
    }
    
    // 正确示例
    
    import wepy from 'wepy';
    
    export default class MyComponent extends wepy.component {
        methods = {
            bindtap () {
                let rst = this.commonFunc();
                // doSomething
            },
    
            bindinput () {
                let rst = this.commonFunc();
                // doSomething
            },
        }
    
        //正确:普通自定义方法在methods对象外声明,与methods平级
        customFunction () {
            return 'sth.';
        }
    
    }
    
    /**
    project
    └── src
        ├── components
        |   └── child.wpy
        ├── pages
        |   ├── index.wpy    index 页面配置、结构、样式、逻辑
        |   └── log.wpy      log 页面配置、结构、样式、逻辑
        └──app.wpy           小程序配置项(全局公共配置、公共样式、声明钩子等)
    **/
    
    // index.wpy
    
    <template>
        <!-- 以`<script>`脚本部分中所声明的组件ID为名命名自定义标签,从而在`<template>`模板部分中插入组件 -->
        <child></child>
    </template>
    
    <script>
        import wepy from 'wepy';
        //引入组件文件
        import Child from '../components/child';
    
        export default class Index extends wepy.page {
            //声明组件,分配组件id为child
            components = {
                child: Child
            };
        }
    </script>
    
    
    <template>
        <view class="child1">
            <child></child>
        </view>
    
        <view class="child2">
            <anotherchild></anotherchild>
        </view>
    </template>
    
    
    <script>
        import wepy from 'wepy';
        import Child from '../components/child';
    
        export default class Index extends wepy.page {
            components = {
                //为两个相同组件的不同实例分配不同的组件ID,从而避免数据同步变化的问题
                child: Child,
                anotherchild: Child
            };
        }
    </script>
    
    /**
    project
    └── src
        ├── components
        |   └── child.wpy
        ├── pages
        |   ├── index.wpy    index 页面配置、结构、样式、逻辑
        |   └── log.wpy      log 页面配置、结构、样式、逻辑
        └──app.wpy           小程序配置项(全局样式配置、声明钩子等)
    **/
    
    // index.wpy
    
    <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.page {
            components = {
                // 声明页面中要使用到的Child组件的ID为child
                child: Child
            }
    
            data = {
                list: [{id: 1, title: 'title1'}, {id: 2, title: 'title2'}]
            }
        }
    </script>
    
    
      data = {
          a: 1
      }
    
      // 计算属性aPlus,在脚本中可通过this.aPlus来引用,在模板中可通过{{ aPlus }}来插值
      computed = {
          aPlus () {
              return this.a + 1
          }
      }
    

    通过监听器watcher能够监听到任何属性的更新。监听器在watch对象中声明,类型为函数,函数名与需要被监听的data对象中的属性同名,每当被监听的属性改变一次,监听器函数就会被自动调用执行一次。

     data = {
          num: 1
      }
    
      // 监听器函数名必须跟需要被监听的data对象中的属性num同名,
      // 其参数中的newValue为属性改变后的新值,oldValue为改变前的旧值
      watch = {
          num (newValue, oldValue) {
              console.log(`num value: ${oldValue} -> ${newValue}`)
          }
      }
    
      // 每当被监听的属性num改变一次,对应的同名监听器函数num()就被自动调用执行一次
      onLoad () {
          setInterval(() => {
              this.num++;
              this.$apply();
          }, 1000)
      }
    
    
    props = {
        fromShopCar: Number
      }
    

    props传值

    静态传值为父组件向子组件传递常量数据,因此只能传递String字符串类型。

    在父组件template模板部分的组件标签中,使用子组件props对象中所声明的属性名作为其属性名来接收父组件传递的值。

    <child title="mytitle"></child>
    
    // child.wpy
    props = {
        title: String
    };
    
    onLoad () {
        console.log(this.title); // mytitle
    }
    
    
    // parent.wpy
    
    <child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child>
    
    data = {
        parentTitle: 'p-title'
    };
    
    
    // child.wpy
    
    props = {
        // 静态传值
        title: String,
    
        // 父向子单向动态传值
        syncTitle: {
            type: String,
            default: 'null'
        },
    
        twoWayTitle: {
            type: String,
            default: 'nothing',
            twoWay: true
        }
    };
    
    onLoad () {
        console.log(this.title); // p-title
        console.log(this.syncTitle); // p-title
        console.log(this.twoWayTitle); // p-title
    
        this.title = 'c-title';
        console.log(this.$parent.parentTitle); // p-title.
        this.twoWayTitle = 'two-way-title';
        this.$apply();
        console.log(this.$parent.parentTitle); // two-way-title.  --- twoWay为true时,子组件props中的属性值改变时,会同时改变父组件对应的值
        this.$parent.parentTitle = 'p-title-changed';
        this.$parent.$apply();
        console.log(this.title); // 'c-title';
        console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修饰符的props属性值,当在父组件中改变时,会同时改变子组件对应的值。
    }
    

    wepy.component基类提供broadcast、emit、$invoke三个方法用于组件之间的通信和交互

    import wepy from 'wepy'
    
    export default class Com extends wepy.component {
        components = {};
    
        data = {};
    
        methods = {};
    
        // events对象中所声明的函数为用于监听组件之间的通信与交互事件的事件处理函数
        events = {
            'some-event': (p1, p2, p3, $event) => {
                   console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`);
            }
        };
        // Other properties
    }
    

    @表示事件修饰符,customEvent 表示事件名称,.user表示事件后缀。

    目前总共有三种事件后缀:

    .default: 绑定小程序冒泡型事件,如bindtap,.default后缀可省略不写;

    .stop: 绑定小程序捕获型事件,如catchtap;

    .user: 绑定用户自定义组件事件,通过$emit触发。注意,如果用了自定义事件,则events中对应的监听函数不会再执行。

    // index.wpy
    
    <template>
        <child @childFn.user="parentFn"></child>
    </template>
    
    <script>
        import wepy from 'wepy'
        import Child from '../components/child'
    
        export default class Index extends wepy.page {
            components = {
                child: Child
            }
    
            methods = {
                parentFn (num, evt) {
                    console.log('parent received emit event, number is: ' + num)
                }
            }
        }
    </script>
    
    
    // child.wpy
    
    <template>
        <view @tap="tap">Click me</view>
    </template>
    
    <script>
        import wepy from 'wepy'
    
        export default class Child extends wepy.component {
            methods = {
                tap () {
                    console.log('child is clicked')
                    this.$emit('childFn', 100)
                }
            }
        }
    </script>
    

    slot 组件内容分发插槽

    在Panel组件中有以下模板:

    <view class="panel">
        <slot name="title">默认标题</slot>
        <slot name="content">默认内容</slot>
    </view>
    在父组件中使用Panel子组件时,可以这样使用:
    
    <panel>
        <view slot="title">新的标题</view>
        <view slot="content">
            <text>新的内容</text>
        </view>
    </panel>
    
    
    // mixins/test.js
    import wepy from 'wepy';
    
    export default class TestMixin extends wepy.mixin {
        data = {
            foo: 'foo defined by page',
            bar: 'bar defined by testMix'
        };
        methods = {
        tap () {
          console.log('mix tap');
        }
      }
    }
    
    // pages/index.wpy
    import wepy from 'wepy';
    import TestMixin from './mixins/test';
    
    export default class Index extends wepy.page {
        data = {
            foo: 'foo defined by index'
        };
        mixins = [TestMixin ];
        onShow() {
            console.log(this.foo); // foo defined by index
            console.log(this.bar); // bar defined by testMix
        }
    }
    
    // mixins/test.js
    import wepy from 'wepy';
    
    export default class TestMixin extends wepy.mixin {
        methods = {
            tap () {
                console.log('mixin tap');
            }
        };
        onShow() {
            console.log('mixin onshow');
        }
    }
    
    // pages/index.wpy
    import wepy from 'wepy';
    import TestMixin from './mixins/test';
    
    export default class Index extends wepy.page {
    
        mixins = [TestMixin];
        methods = {
            tap () {
                console.log('index tap');
            }
        };
        onShow() {
            console.log('index onshow');
        }
    }
    
    
    // index onshow
    // mixin onshow
    // ----- when tap
    // index tap
    // mixin tap
    
    
    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);
                }
            });
        }
    }
    

    WePY脏数据检查流程

    // 原生代码:
    
    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);
    }
    
    // 原生的事件传参方式:
    
    <view data-id="{{index}}" data-title="wepy" data-other="otherparams" bindtap="tapName"> Click me! </view>
    
    Page({
        tapName: function (event) {
            console.log(event.currentTarget.dataset.id)// output: 1
            console.log(event.currentTarget.dataset.title)// output: wepy
            console.log(event.currentTarget.dataset.other)// output: otherparams
        }
    });
    
    // WePY 1.1.8以后的版本,只允许传string。
    
    <view @tap="tapName({{index}}, 'wepy', 'otherparams')"> Click me! </view>
    
    methods: {
        tapName (id, title, other, event) {
            console.log(id, title, other)// output: 1, wepy, otherparams
        }
    }
    
    // 原生代码:
    
    <view> {{ message }} </view>
    
    onLoad: function () {
        this.setData({message: 'hello world'});
    }
    
    
    // WePY
    <view> {{ message }} </view>
    
    onLoad () {
        this.message = 'hello world';
    }
    
    // 原生代码:
    
    <!-- item.wxml -->
    <template name="item">
      <text>{{text}}</text>
    </template>
    
    <!-- index.wxml -->
    <import src="item.wxml"/>
    <template is="item" data="{{text: 'forbar'}}"/>
    
    <!-- index.js -->
    var item = require('item.js')
    
    // WePY
    <!-- /components/item.wpy -->
     <text>{{text}}</text>
    
    <!-- index.wpy -->
    <template>
        <com></com>
    </template>
    <script>
        import wepy from 'wepy';
        import Item from '../components/item';
        export default class Index extends wepy.page {
            components = { com: Item }
        }
    </script>
    

    请点赞!因为你的鼓励是我写作的最大动力!

    官方微信公众号

    吹逼交流群:711613774

    吹逼交流群

    相关文章

      网友评论

        本文标题:微信小程序组件化开发框架WePY

        本文链接:https://www.haomeiwen.com/subject/dlknxctx.html