微信小程序wepy框架笔记小结


Posted in Javascript onAugust 08, 2018

该框架是腾讯内部基于小程序的开发框架,设计思路基本参考VUE,开发模式和编码风 格上80%以上接近VUE

优势

组件化开发

小程序虽然有标签可以实现组件复用,但仅限于模板片段层面的复用,业务代码与交互事件 仍需在页面处理。无法实现组件化的松耦合与复用的效果。

wepy组件示例

// index.wpy

 <template>

  <view>

   <panel>

    <h1 slot="title"></h1>

   </panel>

   <counter1 :num="myNum"></counter1>

   <counter2 :num.sync="syncNum"></counter2>

   <list :item="items"></list>

  </view>

 </template>

 <script>
 import wepy from 'wepy';

 import List from '../components/list';

 import Panel from '../components/panel';

 import Counter from '../components/counter';

 export default class Index extends wepy.page {

  config = {

   "navigationBarTitleText": "test"

  };

  components = {

   panel: Panel,

   counter1: Counter,

   counter2: Counter,

   list: List

  };

  data = {

   myNum: 50,

   syncNum: 100,

   items: [1, 2, 3, 4]

  }

 }
 </script>

支持加载外部NPM包

小程序较大的缺陷是不支持NPM包,导致无法直接使用大量优秀的开源内容,wepy在编译过程当中,会递归 遍历代码中的require然后将对应依赖文件从node_modules当中拷贝出来,并且修改require为相对路径, 从而实现对外部NPM包的支持

单文件模式,使得目录结构更加清晰

小程序官方目录结构要求app必须有三个文件app.json,app.js,app.wxss,页面有4个文件 index.json,index.js,index.wxml,index.wxss。而且文 件必须同名。 所以使用wepy开发前后开发目录对比如下:

官方DEMO:

project

├── pages

| ├── index

| | ├── index.json index 页面配置

| | ├── index.js index 页面逻辑

| | ├── index.wxml index 页面结构

| | └── index.wxss index 页面样式表

| └── log

|  ├── log.json log 页面配置

|  ├── log.wxml log 页面逻辑

|  ├── log.js  log 页面结构

|  └── log.wxss log 页面样式表

├── app.js    小程序逻辑

├── app.json   小程序公共设置

└── app.wxss   小程序公共样式表

使用wepy框架后目录结构:

project

└── src

 ├── pages

 | ├── index.wpy index 页面配置、结构、样式、逻辑

 | └── log.wpy  log 页面配置、结构、样式、逻辑

 └──app.wpy   小程序配置项(全局样式配置、声明钩子等)

如何开发

快速起步

安装

npm install wepy-cli -g

小程序框架wepy命令行工具

创建项目

wepy new myproject

切换至项目目录

cd myproject

实时编译

wepy build ?watch

目录结构 ├── dist 微信开发者工具指定的目录

├── node_modules

├── src     代码编写的目录

| ├── components   组件文件夹(非完整页面)

| | ├── com_a.wpy  可复用组件 a

| | └── com_b.wpy  可复用组件 b

| ├── pages    页面文件夹(完整页面)

| | ├── index.wpy  页面 index

| | └── page.wpy  页面 page

| └── app.wpy   小程序配置项(全局样式配置、声明钩子等)

└── package.json   package 配置

wepy和VUE主要区别

1.二者均支持props、data、computed、components、methods、watch(wepy中是watcher), 但wepy中的methods仅可用于页面事件绑定,其他自定义方法都要放在外层,而VUE中所有方法均放在 methods下

2.wepy中props传递需要加上.sync修饰符(类似VUE1.x)才能实现props动态更新,并且父组件再 变更传递给子组件props后要执行this.$apply()方法才能更新

3.wepy支持数据双向绑定,子组件在定义props时加上twoway:true属性值即可实现子组件修改父组 件数据

4.VUE2.x推荐使用eventBus方式进行组件通信,而在wepy中是通过broadcast,broadcast,emit,$invoke 三种方法实现通信

· 首先事件监听需要写在events属性下:

``` bash

import wepy from 'wepy';

export default class Com extends wepy.component {

 components = {};

 data = {};

 methods = {};

 events = {

  'some-event': (p1, p2, p3, $event) => {

    console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);

  }

 };

 // Other properties

}

```
· $broadcast:父组件触发所有子组件事件
· $emit:子组件触发父组件事件
· $invoke:子组件触发子组件事件

 5.VUE的生命周期包括created、mounted等,wepy仅支持小程序的生命周期:onLoad、onReady等

6.wepy不支持过滤器、keep-alive、ref、transition、全局插件、路由管理、服务端渲染等VUE特性技术

进阶介绍

.wpy文件说明

一个.wpy文件可分为三大部分,各自对应于一个标签:

脚本部分,即标签中的内容,又可分为两个部分:
    逻辑部分,除了config对象之外的部分,对应于原生的.js文件;
    配置部分,即config对象,对应于原生的.json文件。

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

样式部分,即样式部分,对应于原生的.wxss文件。

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

标签 lang默认值 lang支持值
style css css、less、sass、stylus
template wxml wxml、xml、pug(原jade)
script babel babel、TypeScript

普通组件引用

当页面需要引入组件或组件需要引入子组件时,必须在.wpy文件的

<template>
 <!-- 以`<script>`脚本部分中所声明的组件ID为名命名自定义标签,从而在`<template>`模板部分中插入组件 -->
 <child></child>
</template>

<script>
 import wepy from 'wepy';
 //引入组件文件
 import Child from '../components/child';

 export default class Index extends wepy.component {
  //声明组件,分配组件id为child
  components = {
   child: Child
  };
 }
</script>

需要注意的是,WePY中的组件都是静态组件,是以组件ID作为唯一标识的,每一个ID都对应一个组件实例,当页面引入两个相同ID的组件时,这两个组件共用同一个实例与数据,当其中一个组件数据变化时,另外一个也会一起变化。
如果需要避免这个问题,则需要分配多个组件ID和实例。

组件的循环渲染

1.4.6新增

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

<template>
 <!-- 注意,使用for属性,而不是使用wx:for属性 -->
 <repeat for="{{list}}" key="index" index="index" item="item">
  <!-- 插入<script>脚本部分所声明的child组件,同时传入item -->
  <child :item="item"></child>
 </repeat>
</template>

computed 计算属性

computed计算属性,是一个有返回值的函数,可直接被当作绑定数据来使用。因此类似于data属性,代码中可通过this.计算属性名来引用,模板中也可通过{{ 计算属性名 }}来绑定数据。

需要注意的是,只要是组件中有任何数据发生了改变,那么所有计算属性就都会被重新计算。

data = {
  a: 1
 }

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

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)
 }

props 传值

静态传值

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

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

<child title="mytitle"></child>

// child.wpy
props = {
 title: String
};

onLoad () {
 console.log(this.title); // mytitle
}

动态传值

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

注意:下文示例中的twoWay为true时,表示子组件向父组件单向动态传值,而twoWay为false(默认值,可不写)时,则表示子组件不向父组件传值。这是与Vue不一致的地方,而这里之所以仍然使用twoWay,只是为了尽可能保持与Vue在标识符命名上的一致性。

在父组件template模板部分所插入的子组件标签中,使用:prop属性(等价于Vue中的v-bind:prop属性)来进行动态传值。

// 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: Number,
  default: 50,
  twoWay: true
 }
};

onLoad () {
 console.log(this.title); // p-title
 console.log(this.syncTitle); // p-title
 console.log(this.twoWayTitle); // 50

 this.title = 'c-title';
 console.log(this.$parent.parentTitle); // p-title.
 this.twoWayTitle = 60;
 this.$apply();
 console.log(this.$parent.parentTitle); // 60. --- twoWay为true时,子组件props中的属性值改变时,会同时改变父组件对应的值
 this.$parent.parentTitle = 'p-title-changed';
 this.$parent.$apply();
 console.log(this.title); // 'p-title';
 console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修饰符的props属性值,当在父组件中改变时,会同时改变子组件对应的值。
}

 组件通信与交互

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

- broadcastbroadcastbroadcast事件是由父组件发起,所有子组件都会收到此广播事件,除非事件被手动取消。事件广播的顺序为广度优先搜索顺序

- emitemitemit与broadcast正好相反,事件发起组件的所有祖先组件会依次接收到broadcast正好相反,事件发起组件的所有祖先组件会依次接收到emit事件。

- invokeinvokeinvoke是一个页面或组件对另一个组件中的方法的直接调用,通过传入组件路径找到相应的组件,然后再调用其方法。

比如,想在页面Page_Index中调用组件ComA的某个方法:

this.$invoke('ComA', 'someMethod', 'someArgs');

如果想在组件ComA中调用组件ComG的某个方法:

this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');

组件自定义事件处理函数

可以通过使用.user修饰符为自定义组件绑定事件,如:@customEvent.user=”myFn”

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

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

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

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

.user: 绑定用户自定义组件事件,通过$emit触发。

// 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 组件内容分发插槽

WePY中的slot插槽作为内容分发标签的空间占位标签,便于在父组件中通过对相当于扩展板卡的内容分发标签的“插拔”,更为灵活、方便地对子组件进行内容分发。

具体使用方法是,首先在子组件template模板部分中声明slot标签作为内容插槽,同时必须在其name属性中指定插槽名称,还可设置默认的标签内容;然后在引入了该带有插槽的子组件的父组件template模板部分中声明用于“插拔”的内容分发标签。
注意,这些父组件中的内容分发标签必须具有slot属性,并且其值为子组件中对应的插槽名称,这样父组件内容分发标签中的内容会覆盖掉子组件对应插槽中的默认内容。

在Panel组件中有以下模板:

<view class="panel">
 <slot name="title">默认标题</slot>
 <slot name="content">默认内容</slot>
</view>

在父组件中使用Pannel子组件时,可以这样使用:

<panel>
 <view slot="title">新的标题</view>
 <view slot="content">
  <text>新的内容</text>
 </view>
</panel>

混合

默认式混合

对于组件data数据,components组件,events事件以及其它自定义方法采用默认式混合,即如果组件未声明该数据,组件,事件,自定义方法等,那么将混合对象中的选项将注入组件这中。对于组件已声明的选项将不受影响。

// 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); // foo defined by testMix.
 }
}

兼容式混合

对于组件methods响应事件,以及小程序页面事件将采用兼容式混合,即先响应组件本身响应事件,然后再响应混合对象中响应事件。

// mixins/test.js
import wepy from 'wepy';

export default class TestMixin extends wepy.mixin {
 methods = {
  tap () {
   console.log('mix tap');
  }
 };
 onShow() {
  console.log('mix 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
// mix onshow
// ----- when tap
// index tap
// mix tap

拦截器

可以使用全域拦截器配置API的config、fail、success、complete方法,参考示例:

import wepy from 'wepy';

export default class extends wepy.app {

 constructor () {
  this.intercept('request', {
   config (p) {
    p.timestamp = +new Date();
    return p;
   },
   success (p) {
    console.log('request success');
    return p;
   },
   fail (p) {
    console.log('request error');
    return p;
   }
  });
 }
}

WePY数据绑定方式

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

this.title = 'this is title';

在函数运行周期之外的函数里去修改数据需要手动调用$apply方法

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

优化事件参数传递

// 官方
<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 bindtap="tapName({{index}}, 'wepy', 'otherparams')"> Click me! </view>

methods: {
 tapName (id, title, other, event) {
  console.log(id, title, other)// output: 1, wepy, otherparams
 }
}

改变数据绑定方式

保留setData方法,但不建议使用setData执行绑定,修复传入undefined的bug,并且修改入参支持: this.setData(target, value) this.setData(object)

// 官方
<view> {{ message }} </view>

onLoad: function () {
 this.setData({message: 'hello world'});
}


// WePY
<view> {{ message }} </view>

onLoad () {
 this.message = 'hello world';
}

重要提醒

  1. 使用微信开发者工具?>添加项目,项目目录请选择dist目录。
  2. 微信开发者工具?>项目?>关闭ES6转ES5。 重要:漏掉此项会运行报错。
  3. 微信开发者工具?>项目?>关闭上传代码时样式自动补全。 重要:某些情况下漏掉此项也会运行报错。
  4. 微信开发者工具?>项目?>关闭代码压缩上传。 重要:开启后,会导致真机computed, props.sync 等等属性失效。(注:压缩功能可使用WePY提供的build指令代替,详见后文相关介绍以及Demo项目根目录中的wepy.config.js和package.json文件。)
  5. 本地项目根目录运行wepy build ?watch,开启实时编译。(注:如果同时在微信开发者工具?>设置?>编辑器中勾选了文件保存时自动编译小程序,将可以实时预览,非常方便。)

注意

WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使弱类型的语言JavaScript变强势
Jun 22 Javascript
mailto的使用技巧分享
Dec 21 Javascript
jquery实现根据浏览器窗口大小自动缩放图片的方法
Jul 17 Javascript
Javascript验证Visa和MasterCard信用卡号的方法
Jul 27 Javascript
基于jquery实现轮播焦点图插件
Mar 31 Javascript
JS简单实现仿百度控制台输出信息效果
Sep 04 Javascript
基于JavaScript实现的顺序查找算法示例
Apr 14 Javascript
vue 自定义组件 v-model双向绑定、 父子组件同步通信的多种写法
Nov 27 Javascript
vue 过滤器filter实例详解
Mar 14 Javascript
解决Mac安装thrift因bison报错的问题
May 17 Javascript
对VUE中的对象添加属性
Sep 18 Javascript
详解Js里的for…in和for…of的用法
Mar 28 Javascript
angularJs中$http获取后台数据的实例讲解
Aug 08 #Javascript
JavaScript常见JSON操作实例分析
Aug 08 #Javascript
vue.js与后台数据交互的实例讲解
Aug 08 #Javascript
JS实现自定义弹窗功能
Aug 08 #Javascript
vue.js提交按钮时进行简单的if判断表达式详解
Aug 08 #Javascript
解决jquery的ajax调取后端数据成功却渲染失败的问题
Aug 08 #jQuery
JS+HTML5实现获取手机验证码倒计时按钮
Aug 08 #Javascript
You might like
php download.php实现代码 跳转到下载文件(response.redirect)
2009/08/26 PHP
php中ltrim()、rtrim()与trim()删除字符空格实例
2014/11/25 PHP
php实现的任意进制互转类分享
2015/07/07 PHP
Jquery弹出窗口插件 LeanModal的使用方法
2012/03/10 Javascript
JS刷新框架外页面七种实现代码
2013/02/18 Javascript
js Calender控件使用详解
2015/01/05 Javascript
jQuery中position()方法用法实例
2015/01/16 Javascript
javascript实现随时变化着的背景颜色
2015/04/02 Javascript
JavaScript中的this关键字使用详解
2015/08/14 Javascript
Jquery和JS获取ul中li标签的实现方法
2016/06/02 Javascript
javaScript给元素添加多个class的简单实现
2016/07/20 Javascript
Bootstrap分页插件之Bootstrap Paginator实例详解
2016/10/15 Javascript
layui导航栏实现代码
2017/05/19 Javascript
使用Bootstrap和Vue实现用户信息的编辑删除功能
2017/10/25 Javascript
react-router4 配合webpack require.ensure 实现异步加载的示例
2018/01/18 Javascript
vue watch深度监听对象实现数据联动效果
2018/08/16 Javascript
JS实现的tab页切换效果完整示例
2018/12/18 Javascript
小程序云开发如何实现图片上传及发表文字
2019/05/17 Javascript
30分钟用Node.js构建一个API服务器的步骤详解
2019/05/24 Javascript
JavaScript实现左右滚动电影画布
2020/02/06 Javascript
Vue项目移动端滚动穿透问题的实现
2020/05/19 Javascript
wxPython事件驱动实例详解
2014/09/28 Python
python实现的简单RPG游戏流程实例
2015/06/28 Python
关于python的bottle框架跨域请求报错问题的处理方法
2017/03/19 Python
python 实现敏感词过滤的方法
2019/01/21 Python
Pytest框架之fixture的详细使用教程
2020/04/07 Python
Python txt文件如何转换成字典
2020/11/03 Python
python实现图片,视频人脸识别(dlib版)
2020/11/18 Python
用Python 执行cmd命令
2020/12/18 Python
Omio法国:全欧洲低价大巴、火车和航班搜索和比价
2017/11/13 全球购物
英国蛋糕装饰用品一站式商店:Craft Company
2019/03/18 全球购物
Booking.com德国:预订最好的酒店和住宿
2020/02/16 全球购物
个人自我鉴定怎么写
2013/10/28 职场文书
开会通知
2015/04/20 职场文书
python 实现体质指数BMI计算
2021/05/26 Python
Python字符串常规操作小结
2022/04/03 Python