wepy框架的那些坑

原创 王振鹏 随笔 wepy 209阅读 2018-09-05 17:56:39 举报

组件库:
http://auicss.com/doc/v/2/doc_id/23 AUI Mobile 组件库
https://youzan.github.io/vant/#/zh-CN/intro 有赞UI组件库 小程序 在使用 有赞UI组件库的时候,不要使用npm 安装 直接 git克隆 或者 githud地址 克隆下来 将dist文件拷贝下来 放在你的项目目录下 然后配置
config = {
'usingComponents': {
'van-button': '../../assets/styles/button/index' -->注意:路径问题
}
}
https://github.com/youzan/vant-weapp 有赞UI组件库githud地址
https://meili.github.io/min/docs/minui/index.html min 组件库
redux小程序:
https://www.npmjs.com/package/wepy-redux 小程序redux
Dom
https://github.com/c-yyy/wepy-Evolution
https://www.w3cschool.cn/weixinapp/weixinapp-app.html 小程序开发文档
------------------------------------------------------API----------------------------------------------------------

属性
类型
描述
触发时机
onLaunch
Function
生命周期函数--监听小程序初始化
当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onShow
Function
生命周期函数--监听小程序显示
当小程序启动,或从后台进入前台显示,会触发 onShow
onHide
Function
生命周期函数--监听小程序隐藏
当小程序从前台进入后台,会触发 onHide
onError
Function
错误监听函数
当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
onPageNotFound
Function
页面不存在监听函数
当小程序出现要打开的页面不存在的情况,会带上页面信息回调该函数
其他
Any

开发者可以添加任意的函数或数据到 Object 参数中,用 this 可以访问

前台、后台定义:当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。需要注意的是:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。

关闭小程序(基础库版本1.1.0开始支持):当用户从扫一扫、转发等入口(场景值为1007, 1008, 1011, 1025)进入小程序,且没有置顶小程序的情况下退出,小程序会被销毁。小程序运行机制在基础库版本 1.4.0 有所改变:上一条关闭逻辑在新版本已不适用, 详情

我这里要重点介绍下 onShow函数

当我们遇到用户登录后,然后在页面显示数据,那该怎么办?onload(){} 函数只执行一次

这时候就需要onShow 实现用户登录后,显示数据了

举个例子:

那 签到来说 没登录之前 你是不是 不应该 有数据啊 登录之后 才会显示 你签到 多少天

此时 就是 onShow 的用场了

tabBar 对应的页面里 写上 onShow
注意:
该函数 与 data = {} 等。。是同级的

这是原生的api wx-->wepy就可以了
如果说你想看wepy的api 可以console.log(wepy);不过没有用法 ,此时你可以参照微信小程序的api
redirectTo:关闭当前页,跳转到指定页;
navigateTo:保留当前页,跳转到指定页;注意:非tabbar页面 什么是非tabbar页面 就是tanbar中引入的页面路径
switchTab:只能用于跳转到tabbar页面,并关闭其他非tabbar页面。
不传参的用法:
wepy.redirectTo({
url:'地址' --->相对路径哦 '../home/home'
})

传参例子:
//list wepy.page
wepy.navigateTo({
url: '../shop/shop?id=2'
})
//shop wepy.page
list-->shop 如果你想获得地址栏的参数,那么就在shop的页面里用onLoad(options)获得参数
例子:

onLoad(options) {
console.log(options) //{id:"2"} 如果这是个商户的id值,那么你就可以利用这个id值,发起请求然后得到这个商户下的信息
}

注意:目前页面路径最多只能十层。
下拉刷新:
开启下拉刷新:enablePullDownRefresh: true 配合onPullDownRefresh(监听该页面用户下拉刷新事件)
有两种方式开启下拉刷新 全局下拉加载 局部下拉加载
1.配置在app.wpy里 window:{enablePullDownRefresh: true} 这种写法是开启了全局下来加载
2.页面的config = {enablePullDownRefresh: true} 这种写法只是当前页面开启了下拉加载
例子:
config = {
enablePullDownRefresh: true
}
onPullDownRefresh() {
//下来加载事件刷新 当数据加载完成时,调用 wepy.stopPullDownRefresh()停止动画
}
注意:
1.onPullDownRefresh(){}的写法 在wepy中与data = {} config = {} methods = {} 是并列的 不要写在其内部中
2.onPullDownRefresh写在app.wpy无效 只能写在页面中
例子:
config = {
enablePullDownRefresh: true
}
components = {
}
data = {
}
events = {
}
methods = {
}
onLoad(options) {
console.log(options)
}
onPullDownRefresh() { -->并列
console.log('2')
wepy.stopPullDownRefresh()
}
上拉触底事件
onReachBottomDistance:numder 单位px
在需要的上拉加载的页面调用onReachBottom() {} 即可实现
具体写法同上
注意:
只有当页面内容高度大于当前的整个也面高度时,才会触发该事件,也就是说只有出现竖向滚动条时,才出发该事件
wx:for 可以循环嵌套
例子:
data = {
page: {
ask: '我的',
answer: ['aa','cc']
}
}
<repeat wx:for="{{page}}" key="index" item="item">
<view>{{item.ask}}</view>
<repeat wx:for="{{item.answer}}" key="index" item="item">
<view>{{item}}</view>
</repeat>
</repeat>

------------------------------------------------------------wepy-----------------------------------------------------
创建小程序应用时
1.在全局按装 npm install wepy-cli -g
2.初始化项目 wepy init standard myproject
3.在初始化时候注意以下几点:
(1).程序名字不能有大写字母
(2).Appid是你小程序创建时候的ID值
(3).项目事项(默认即可)
(4).作者(随便)
(5).Use ESLint to lint your code?(默认即可)
(6).Use Redux in your project?(是否用redux-->以项目而定)
(7). Use web transform feature in your project? (Y/n)(在项目中使用Web转换功能?(Y/ N)-->默认即可)
这样我们就创建好了一个小程序的例子

  1. cd <项目名>
    5.安装依赖即可 npm install
    --------------------------------------------------------踩坑记--------------------------------------------------
    在这里我提醒大家一定要看对路径和函数的写法
    注意事项:
    1.在文件的结尾处 敲回车 必须有换行符,且没有空格 否则报错 error Newline required at end of file but not found eol-last
    2.字符串必须是单引号
    3.注意空格
    3.improt 结尾 没有分号 在程序里也不要加分号
    4.wx:if="{{}}" 加双引号
    5.css样式图片和标签中的img src='' 不可以静态加载,只能网络加载
    6.小程序劲量不用原生的动画,采用css3 或者用组件库
    7.在实例化app.wepy的时候
    export default class extends wepy.app {
    config = {
    pages: [
    'pages/home/home' 报错-->未找到 app.json 中的定义的 pages "pages/home/home" 对应的 JS 文件
    解决方案:
    1.看路径是否正确!!!!
    2.清空dist文件 重新编译
    ]
    }
    }
    8.VM1944:1 thirdScriptError sdk uncaught third Error module "npm/lodash.isarray/index.js" is not defined Error: module "npm/lodash.isarray/index.js" is not defined
    解决办法:
    1.npm init 在选择是否用redux 选择否
    2.用命令行npm install util –no-save ,安装完后wepy build –no-cache, 最后npm run dev编译就行了。
    3.app.wepy引用了 redux 造成的问题 删除即可
    import { setStore } from 'wepy-redux'
    import configStore from './store'
    const store = configStore()
    setStore(store)
    9.报错:pages/home/home.js 出现脚本错误或者未正确调用 Page()
    解决办法:
    1.app.wepy引用了 redux 造成的问题 删除即可
    10.统一标题在app.wpy里配置
    config = {
    path: [
    '页面路径' //和页面中的 wpy.page 的命名没有关系
    ],
    window:{
    navigationBarBackgroundColor: '#1a9dff',
    navigationBarTitleText: '建宇订水',-->所有页面 wpy.Page的顶部title名称都是一样的,如果想给重新的title的话,在对应的wpy.page页面设置 config = {navigationBarTitleText: '建宇订水2'}-->那么对应的wpy.page的title也就发生变化
    navigationBarTextStyle: '#ffffff'
    }
    }
    10.当你的底部的图片加载不出来时,可以尝试关闭微信开发者工具,在打开就好了
    11.当你页面报错为 没有引用js文件;
    解决方案:
    查看dist文件下对应的js文件(此js文件是你报错没有引用的js文件),仔细查看js的文件名,是否与你的src目录下的wpy的文件命名一样。如果不一样
    请执行 npm clear命令 就是你的package.json命令,具体看你的 package.json的文件命令,如果没有该命令,那就删除dist文件,然后重新执行命令
    npm build("build": "cross-env NODE_ENV=production wepy build --no-cache")
    -------------------------------------------------------------wepy心得-------------------------------------------------------------
    app.wpy 引用公共样式在style里写如路径
    小程序被分为三个实例:小程序实例App、页面实例Page、组件实例Component。其中Page实例继承自Component;
    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 { }
    提示:
    什么时候创建App小程序实例,有什么时候创建Page页面实例,又什么时候用组件?
    App小程序实例 这个没有什么异议 因为一个小程序,只能维一一个App小程序实例
    Page页面实例 这个根据UI给了你几个效果图 他给你几个效果图,你就创建几个Page页面实例
    Component组件实例 当复用,循环,某个特定的功能等,这时候你就需要考虑是否要创建组件
    App小程序实例
    import wepy from 'wepy';
    export default class MyAPP extends wepy.app {
    customData = {};
    customFunction () { }
    onLaunch () {}
    onShow () {}
    config = {} // 对应 app.json 文件
    globalData = {}
    }
    Page页面实例和Component组件实例
    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 = {}; // 声明组件之间的事件处理函数
    }
    注意methods:
    // 正确示例
    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.';
}
}
普通组件引用
注意:
WePY中的组件都是静态组件,是以组件ID作为唯一标识的,每一个ID都对应一个组件实例,当页面引入两个相同ID的组件时,这两个组件共用同一个实例与数据,当其中一个组件数据变化时,另外一个也会一起变化。
避免方法:同一个组件,用不同的ID
components = {
page1 = page,
page2 = page,
}
组件的循环渲染
注意:
循环渲染WePY组件时,必须使用辅助组标签<repeat>
例如:
<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.component {
components = {
// 声明页面中要使用到的Child组件的ID为child
child: Child
}
data = {
list: [{id: 1, title: 'title1'}, {id: 2, title: 'title2'}]
}
}
</script>
computed 计算属性
如何使用:
计算属性aPlus,在脚本中可通过this.aPlus来引用,在模板中可通过{{ aPlus }}来插值
data = {
a : 1
}
computed = {
aPlus () {
return this.a + 1
}
}
watcher 监听器
通过监听器watcher能够监听到任何属性的更新。监听器在watch对象中声明,类型为函数,函数名与需要被监听的data对象中的属性同名,每当被监听的属性改变一次,监听器函数就会被自动调用执行一次。
例子:
data = {
num: 1
}
注意: 监听的函数名必须与data中的函数名一致 切记!!!
// 其参数中的newValue为属性改变后的新值,oldValue为改变前的旧值
watcher = {
num(newValue,oldValue){
console.log('num value:$(oldValue) -> ${newValue}')
}
}
onload() {
setInterval(() => {
this.num++;
this.$apply;
},1000)
}
props 传值
父组件往子组件传值用法:
静态传值:
父组件:
<template>
<sign title="aa"></sign>
</template>
子组件:
<template>
<view>{{title}}</view> // aa
</template>
props = {
title: String
}
动态传值:
父组件:
<template>
//isNas 此时不用加{{shop}} shop名与子组件一样 shop可以是任意数据类型,具体看data中的isNas的数据类型
<sign :shop.snyc='isNas'></sign>-->父组件引用子组件
</template>
data = {
isNas: false
}
子组件:
<template>
<view>{{shop}}</view> 注意 此时shop 为false 不显示
</template>
props = {
shop: {
type: String
}
}
.snyc 通过设置snyc的修饰符 父组件可以往子组件传递值;
twoWay: true 通过设置子组件中的props属性 可以实现子组件往父组件传递值(默认为false), 如果二者都设置 就可以实现数据双向绑定;

父组件:
<template>
<sign :shop.snyc='isNas' twoWayTitle="num"></sign>
</template>

写在子组件props 里
props = {
// 静态传值
title: String,

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

twoWayTitle: {
    type: String,
    default: 'nothing',
    twoWay: true 
 }

};
注意:
props = {
syncTitle: {
type: String //如果你设置了 type 的数据类型 就必须符合该数据类型,也就是说 父组件往子组件传递数值类型也必须符合 (动态传值)
如果是静态传值只能是String 类型
}
}
组件通信与交互
$broadcast、$emit、$invoke 三种方法
首先 $broadcast、$emit 这两个方法
$broadcast、$emit 要配合events对象
拿broadcast举例子:
父组件:
this.$broadcast('some-event',1,2,3,4)
子组件:
events = {
'some-event': (num0, num1, num2, num3, $event:Event) => {
console.log(num0, num1, num2, num3,$event:Event) //1 2 3 4 $event:Event 对象 可以看出 some-event,broadcast:具体console.log(,$event:Event)
}
}
注意:
用于监听组件之间的通信与交互事件的事件处理函数需要写在组件和页面的events对象中
$broadcast-->是由父组件发起的 类似于广播 会传递给他的子组件,然后他的子组件在传递给下个子组件的组件

// events对象中所声明的函数为用于监听组件之间的通信与交互事件的事件处理函数
$emit

$invoke
$invoke是一个页面或组件对另一个组件中的方法的直接调用,通过传入组件路径找到相应的组件,然后再调用其方法。
如果想在组件ComA中调用组件ComG的某个方法:

this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');
someMethod -->方法
someArgs --> 方法用到的参数
如果通过当前组件进行$invoke触发事件,如果父组件已经在components里面引入了子组件就可以直接通过invoke来单独向子组件发送事件;

如果是子组件之间的事件交互,第一个参数就需要对应组件的路径。调用方式如下:

父组件向子组件发送事件:

this.$invoke('子组件,必须要单引号括起来-->components中的组件ID名,不是import', '子组件方法名称', param1,param2,param3.......);

子组件间发送事件:

this.$invoke('子组件的相对路径', '子组件方法名称', param1,param2,param3.......);

注意:

官方说子组件间发送事件需要引用路径,但是实际测试中发现,建立进行$invoke触发事件的前提是必须用components引用其组件,否则报错!!!!

组件自定义事件处理函数
例如: @customEvent.user="myFn"
@修饰符
customEvent 表示事件名称
.user表示事件后缀
有三种事件后缀:
default: 绑定小程序冒泡型事件,如bindtap,.default后缀可省略不写;
.stop: 绑定小程序捕获型事件,如catchtap;
.user: 绑定用户自定义组件事件,通过$emit触发。注意,如果用了自定义事件,则events中对应的监听函数不会再执行。
slot 组件内容分发插槽
首先子组件里写slot标签作为内容插槽 name指定名称插槽名称
父组件里在子组件标签里写标签里写slot="name名"
注意:
父组件的标签里必须有slot属性,slot指定子组件里的slot的name的名字
另外如果父组件组件里没有数值,那么子组件里的slot也不会渲染出来
例如:
sign子组件:
<slot name="title">默认标题</solt> //新标题 如果父组件没有数值,那么子组件里也不会显示出来
父组件:
<sign>
<view slot="title">新标题</view>
</sign>
第三方组件 == 不描述
Mixin 混合 混合提高附件的复用性
默认式混合(默认)

对于组件data数据,components组件,events事件以及其它自定义方法采用默认式混合,即如果组件未声明该数据,组件,事件,自定义方法等,

那么将混合对象中的选项将注入组件之中。对于组件已声明的选项将不受影响。

复用的组件:
// mixins/test.js
import wepy from 'wepy';
export default class TestMixin extends wepy.mixin { //注意: 组件的后缀名必须是 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
}
}
兼容式混合-->响应组件本身响应事件在相应组件的事件
对于组件methods响应事件,以及小程序页面事件将采用兼容式混合,即先响应组件本身响应事件,然后再响应混合对象中响应事件。
// 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
注意:
1.复用的组件是js文件不是wpy
2.写入 import wepy from 'wepy' export default class TestMixin extends wepy.mixin {}
3.引用复用的组件名 import TestMixin from '路径'
interceptor 拦截器(可以使用WePY提供的全局拦截器对原生API的请求进行拦截。) 没看懂
具体方法是配置API的config、fail、success、complete回调函数。参考示例:
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数据绑定方式
WePY使用脏数据检查对setData进行封装,在函数运行周期结束时执行脏数据检查,一来可以不用关心页面多次setData是否会有性能上的问题,二来可以更加简洁去修改数据实现绑定,不用重复去写setData方法。
this.num = 'aa'
注意:
在异步函数绑定数据时,需要触发 $apply();数据才能更新;
例如:
setTimeout(() => { this.title = 'this is title'; this.$apply(); }, 3000);
WePY脏数据检查流程

评论 ( 1 )
最新评论