小程序开发知识细节总结

244 阅读9分钟

#页面样式

(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') 
//加入空格符(&nbsp;)让换行段落段前缩进,wxml中要给对应标签设置decode="{{true}}",才能解析空格符  
 return text.replace(reg,'\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
}
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()        
   })     
  }   
 },
}