#页面样式
(1)组件只能继承全局样式中的color和font,page可以继承全局中的所有样式
(2)line-height能消除文字上下的空白间隙,组件中最好不要留不必要的间隙
(3)组件宽度自适应:组件的宽度需要根据子元素自适应,所以不能给父元素定宽,通过设置:
.container{display: inline-flex;}
(4)让组件文字多时能换行,较少时能居中,可以给文字设置最大宽度
.text{ font-size: 36rpx; max-width: 550rpx; color: #707070;}(5)移动端在需要点击的的地方要尽可能增大元素的可触碰区域,如增加padding
#获取用户信息
(1)open-data:微信提供的开发能力,不需要用户授权就能显示用户信息,但是只能显示用户的信息,但不能获取用户的信息
(2)bindgetuserinfo与wx.getUserInfo
bindgetuserinfo是button的一个属性,通过绑定事件来获取用户信息,注意:每次都需要用户主动点击才会触发事件获取用户信息,会触发弹窗授权
wx.getUserInfo是微信提供的API,只要用户已授权登录,就能直接调用该API获取到用户信息,不能触发弹窗授权
结论:授权登录应该是用户的主观动作,所以微信取消了wx.getUserInfo的弹窗授权功能,但用户授权登录后,我们每次刷新页面时需要获取验证用户信息,不能让用户每次都去点击,就可以通过wx.getUserInfo来获取用户信息,当然也可以在首次登陆时就将用户信息存储到localStorage中
#自定义组件
(1)组件中的properties中的属性是可开发出来的数据,供组件外部访问,用来向组件内部传递数据;组件data中定义的属性供组件内部使用,外部不可以访问
#自定义组件中的自定义事件
例如:实现点赞组件like:
点赞组件会被应用到多个页面中,为了增加组件的通用性,组件内部只负责改变组件状态,即点赞就为红心并数字加一,否则为白心并数字减一;
但是现实情况,我们需要将用户点赞的情况实时地更新到服务器上去,根据点赞的状态来调用对应数据接口,而点赞的状态只有组件自己知道,这是就可以通过在组件内部激活自定义事件,将点赞状态传递给组件外部
//获取点赞状态
let behavior = this.properties.like?'like':'unlike'
//激活自定义事件
this.triggerEvent('like',{ behavior:behavior})//调用组件的页面中绑定自定义事件来获取点赞状态
<v-like bind:like="clickLike"/>//点赞
clickLike:function(event){
let behavior = event.detail.behavior
//调用接口
likeModel.updateLike(behavior, this.data.classicData.id, this.data.classicData.type) },#observer监听组件属性改变
observer能监听组件属性值的改变,但是需要注意的是不能在observer内部直接修改对应属性值否则会造成死循环
例如:
properties: {
index:{
type:String,
observer:function(newVal,oldVal,changedPath){
let val =newVal< 10 ? `0${newVal}` : newVal
this.setData({ _index:val })
}
},#组件的behavior继承和多继承的覆盖规则
(1)多个组件会有些公共部分,将公共部分抽离出来,定义到behavior中,然后组件能通过继承的方式来使用这些公共部分,提高代码的复用性:
例如:
(1)定义behavior:
//组件行为用来抽离组件共有部分,让组件通过继承来使用,不仅可以定义属性,data和method,甚至生命周期函数都可以定义
let classicBeh = Behavior({
properties: {
img: { type: String },
content: { type: String } 、
},})
export { classicBeh}(2)在组件中继承:
import {classicBeh } from '../classic-beh.js'
Component({
/** * 组件的属性列表 */
//组件可以继承多个behavior,所以这里是behaviors数组
behaviors: [classicBeh],
properties: {}(2)行为是可以多继承的,相同部分的覆盖规则:
子类覆盖父类
behaviors的最后一个覆盖前面的behavior
生命周期函数不存在覆盖,会被依次调用
#定义模板,组件间复用样式
(1)新建公共样式文件:common.wxss
(2)将样式写入common.wxss中
(3)在组件的.wxss文件中引入公共样式文件:
@import "../common.wxss";
#wx:if vs hideen
做多个组件间切换时,需要根据条件来判断对应组件的显示或隐藏,wx:if和hideen都能用于判断,两者有什么区别
(1)wx:if做切换,每次切换都存在上一次组件的销毁和下一次组件的重新渲染,消耗很大
(2)wx:if是惰性的,如果初次渲染条件为false时,框架什么都不会做,在条件变为true时,才会开始局部渲染
(3)hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。hidden 有更高的初始渲染消耗
(4)因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好,但是hideen不会触发生命周期函数
#Promise的本质与用法
(1)Promise是一个对象,对象可以用来保存对象
(2)Promise的三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)
(3)Promise实例创建时就处于pending状态,通过resolve和reject可以修改Promise的状态
实例:
//创建Promise实例
const promise = new Promise((resolve,reject)=>{
//写入异步代码
wx.getSystemInfo({
success: res=>{
//将Promise的状态修改为已成功
resolve(res)
},
fail: error=>{
//将Promise状态修改为已失败
resolve(error)
}
})
}//通过实例获取Promise结果
promise.then(
//成功回调函数
res=>{ console.log(res) },
//失败回调函数
error=>{ console.log(error) }
)#Promise.all()串行发送异步请求
Promise.all(),接受多个异步请求,等待所有请求都成功,再返回一个包含所有请求结果对象的新的Promise对象
示例:
onLoad: function (options) {
//获取传递的数据id
const id = options.bid
//以下是三个异步请求
const detail = bookModel.getBookDetail(id)
const comments = bookModel.getShortComments(id)
const likes = bookModel.getLikeStatus(id)
Promise.all([detail,comments,likes])
.then(res=>{
this.setData({
book:res[0],
comments: res[1].comments,
likeStatus: res[2].like_status,
likeCount: res[2].fav_nums
})
})
},#组件wxml的slot使用
在组件的wxml中可以包含 slot 节点,用于承载组件使用者提供的wxml结构。
默认情况下,一个组件的wxml中只能有一个slot。需要使用多slot时,可以在组件js中声明启用。
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
})此时,可以在这个组件的wxml中使用多个slot,以不同的 name 来区分。
<!-- 组件模板 -->
<view class="wrapper">
<slot name="before"></slot>
<view>这里是组件的内部细节</view>
<slot name="after"></slot>
</view>使用时,用 slot 属性来将节点插入到不同的slot上。
<!-- 引用组件的页面模板 -->
<view>
<component-tag-name>
<!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
<view slot="before">这里是插入到组件slot name="before"中的内容</view>
<!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
<view slot="after">这里是插入到组件slot name="after"中的内容</view>
</component-tag-name>
</view> #自定义组件样式探讨:hack方式与外部样式externalClass
例如:短评组件实现:
如图所示,前两条短评的颜色和其他不一样,每条短评都是通过相同短评组件循环出来的内容,组件内部设定了短评的基础样式,要通过什么方式改变短评的前两条内容的背景色?
方法一:hack方式,使用:nth-child()
缺点:违反了组件封装yu原则,修改了组件的默认样式
.comments > v-tag:nth-child(1) > view{
background-color: #fffbdd;
}
. omments > v-tag:nth-child(2) > view{
background-color: #eefbff;
}方法二:通过参数传递,用外部样式强制覆盖组件内部普通样式
修改组件.js文件内容:
Component({
//启用插槽
options:{ multipleSlots:true },
//引用外部样式
externalClasses:['tag-class'],
properties: {text:String},
})修改组件.wxml文件内容:
<view class="container tag-class">
<text>{{text}}</text>
<slot name="after"></slot>
</view>定义外部样式:
.ex-tag1{ background-color: #fffbdd !important;}
.ex-tag2{ background-color: #eefbff !important;}
应用外部样式
<view class="comments">
<block wx:for="{{comments}}" wx:key="content">
<v-tag tag-class="{{index==0?'ex-tag1':'' ||index==1?'ex-tag2':''}}"
text=" {{item.content}}">
<text class="nums" slot="after" >{{'+' +item.nums}}</text>
</v-tag>
</block>
</view>#wxs的使用
知识点:wxs的语法与ES5基本相似,但是wxs有自己的运行环境,它与JS是隔离的,wxs的意义在于它是能结合wxml,是可以在wxml中调用的脚本,而JS不行
wxs的引用方式:
(1)直接写在wxml中
<wxs>...</wxs>
(2)定义在.wxs文件中,再通过<wxs src="../../xx/xxx.wxs" module="xxx" />引入
示例:
问题:书籍内容简介中出现了字符‘/n’
原因:服务器返回的数据内容是‘//n’,而不是‘/n’,因此不能被小程序自动解析成换行符,对内容进行换行
方法:使用wxs定义模块,模块中使用正则表达式将‘//n’替换成‘/n’,wxml中只需要将只要处理的数据传递给模块即可
(1)定义filter.wxs
var format = function(text){
if(!text){
return
}
//这里使用四个‘\’,是对数据中‘\\n’的两个斜杠进行转义
var reg = getRegExp('\\\\n','g')
//加入空格符( )让换行段落段前缩进,wxml中要给对应标签设置decode="{{true}}",才能解析空格符
return text.replace(reg,'\n ')
}
module.exports={ format:format}(2)引用wxs
<wxs src="../../util/filter.wxs" module="util" />(3)使用wxs
<view class="content-wrap">
<text class="headline">内容简介</text>
<view class="contents">
<text class="content-text" decode="{{true}}">{{util.format(book.summary)}}</text>
</view>
</view>#监听用户的下滑页面操作
使用page的onReachBottom来监听用户下滑页面到底部,备注:组件无法直接使用page的onReachBottom
#加入锁机制解决重复数据问题
问题:通过监听用户的下滑操作来触发数据请求,但是如果用户操作过快,上次数据请求还未返回,又进行下滑操作触发数据请求,那么两次的数据请求会返回相同的数据,造成数据重复。
方法:为每一次的数据请求上锁,数据请求结束后解锁,保证用户每次的下滑操作只会触发一次数据请求,新的数据请求只能在上一次数据请求结束后开始
示例:示例为输入书籍名加载书籍
methods: {
//用户下滑页面到底
loadMore:function(){
//判断用户输入是否为空
if (!this.data.words) {
return
}
//是否正在数据请求中
if (this.isLocked()) {
return
}
//数据是否还未加载完
if (this.hasMore()) {
//数据请求前上锁
this.locked()
//请求数据
bookModel.searchBook(this.getCurrentStart(), this.data.words)
.then(res => {
this.setMoreData(res.books)
//成功时解锁
this.unLocked()
}, () => {
//失败时也解锁否则会变成死锁
this.unLocked()
})
}
},
}