微信小程序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 相关文章推荐
用js实现的检测浏览器和系统的函数
Apr 09 Javascript
jQuery 核心函数以及jQuery对象
Mar 23 Javascript
基于jquery实现的可以编辑选择的下拉框的代码
Nov 19 Javascript
JavaScript中的作用域链和闭包
Jun 30 Javascript
使用命令对象代替switch语句的写法示例
Feb 28 Javascript
JQuery fileupload插件实现文件上传功能
Mar 18 Javascript
jQuery的 $.ajax防止重复提交的两种方法(推荐)
Oct 14 Javascript
JS实现动态修改table及合并单元格的方法示例
Feb 20 Javascript
COM组件中调用JavaScript函数详解及实例
Feb 23 Javascript
分分钟玩转Vue.js组件(二)
Mar 01 Javascript
jQuery使用unlock.js插件实现滑动解锁
Apr 04 jQuery
微信小程序-可移动菜单的实现过程详解
Jun 24 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 高手之路(一)
2006/10/09 PHP
ThinkPHP跳转页success及error模板实例教程
2014/07/17 PHP
PHP防止刷新重复提交页面的示例代码
2015/11/11 PHP
php使用glob函数遍历文件和目录详解
2016/09/23 PHP
PHP实现负载均衡session共享redis缓存操作示例
2018/08/22 PHP
PHP实现给定一列字符,生成指定长度的所有可能组合示例
2019/06/22 PHP
thinkPHP5框架接口写法简单示例
2019/08/05 PHP
Jquery中LigerUi的弹出编辑框(实现方法)
2013/07/09 Javascript
Jquery easyui 下loaing效果示例代码
2013/08/12 Javascript
用html5 js实现点击一个按钮达到浏览器全屏效果
2014/05/28 Javascript
jquery 取子节点及当前节点属性值的方法
2014/08/24 Javascript
jQuery对象的selector属性用法实例
2014/12/27 Javascript
jQuery过滤特殊字符及JS字符串转为数字
2016/05/26 Javascript
angular仿支付宝密码框输入效果
2017/03/25 Javascript
详谈js模块化规范
2017/07/07 Javascript
JS计算两个时间相差分钟数的方法示例
2018/01/10 Javascript
vue.js与后台数据交互的实例讲解
2018/08/08 Javascript
从零开始实现Vue简单的Toast插件
2018/12/03 Javascript
Python切换pip安装源的方法详解
2016/11/18 Python
Win7下Python与Tensorflow-CPU版开发环境的安装与配置过程
2018/01/04 Python
解决python3爬虫无法显示中文的问题
2018/04/12 Python
python虚拟环境迁移方法
2019/01/03 Python
Python如何获得百度统计API的数据并发送邮件示例代码
2019/01/27 Python
python定时检测无响应进程并重启的实例代码
2019/04/22 Python
浅谈pytorch中的BN层的注意事项
2020/06/23 Python
Python如何实现线程间通信
2020/07/30 Python
Python 使用xlwt模块将多行多列数据循环写入excel文档的操作
2020/11/10 Python
利用html5 canvas动态画饼状图的示例代码
2018/04/02 HTML / CSS
科颜氏加拿大官方网站: Kiehl’s加拿大
2016/08/16 全球购物
俄罗斯领先的移动和数字设备在线商店:Svyaznoy.ru
2020/12/21 全球购物
几个Shell Script面试题
2014/04/18 面试题
酒店个人培训自我鉴定
2013/12/11 职场文书
紧急迫降观后感
2015/06/15 职场文书
小学生运动会广播
2015/08/19 职场文书
导游词之宿迁乾隆行宫
2019/10/15 职场文书
python基于OpenCV模板匹配识别图片中的数字
2021/03/31 Python