小程序开发之wepy


title: 小程序教程之wepy

参考文档
  1. 中文文档:https://tencent.github.io/wepy/document.html#/?id=app%e5%b0%8f%e7%a8%8b%e5%ba%8f%e5%ae%9e%e4%be%8b
  2. github:https://github.com/Tencent/wepy
  3. 微信小程序开发资源导航:http://www.yimijili.com/xcxwzdh.html
  4. over
VSCode自动补齐Vue语法

打卡VScode、首选项 、设置,或者直接Comand+,快捷键

补全的语法为类Vue语法

用户设置一栏中改成:

// {
//     "window.zoomLevel": 0,
//     "editor.fontSize": 16,
//     "files.associations": {
//         "*.wpy": "vue",
//         "*.wxss": "css",
//         "*.wxml": "html"
//     }
// }

// Place your settings in this file to overwrite the default settings
{

// 配置 glob 模式以排除文件和文件夹。
"files.exclude": {
  "**/.git": true,
  "**/.svn": true,
  "**/.hg": true,
  "**/CVS": true,
  "**/.DS_Store": true,
  // "**/node_modules": true,
  "**/bower_components": true
  // "**/dist": true
},
// 配置语言的文件关联(如: "*.extension": "html")。这些关联的优先级高于已安装语言的默认关联。
"files.associations": {
  "*.vue": "vue",
  "*.wpy": "vue",
  "*.wxss": "postcss",
  "*.tpl": "vue",
  "*.md@xxx": "markdown",
  "*.wepy": "vue"
},
// 一个制表符等于的空格数。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。
"editor.tabSize": 2,
// 当打开文件时,将基于文件内容检测 "editor.tabSize" 和 "editor.insertSpaces"。
"editor.detectIndentation": false,
"window.zoomLevel": 1,
"editor.wordWrap": "on",
"workbench.iconTheme": "vs-seti",
"editor.wordSeparators": "`~!@#$%^&*()=+[{]}\\|;:'\",.<>/?。",
"editor.minimap.enabled": true,
// 控制键入时是否应自动显示建议
"editor.quickSuggestions": {
  "other": true,
  "comments": true,
  "strings": true
},
// 配置 glob 模式以在搜索中排除文件和文件夹。从 files.exclude 设置中继承所有 glob 模式。
"search.exclude": {
  "**/node_modules": true,
  "**/bower_components": true,
  "**/dist": true
},
// 控制编辑器是否应呈现缩进参考线
"editor.renderIndentGuides": true,
"emmet.syntaxProfiles": {
  "vue-html": "html",
  "vue": "html"
},

// 配置内置 HTML 语言支持是否建议 Angular V1 标记和属性。
"html.suggest.angular1": false,
// 自动更新扩展
"extensions.autoUpdate": true,
// 对属性进行换行。
"html.format.wrapAttributes": "auto",
// Link file types to the beautifier type
"beautify.language": {
  "js": {
    "type": [
      "javascript",
      "json"
    ],
    "filename": [
      ".jshintrc",
      ".jsbeautify",
      ".eslintrc.js"
    ]
  },
  "css": [
    "css",
    "scss"
  ],
  "html": [
    "htm",
    "html"
  ]
},
"git.enabled": false,
"editor.renderControlCharacters": true,
"typescript.check.npmIsInstalled": false,
"extensions.ignoreRecommendations": false,
// 覆盖当前所选颜色主题的颜色。 此为实验性设置,因为下一版本中将更改颜色名称。
// "workbench.experimental.colorCustomizations": {
//   "statusBarBackground": "#666666",
//   "panelBackground": "#555555",
//   "sideBarBackground": "#444444"
// }
// When enabled, emmet abbreviations are expanded when pressing TAB.
"emmet.triggerExpansionOnTab": true,
"workbench.panel.location": "bottom",
  "editor.fontSize": 16
}

over

快速入门
  1. 初始化项目

    1.全局安装或者更新wepy命令行工具
    $ npm install wepy-cli -g
    
    2.在开发目录中生成Demo开发项目
    wepy new myproject
    # 1.7.0之后的版本使用 wepy init standard myproject 初始化项目,使用 wepy list 查看项目模板
    
    3.编译
    $ cd project
    $ npm install 
    $ wepy build --watch 或者
    $ npm run dev
    
  2. 项目目录

    ├── dist                   微信开发者工具指定的目录(该目录由WePY的build指令自动编译生成,请不要直接修改该目录下的文件)
    ├── node_modules           
    ├── src                    代码编写的目录(该目录为使用WePY后的开发目录)
    |   ├── components         WePY组件目录(组件不属于完整页面,仅供完整页面或其他组件引用)
    |   |   ├── com_a.wpy      可复用的WePY组件a
    |   |   └── com_b.wpy      可复用的WePY组件b
    |   ├── pages              WePY页面目录(属于完整页面)
    |   |   ├── index.wpy      index页面(经build后,会在dist目录下的pages目录生成index.js、index.json、index.wxml和index.wxss文件)
    |   |   └── other.wpy      other页面(经build后,会在dist目录下的pages目录生成other.js、other.json、other.wxml和other.wxss文件)
    |   └── app.wpy            小程序配置项(全局数据、样式、声明钩子等;经build后,会在dist目录下生成app.js、app.json和app.wxss文件)
    └── package.json           项目的package配置
    
  3. 重要提醒

    1. 微信开发者工具添加dist目录
    2. 微信开发者工具关闭ES6转ES5
    3. 运行 wepy build --watch 实时编译
    。。。
    
  4. 代码高亮和代码规范

  5. over

主要功能特性
  1. 开发模式转换

    原生代码
    //index.js
    
    //获取应用实例
    var app = getApp()
    
    //通过Page构造函数创建页面逻辑
    Page({
        //可用于页面模板绑定的数据
        data: {
            motto: 'Hello World',
            userInfo: {}
        },
    
        //事件处理函数
        bindViewTap: function() {
            console.log('button clicked')
        },
    
        //页面的生命周期函数
        onLoad: function () {
            console.log('onLoad')
        }
    

    基于wepy的代码

    //index.wpy中的
    

  2. 支持加载外部npm包

  3. 单文件模式,目录结构更加清晰,开发方便

  4. WePY中则使用了单文件模式,将原生小程序app实例的3个文件统一为app.wpy,page页面的4个文件统一为page.wpy

  5. 默认babel编译,支持ES7新特性

  6. 针对原生API进行优化,如wx.request的并发问题等。

  7. over

进阶介绍
  1. wepy.config.js配置文件

    执行wepy new demo 后,会生成类似下面的配置文件

    let prod = process.env.NODE_ENV === 'production';
    module.exports = {
        'output': 'dist',
        'source': 'src',
        'wpyExt': '.wpy',
        'compilers': {
            less: {
                'compress': true
            },
            /*sass: {
                'outputStyle': 'compressed'
            },*/
            babel: {
                'presets': [
                    'es2015',
                    'stage-1'
                ],
                'plugins': [
                    'transform-export-extensions',
                    'syntax-export-extensions',
                    'transform-runtime'
                ]
            }
        },
        'plugins': {
        }
    };
    
    if (prod) {
        // 压缩sass
        module.exports.compilers['sass'] = {'outputStyle': 'compressed'};
    
        // 压缩less
        module.exports.compilers['less'] = {'compress': true};
    
        // 压缩js
        module.exports.plugins = {
            'uglifyjs': {
                filter: /\.js$/,
                config: {
                }
            },
            'imagemin': {
                filter: /\.(jpg|png|jpeg)$/,
                config: {
                    'jpg': {
                        quality: 80
                    },
                    'png': {
                        quality: 80
                    }
                }
            }
        };
    }
    
    wpyExt: 默认值为.wpy
    compilers: sass\less\stylus\babel\typscript
    plugins
    
    

  2. .wepy文件说明

    .wepy 文件编译过程:

    小程序开发之wepy_第1张图片
    图片

    .wpy文件分为三个部分

    • 脚本部分,即标签中的内容,又可分为两个部分:

    逻辑部分,除了config对象之外的部分,对应于原生的.js文件;

    配置部分,即config对象,对应于原生的.json文件。

    • 结构部分,即模板部分,对应于原生的.wxml文件。
  • 样式部分,即样式部分,对应于原生的.wxss文件。

  • .wpy文件中的scripttemplatestyle这三个标签都支持langsrc属性,lang决定了其代码编译过程,src决定是否外联代码,存在src属性且有效时,会忽略内联代码。

  • 各标签对应的lang值如下表所示:

    标签 lang默认值 lang支持值
    style css csslessscssstylus
    template wxml wxmlxmlpug(原jade)
    script babel babelTypeScript
  1. over

  2. over

脚本部分介绍
  1. 小程序入口app.wpy

    
    
    
    入口文件app.wpy中所声明的小程序实例继承自wepy.app类,包含一个config属性和其它全局属性、方法、事件。其中config属性对应原生的app.json文件,build编译时会根据config属性自动生成app.json文件,如果需要修改config中的内容,请使用微信提供的相关API。
    
  2. 页面page.wpy

    
    
    
    
    
    
    属性 说明
    config 页面配置对象,对应于原生的page.json文件,类似于app.wpy中的config
    components 页面组件列表对象,声明页面所引入的组件列表
    data 页面渲染数据对象,存放可用于页面模板绑定的渲染数据
    methods wxml事件处理函数对象,存放响应wxml中所捕获到的事件的函数,如bindtapbindchange
    events WePY组件事件处理函数对象,存放响应组件之间通过$broadcast$emit$invoke所传递的事件的函数
    其它 小程序页面生命周期函数,如onLoadonReady等,以及其它自定义的方法与属性
  3. 组件com.wpy

    
    
    
    
    
    组件文件com.wpy中所声明的组件实例继承自wepy.component类,除了不需要config配置以及页面特有的一些生命周期函数之外,其属性与页面属性大致相同。
    
  4. over

实例
  1. 实例

    wepy中,小程序被分为三个实例:

    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 {
    }
    
  2. App小程序实例

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

  3. Page页面实例和Component组件实例

    Page实际上继承自Component组件,即Page也是组建。

    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 = {};  // 声明组件之间的事件处理函数
    }
    
    WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法,这与Vue中的用法是不一致的
    

组件
  1. WePY中实现了小程序的组件化开发,组件的所有业务与功能在组件本身实现,组件与组件之间彼此隔离

  2. 普通组件引用

    当页面需要引入子组件时,

    必须 在.wpy文件的

  3. 组件的循环渲染

    当需要循环渲染WePY组件时(类似于通过wx:for循环渲染原生的wxml标签),必须使用WePY定义的辅助标签

    
    // index.wpy
    
    
    
    
    
  4. computed计算属性

    computed计算属性,是一个有返回值的函数,可直接被当做绑定数据来使用。需要注意的是,只要是组件中有任何数据发生了改变,那么所有计算属性就都会被重新计算

    data = {
          a: 1
      }
    
      // 计算属性aPlus,在脚本中可通过this.aPlus来引用,在模板中可通过{{ aPlus }}来插值
      computed = {
          aPlus () {
              return this.a + 1
          }
      }
    
  5. watcher监听器

    通过监听器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)
      }
    
  6. props传值

    传值包括三种:父组件向子组件传值,子组件向父组件传值,双向传值

    props传值在WePY中属于父子组件之间传值的一种机制,包括静态传值与动态传值。

    
    
    // child.wpy
    props = {
        title: String
    };
    
    onLoad () {
        console.log(this.title); // mytitle
    }
    

    动态传值,双向绑定

    动态传值是指父组件向子组件传递动态数据内容,父子组件数据完全独立互不干扰。但可以通过使用.sync修饰符来达到父组件数据绑定至子组件的效果,也可以通过设置子组件props的twoWay: true来达到子组件数据绑定至父组件的效果。那如果既使用.sync修饰符,同时子组件props中添加的twoWay: true时,就可以实现数据的双向绑定了。

    // parent.wpy
    
    
    
    data = {
        parentTitle: 'p-title'
    };
    

// child.wpy

props = {
// 静态传值
title: String,

   // 父向子单向动态传值
   syncTitle: {
       type: String,
       default: 'null'
   },

   twoWayTitle: {
       type: Number,
       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属性值,当在父组件中改变时,会同时改变子组件对应的值。

}


​

7. 组件通信与交互

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

```js
this.$emit('some-event', 1, 2, 3, 4);

用于监听组件之间的通信与交互事件的事件处理函数需要写在组件和页面的events对象中,如:

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
}

$broadcast 广播

$emit 出发

$invoke 直接调用

  1. 组件自定义事件处理函数

    可以通过使用.user修饰符为自定义组件绑定事件,如:@customEvent.user="myFn" 其中,@表示事件修饰符,customEvent 表示事件名称,.user表示事件后缀。

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

    • .default: 绑定小程序冒泡型事件,如bindtap.default后缀可省略不写;
    • .stop: 绑定小程序捕获型事件,如catchtap
    • .user: 绑定用户自定义组件事件,通过$emit触发。注意,如果用了自定义事件,则events中对应的监听函数不会再执行。
    // index.wpy
    
    
    
    
    // child.wpy
    
    
    
    
    

  2. slot组件内容分发插槽

    相当于占位符

    在Panel组件中有以下模板
    
        默认标题
        默认内容
    
    在父组件中使用Pannel子组件时,可以这样使用:
    
        新的标题
        
            新的内容
        
    
    

  3. over

第三方组件

WePY允许使用基于WePY开发的第三方组件,开发第三方组件规范请参考wepy-com-toast。

Mixin混合

混合可以将组之间的可复用部分抽离,从而在组件中使用混合时,可以将混合的数据,事件以及方法注入到组件之中。混合分分为两种:

  • 默认式混合
  • 兼容式混合
  1. 默认式混合
  2. 兼容式混合
WXS
interceptor拦截器

over

数据绑定
  1. 原生小程序数据绑定方式

    this.setData({title: 'this is title'});
    
  2. wepy数据绑定方式

    WePY使用脏数据检查对setData进行封装,在函数运行周期结束时执行脏数据检查,一来可以不用关心页面多次setData是否会有性能上的问题,二来可以更加简洁去修改数据实现绑定,不用重复去写setData方法

    this.title = 'this is title';
    

    需注意的是,在异步函数中更新数据的时,必须手动调用$apply方法,才会触发脏数据检查流程的运行

    setTimeout(() => {
        this.title = 'this is title';
        this.$apply();
    }, 3000);
    

  3. wepy脏数据检查流程

  4. over

其他优化细节
  1. wx.request 接受参数修改
  2. 优化事件参数传递
  3. 改变数据绑定方式
  4. 组件地带模板和模块

实战开发

文件结构
  1. src/components/config 文件夹结构

    api.js 存放借口给
    config.js存放全局、服务器地址等常量
    utils.js 存放 toast、网络请求等方法
    
  2. src/pages/diary文件夹结构

暂无


  1. 微信开发者工具自定义编译

    0.查看Network列表(在Console旁边),该列表为当前页面所有接口,查看info发现,Response返回值
    1.打开微信开发者工具
    2.在上方编译处选择 添加编译模式
    3.自定义编译条件
    模式名称:便于记录 日记详情页
    启动页面:打开相应页面,会自动生成 pages/diary/DiaryInfo
    启动参数 catDiaryId=1513
    进入场景 
    
  2. 页面导航

  3. over

开发流程
  1. 熟悉目录结构
  2. 熟悉服务端接口流程
  3. 先开发网络请求
  4. 构造数据
  5. 拆解sketch原型,开始template页面开发
布局

参考文献:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

  1. 盒子模型
  2. Flex布局

wepy API
  1. wepy.app Class

    $wxapp:Object: this.$wxapp等同于getApp()。
    
    $pages:List: 所有页面列表
    
    $interceptors:List:所有拦截器列表
    
    use(middleWare:String|Function):使用中间件。
    
     
    
  2. wepy.component Class

    属性
    
    $name:String: 组件名称。
    $isComponent:Boolean:是否是组件,如果是页面,此值为false。
    $wxpage:Object: 小程序原生page。
    $parent:Page|App:组件的父组件,如果当前是组件是Page对象,那么$parent的值为App对象。
    $root:Page: 组件所在的Page对象,如果当前组件是Page对象,那么$root的值就是自己本身。
    $coms:List:组件的子组件列表。
    $mixins:Array[Mixin]:组件所注入的Mixin对象。
    data:Object: 组件需要绑定的数据。
    methods:List:组件需要响应的事件列表。
    props:List:组件允许传递的props列表。
    events:List:组件通信时所需要的事件表现。
    
    方法
    getCurrentPages():相当于全局方法getCurrentPages()。
    $getComponent(com:String):通过组件名称路径查找组件对象。
    $invoke(com:String|Component):调用另一组件的方法。
     // coma.js
      this.$invoke('./ComB', 'func1', 'p1', 'p2');
      this.$invoke('./ComB', 'func2', 'p1', 'p2');
    
      // comb.js
      export class ComB extends wepy.component {
          methods = {
              func1 (p1, p2, evt) {}
          },
          func2 (p1, p2) {}
      }
      
      $broadcast(eventName:String, [args]):组件发起一个广播事件。
      // page1.js
      components = { ComA };
      this.$broadcast('broadcast-event', 'p1', 'p2');
    
      // coma.js
      events = {
          'broadcast-event': (p1, p2, event) {}
      }
      
      $emit(eventName:String, [args]):组件发起一个冒泡事件。
       // coma.js
      this.$emit('emit-event', 'p1', 'p2');
    
      // page1.js
      components = { ComA };
      events = {
          'emit-event': (p1, p2, event) => {}
      }
    
    $apply([func:Function]):组件发起脏检查。
    正常流程下,改变数据后,组件会在流程结束时自动触发脏检查。 在异步或者回调流程中改变数据时,需要手动调用$apply方法。
    
    $nextTick([func:Function]):组件数据绑定完成后的回调事件,v1.6.1以上可用。
    
  3. wepy.page Class

    页面类,继承自wepy.component,拥有页面所有的属性与方法。
    $preload(key:String|Object, [value:Object]):给页面加载preload数据
    $redirect(url:String|Object, [params:Object]):wx.redirectTo的封装方法。
    this.$redirect('./page2', {a: 1, b: 2});
      this.$redirect({
          url: './pages?a=1&b=2'
      });
    

  4. wepy.event Class

  5. wepy.mixin Class

    Mixin基类,用于复用不同组件中的相同功能。
    // mymixn.js
    export class MyMixin extends wepy.mixin {
        // my logic here
    }
    
    // mycom.js
    import MyMixin from './mymixin';
    export class MyCom extends wepy.component {
        mixins = [MyMixin];
    }
    
  6. over

  7. 你可能感兴趣的:(小程序开发之wepy)