微信小程序 补充一发笔记

前言

最近不是很忙,Flutter和RN都有点整不动了,(此时流下了老奶奶基础太差,脑子又笨,咸咸的泪水),想着补补基础,于是就有了以下的笔记

image

笔记

  1. 小程序中的view类似于html中的div,那是块状结构(此处完全不懂块是啥玩意儿,默默的去查了一下,css中块级元素和行级元素的区别,以及微信小程序中的行级和块级元素),默认会占一行,多个view的话,可能会纵向排列,如果不想每个占一行的话,可以设置为行内元素,display:inline,但inline内是不能设置高和宽的,所以可以设置为display:inline-block,然后再设置高和宽

  2. 多个样式可以连续设置

<view class='chunk color1'/>
  1. 一般情况而言,对于view控件来说,高度会自适应,会根据里面填充的元素,动态的决定它的高度,宽度会是100%

就是比如row,row-reverse,column,column-reverse效果会不一样

reverse后,排列方向也会发生变化,比如row是左对齐,reverse后,会变成又对齐

  1. 当子控件没有设置高度的时候,父控件设置了align-items中的stretch后,会有个拉伸的效果,如果子控件明确设置了高度,则strecth会没有效果
  2. align-items中的baseline会保证每个子元素中的文字是对齐的,baseline会参考第一个子元素中的文字的底线作为基准,其他的子元素会根据这个基线,自动调整自己的位置
  3. 如果没有设置换行的话,每个元素加起来的宽度如果超过了屏幕的宽度,则会自动压缩每个控件,平均每个都会缩小一点,如果想换行的话,可以使用flex-wrap:wrap,如果想要消除换行后的间距(默认会在换行后,剩余的空间中,将换行过去的内容居中排列),则需要算高度,给个固定的高度
  4. 相对路径和绝对路径,如果在最前面加上一个/,表示绝对路径,从项目的最根目录开始算起,如果么有/的话,则是从当前文件的位置开始算起
/* 这里使用了子元素选择器的写法,但这种写法有个缺陷,就是不能复用,如果想把一个样式用在多个组件上的时候,可以给每个样式起个名字,小程序目前还支持子弹选择器等多种选择器,并不局限于文档中的几个 */
.container image{
  width: 32rpx;
  height: 28rpx;
}
  1. 字体
.container text{
  /* 苹方细体,只在ios系统中有效,在android中无效,如果电脑是苹果电脑的话,如果是用的安卓模拟器,则也是有效果的,主要是因为苹果电脑默认字体就是苹方 ,而在安卓中的默认字体是思源*/
  font-family: "PingFangSC-Thin";
  font-size: 48rpx;
  color: #bbbbbb;
}
  1. 每个页面,小程序默认会在最外层添加一个page标签(可以在调试器中的Wxml面板中查看到),所以当在全局app.wxss中设置page的样式后,会默认应用到每个页面去,这个就叫样式的继承,如果想修改的话,可以单独在自己的页面,做修改,这样会覆盖掉全局的样式

  2. 关于样式的继承:

  • 不是所有的全局样式都能够被组件继承,只有很少的部分能够被继承,在自定义组件中,只有font,color会从组建外继承到组件内
  • 但是几乎所有的样式都能够被page页面继承
  1. text中文字的四周默认都会有一个间距,消除间距的方法是:如果设置字体大小为24rpx,那么可以将行高line-height也设置为24rpx,这样就可以消除行高了
  2. 对于位置的偏移,在css中常用position来设置,比如position:relative
.container text{
  font-size: 24rpx;
  /* 将行高和字体设置得一样大,可以消除文字的间距 */
  line-height: 24rpx;
  color: #bbbbbb;
  position: relative;
  bottom: 10rpx;
  left: 5rpx;
}
  1. 将组件设置为flex后,可以消除子组件的块状属性,但并不能消除组件自己本身的块状属性
.container{
  /* 将display设置为inline-flex后,可以消除自己和子元素的块状属性,相当于将宽度设置为自适应 */
  display: inline-flex;
  flex-direction: row;
  padding: 10rpx;
}
  1. 关于事件绑定和冒泡:bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡
  2. 组件:
    一般对于组件内部的数据,都定义在data中
  3. 在小程序中,对于通过判断在wxml中显示不同的值的情况下,可以使用三元表达式,如果是在image内部的话,image的src路径如果在{}内部,则可以将路径用单引号括起来,比如:
<image src="{{like?'images/like.png':'images/unlike.png'}}"
  1. 对于组件的属性:
  /**
   * 组件的属性列表,即会开放出去的属性
   */
  properties: {
    //如果这里属性比较多的话,可以将其包裹成一个对象
    like: {
      // 目前小程序只可以设置以下三个值,其中type为必填,value和observer为选填
      type: Boolean,
      // // 初始值,如果初始值为false的话,没有必要写,因为boolean的默认值本来就是false,所以当初始值要为true时,才有必要写
      // value: false,
      // // 监听方法,当我们改变了index的值的时候,微信小程序会主动地来调用该方法,newVal代表改变之前的数值,oldVal代表改变之后的数值
      //但是千万不要在observer中尝试修改index本身的值,否则可能会造成无限递归的情况
      // observer(newVal,oldVal,changedPath){
      // }
    },
    count: {
      type: Number,
    }
  },

  /**
   * 组件内部的数据定义在此,即内部的私有属性
   */
  data: {
    likeSrc: "images/like.png",
    unLikeSrc: 'images/like@dis.png'
  },

在properties中定义的属性,主要是用于外部传入数据,比如:

<z-like like="{{classicData.like_status}}" count="{{classicData.fav_nums}}" />

其中properties是要暴露出去的属性,外部可以访问的属性,而data内部的属性则是组件内部使用的私有属性,不对外开放

  1. 如果要取properties或者data中的数据,使用this关键字
  2. let和var的区别:
    let允许你生命一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,它生命的变量只能是全局或者整个函数块的。var的作用域要更大一点,以前写过java的可能会更习惯于用let一点,python的可能更习惯于var一点
  3. 网络请求有三种形式:GET(获取数据),POST(提交参数),PUT(修改数据)
  4. 网络请求一般放在小程序生命周期中的onLoad中
  5. 一般情况下,只要服务器返回了结果,不管是2、3、4、5开头的,都会走success方法,如果网络出了问题,则会走fail方法
  6. 小程序一般不允许随意访问一个url,如果要访问的话,必须在小程序的后台账号中,将该域名添加到合法域名列表中才可以访问,这是一个方法,另外还有一个方法(只适用于开发阶段,如果最后你的小程序要上线发布的话,还是需要按照第一种方法来设置噢)就是:

    image

  7. 当我们遇到一个网络请求出现错误的时候,最好的办法就是打开调试器中的Network面板,点击这个错误,查看具体的错误信息,才能知道错在哪(如果错误为500,那么肯定是服务器错误,其他的就需要你自己多多查看自己代码哪里有问题了)

     

    image

     

    image

     

    如果是返回正常的数据,那结果也可以点开Name来查看

  8. 关于this的指代问题:在回调函数中,使用this.data.****,某个属性,this是不明确的,会为null,在es6之前,传统的做法为:在回调函数之外,使用let that=this,先将this,赋值给一个变量,在回调函数中使用that这个变量。而在es6中,有个更好的解决办法:使用箭头函数
data: {
    test:1
  },
  onLoad: function (options) {
    console.log(this.data.test)
    wx.request({
      url: 'http://bl.7yue.pro/v1/classic/latest',
      header:{
        appkey:"K5H3SiFRY9qLzs0n"
      },
      success:function(res){
        //这里会报错
        console.log(this.data.test)
      }
    })
  },

解决方法一:

onLoad: function (options) {
    console.log(this.data.test)
    let that=this
    wx.request({
      url: 'http://bl.7yue.pro/v1/classic/latest',
      header:{
        appkey:"K5H3SiFRY9qLzs0n"
      },
      success:function(res){
      //使用that替代
        console.log(that.data.test)
      }
    })
  },

解决方法二:

onLoad: function (options) {
    console.log(this.data.test)
    wx.request({
      url: 'http://bl.7yue.pro/v1/classic/latest',
      header:{
        appkey:"K5H3SiFRY9qLzs0n"
      },
      //使用箭头函数
      success:(res)=>{
        console.log(this.data.test)
      }
    })
  },
  1. 使用Promise的场景:异步嵌套,也就是回调地狱

    image


    如果你的异步操作没有回调的嵌套,只有一次操作,那就完全不需要使用Promise,滥用Promise反而会增加代码的复杂度

Promise的简单用法(解决回调地狱问题)

apiOne()
.then(res=>
    return apiTwo(res)
)
.then(res=>
    return apiThee(res)
)
.then(res=>
    //……
)

每次的异步调用之间是平级的关系,不像以前那样,在回调中调用,在回调的回调中调用

  1. 关于const常量:不能修改该常量的内存地址,否则会报错

     

    image

  2. ES6中的导入与导出:
    es5中如果要导入一个类或者其他的,需要使用到require,而在es6中的话,导出只需加上export,导入的地方使用import即可

导出的地方

export const config={
  api_base_url='http://bl.7yue.pro/v1/',
  appkey: "K5H3SiFRY9qLzs0n"
}

// 也可以写成以下的方式:
// export {
//   config
// }

// 或者
// export {
//   //这里起了别名的话,在导入的地方要直接使用别名哦,而不能使用config了哦
//   config as 别名
// }

导入的地方

// 这里的config必须和导出地方的源常量名一致,如果不想用原来的名字,则可以使用import{config as 别名} from '/config.js'
import {
  config
} from '/config.js'

class HTTP {
  request(params) {
    wx.request({
      url: params.url,
      header: params.header,
      method: params.method
    })
  }
}
  1. 在import的时候尽量使用相对路径,不要使用绝对路径
  2. 在小程序中,setData中的所有数据都可以在调试器下面的AppData面板中看到
  3. 凡是要被wxml使用的变量,最好都在data中定义一下,给个初始值也好,比如:
data: {
    classicData:null
  },
  onLoad: function (options) {
    classic.getLastest((res)=>{
        console.log(res)
        this.setData({
          // classicData是要传递到wxml中去,被wxml使用的变量,最好在data中初始化一下
          classicData:res
        })
    })
  },
  1. 关于自定义组件中的自定义事件
    如果想与外部调用的组件通信,想把一些数据传递出去,则可以使用自定义事件triggerEvent来完成,
    this.triggerEvent("自定义事件名称",{自定义事件参数},{其他设置})

33.如果想对data下面的值做初始化的话,不能给用Number或者String等,因为默认的Number和String是一个函数,而在properties中只是做了特殊处理才没有报错,如果想对data下的值做初始化,可以直接给值
34.不管是properties还是data,它们都指向同一个js对象,可以理解为它们两个最后会合并成一个js对象,所以就算它们两个表面上内部的属性不一样,但打印出来会是一模一样的,最后会指向它们两个的一个合集,但两者内部最好不要有同名的属性,不然合并后会data中的会覆盖properties中的同名属性的值,而区别就是properties中的值会取给定的默认值,而data中的会是js中内置的函数,要设定初始值的话,可以类似以下这种设置方法

 

image

  1. display:inline-flex???
  2. 如果多个组件有同样的属性和行为,那么可以定义一个behavior(类似component,有properties,data,以及methods),而一个组件可以继承多个behavior,所以在component中的behaviors是个数组。而component和behavior如果有同样的属性或者方法的时候,就需要一个规则来决定最后用哪个:

    image

  3. 一般私有函数是放在类中的最下面的
  4. 模板字符串:将单引号改为反引号,并在变量前面加上$以及{},比如
url: 'classic/' + category + '/' + artID + '/favor'

,改为模板字符串后:

url: `classic/${category}/${artID}/favor`
  1. 扩展运算符:"..."使用三个点,可以将一个对象进行展开,这个在绑定wxml的时候比较有用,比如传入一个对象item,在wxml中需要item.title,item.img一个一个的传的话,略微不简洁,则可以在传入的时候就直接使用...item,将对象item展开后传入,然后在wxml中就不用写前面的item了

    image


    比如使用扩展运算符之前

js中

onLoad(options) {
    classicModel.getLastest((res) => {
      console.log(res)
      this.setData({
        // classicData是要传递到wxml中去,被wxml使用的变量,最好在data中初始化一下
        classicData: res
      })
    })
  },

wxml中

<view class ="container">
  <view class='header'>
    <z-epsoide class="epsoide" index="{{classicData.index}}" />
    <z-like class="like" bind:like="onLike" like="{{classicData.like_status}}" count="{{classicData.fav_nums}}" />
  </view>
  <z-movie img="{{classicData.image}}" content="{{classicData.content}}" />
  <z-navi bind:left="onNext" bind:right="onPrevious" title="{{classicData.title}}" first="{{first}}" latest="{{latest}}" class="navi" />
</view>

而使用扩展运算符之后

js中

onLoad(options) {
    classicModel.getLastest((res) => {
      console.log(res)
      this.setData({
        ...res
      })
    })
  },

wxml中

<view class ="container">
  <view class='header'>
    <z-epsoide class="epsoide" index="{{index}}" />
    <z-like class="like" bind:like="onLike" like="{{like_status}}" count="{{fav_nums}}" />
  </view>
  <z-movie img="{{image}}" content="{{content}}" />
  <z-navi bind:left="onNext" bind:right="onPrevious" title="{{title}}" first="{{first}}" latest="{{latest}}" class="navi" />
</view>

而有时候,如果你确定只有一个参数的时候,参数外面不需要小括号,箭头函数后面的部分如果只有一行的话也不需要花括号

比如:

const promise = new Promise((resolve, reject) => {
      wx.getSystemInfo({
        success:(res)=> {
          //信息获取成功后,通过resolve将状态修改为resolve
          resolve(res)
        },
        fail:(error)=> {
          //信息获取失败后,通过resolve将状态修改为reject
          reject(res)
        }
      })
    })

可以修改为:

const promise = new Promise((resolve, reject) => {
      wx.getSystemInfo({
        success:res =>resolve(res),
        fail:error=>reject(res)
        })
    })
  1. 在wxml中控制控件的显示与隐藏:可以使用小程序中提供的条件渲染语句:wx:if="{{***}}",如果括号内的内容为真,那么该控件就显示,否则就隐藏:

    image


    而另外一种控制显隐的方法是使用hidden,在普通的控件中是有效的,但hidden对于自定义组件会失效,可能是因为自定义组件会将hidden当成一个普通的属性,解决办法就是在自定义组件的properties内部,自己新建一个hidden属性来达到目的。而hidden和wx:if也是有区别的:

    image


    如果切换得比较频繁的话,就用hidden吧。但是在组件中,有hidden的话,是不会出发detached方法,但wx:if就可以,因为使用wx:if的话,每次切换都会执行一次完整的生命周期,所以文档中有句话说的是一般来说,wx:if有更高的切换消耗而hidden有更高的初始渲染消耗,因此,如果需要频繁切换的场景下,用hidden更好,如果在运行时条件不大可能改变则用wx:if更好,hidden在被初始化之后,就不会再去多次执行生命周期函数,只会做单纯的显示与隐藏
  2. 对于音乐播放的控制,以前的话是使用老板api,这个使用是调用一个一个的方法:

image

现在推荐使用新版api,这个对象会有一些非常有用的属性和方法,相对要方便点:

image

wx.getBackgroundAudioManager()将会返回一个backgroundAudioManager对象,由这个对象来进行音乐的播放控制

  1. 对于在小程序中实现动画有几种方法:直接使用动画API,另外一种方法就是使用CSS3自己去编写,还有一个就是canvas
  2. airbnb的js规范中都给出了每一个规范的eslint(代码规范和错误检查工具,可以用来约束整个团队的代码风格)??
    let date=new Date()
    let year =date.getFullYear()

    this.setData({
      year:year,
    })

用eslint属性值简写优化后:

    let date=new Date()
    let year =date.getFullYear()

    this.setData({
      year,
    })
  1. 处理异步的几个方案:
  • 纯粹的callback
  • promise
  • async await ES2017 小程序目前不支持
  1. Promise有三种状态
  • pending 进行中
  • fulfilled 成功
  • rejected 失败
    promise的基本用法:
    //promise使用对象的方式,保存了异步调用的结果
    const promise = new Promise((resolve, reject) => {
      wx.getSystemInfo({
        success:(res)=>{
          //信息获取成功后,通过resolve将状态修改为resolve
          resolve(res)
        },
        fail:(error)=> {
          //信息获取失败后,通过resolve将状态修改为reject
          reject(res)
        }
      })
    })

    //then有两个参数,一个是成功,一个是失败,分别对应上面的resolve和reject
    promise.then((res) => {
      console.log(res)
    }, (error) => {
      console.log(error)
    })
  1. es6中的解构???,下面是对象的解构,其他的还有数组的解构
    在传参中,将所有参数用大括号括起来,则可以直接传一个对象进去,并每个参数需要写上参数名,比如:
request(url,data={},method='GET')

传参的时候

this.request({
    url,{
        name:'zoe',
        age:18
    },'POST'
})

修改后:

request({url,data={},method='GET'})

传参:

this.request({
    url:url,
    data:{
        name:'zoey',
        age:18
    },
    method:'POST'
})

传参的时候就会显得比较清晰和明确

  1. 对于absolute,在css文档中,position总共有四个值,分别为absolute fixed relative static,如果不给值得话,默认会是static。而absolute都会有个参照元素(一般都是其父元素),这个参照元素的父元素不能是static的。如果子元素为absolute,那么子元素如果想要参考父元素来定位的话,父元素就需要是非static的

    image

  2. 对于position中的fixed属性:
.header{
  /* fixed会让header始终保持在一个固定的位置,如果想在最上层的话还需要设置一个z-index */
  position: fixed;
  background-color: white;
  height: 100rpx;
  width: 100%;
  border-top: 1px solid #f5f5f5;
  border-bottom: 1px solid #f5f5f5;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 3px 0 #e3e3e3;
  z-index:99
}

就是下图中“搜索书籍”一栏能够固定在顶部的效果

image

  1. 关于wx:for的key:
<view class='books-container'>
    <!-- 如果列表本身就是数字或者字符串,那么key可以直接写成wx:key="*this" -->
      <block wx:for="{{books}}" wx:key="index">
        <z-book book="{{item}}"/>
      </block>
    </view>
  1. 组件接收参数是通过properties接收的,而页面接收的参数,全部在页面的onLoad方法中的options参数中,比如:
    外部给当前页面传一个id,则在该页面,获取id的写法如下:
onLoad(options){
    const id=options.id
}
  1. 微信小程序有三种编译模式:
  • 普通编译模式 每次重新编译,都会从app.json中排在第一个页面的位置重新启动
  • 添加编译模式 可以自己定义编译模式,也就是指定一个启动页面,不用每次都回到首页
  • 通过二维码编译

下面介绍以下第二种编译模式:

点击顶部“普通编译”框,选择下拉列表中的“添加编译模式”

image

取一个模式名称,然后在“启动页面”处下拉选择你要首先展示的页面

image

然后给定一个该页面需要传入的参数,就可以了

image

然后看编译模式那里,就能看到刚刚自定义的模式了。选择该模式,每次编译后,首先就进入你希望的页面了。方便调试

image

  1. 在flex模式下,margin-bottom才会生效 ?
  2. 在自定义组件内部还有个高级的东西:slot(插槽),一个slot相当于一个占位符,如果外部传入标签,那么就会将插槽替换成传入的标签,如果不传,那么就会是一个空的插槽,空的插槽是不会被渲染和显示的

一个组件内部可以有多个插槽,他们之间是用name进行区分

tag.wxml

<view class='container'>
  <slot name="before" />
  <text>{{text}}</text>
  <slot name="after" />
</view>

要在组件内部加上插槽,需要将使用组件的wxml中的组件写成双标签样式,并在标签内部,加入要添加的部分,并声明要对应的插到哪个槽上(slot="插槽名")

book-detail.wxml

<z-tag text="{{item.content}}">
    <text slot="before">^_^</text>
    <text slot="after">{{' +'+item.nums}}</text>
</z-tag>

启用插槽:在组件内部,写上

tag.js

options: {
    //启用插槽
    multipleSlots: true
},
options:{
     multipleSlots:true
 }
  1. 不能直接对自定义组件书写css样式,可以通过:
  • 子元素选择器或者后代选择强行给自定义组件的内部组件设置样式(这种方式违反了组件封装原则)
  • 组件的属性和slot给自定义组件传入你想要的样式
  • 外部样式(externalClass)
  • 全局样式(globalClass)
  1. 子元素选择器与后代选择器:
/* 后代选择器
.comment-container z-tag:nth-child(1) view{
  background-color: #fffbdd;
} */

/* 子元素选择器
.comment-container > z-tag:nth-child(1) > view{
  background-color: #fffbdd;
} */

/* 子元素选择器
.comment-container > z-tag:nth-child(2) > view{
  background-color: #eefbff;
} */

/* 子元素选择器 选择奇数*/
.comment-container > z-tag:nth-child(odd) > view{
  background-color: #eefbff;
}

/* 子元素选择器 选择偶数*/
.comment-container > z-tag:nth-child(even) > view{
  background-color: #fffbdd;
}

nth-child选择器
子元素选择器和后代选择器的区别

  1. 外部样式的使用:

如果想要实现同上面子元素选择器同样的效果:

image

使用外部样式的方式,需要按照以下步骤来:

在组件内部js中定义externalClasses属性

//外部样式,接收组件外部传入进来的样式,可以有多个
  externalClasses: [
    'tag-class',
  ],

在组件内部的wxml中使用定义的externalClasses:

<!-- 这里container代表的叫普通样式,而tag-class代表的为外部样式,外部样式要放在普通样式之后,这样可以在外部对原有的样式做一定的覆盖(会覆盖这个真的是一厢情愿,小程序好像并没有做这样的处理,尴尬,所以括号外的上一句话请忽略,小程序实际的做法是,如果你要传入外部样式,那你原来的样式就不要要了,只能选择一个),补充 -->
<view class='container tag-class'>
  <slot name="before" />
  <text>{{text}}</text>
  <slot name="after" />
</view>

在外部定义即将要传入的样式

book-detail.wxss

.ex-tag1 {
  background-color: #fffbdd;
}

.ex-tag2 {
  background-color: #eefbff;
}

在外部使用,传入我们自定义的样式:

book-detail.wxml

<z-tag tag-class="{{index==0?'ex-tag1':''||index==1?'ex-tag2':''}}" text="{{item.content}}">
    <text class='num' slot="after">{{' +'+item.nums}}</text>
</z-tag>

但是小程序目前不能实现外部样式覆盖内部样式,也就是普通样式和外部样式同时只能有一个,但可以有一个强行实现的办法:在外部定义即将传入的样式的时候,在样式末尾加上!important,提升样式的优先级,强行实现(可能还有其他办法,欢迎告诉我):

book-detail.wxss

.ex-tag1 {
  background-color: #fffbdd !important;
}

.ex-tag2 {
  background-color: #eefbff !important;
}
  1. 全局样式类的使用:
// comp-a.js
Component({
  options: {
    addGlobalClass: true,
  }
})
<!-- comp-a.wxml -->
<text class="text red-text">THIS IS A</text>
/* comp-a.wxss */
.text{
  color: blue;
  font-size: 80rpx;
  font-weight: 400;
}
//comp-b.js
Component({
  options: {
    addGlobalClass: true,
  }
})
<!-- comp-b.wxml -->
<text class="text">THIS IS B</text>
/* comp-b.wxss */
.text{
  color: orange;
  font-size: 40rpx;
  font-weight: 400;
}
{
  "usingComponents": {
    "comp-a": "/components/comp-a/comp-a",
    "comp-b": "/components/comp-b/comp-b"
  }
}
<!-- index.wxml -->
<view class='container'>
  <comp-a/>
  <comp-b/>
</view>
/* index.wxss */
.container{
  display: flex;
  flex-direction: column
}

.red-text {
  font-size: 20rpx;
  color: red !important;
}

image

总的来说可以达到外部样式类的效果,而且还比外部样式类的方式简单一点

  1. wxs:让wxml具备写js或者调用js的能力,主要作用可以用来编写小程序的过滤器,比如:

需求:将text中的\\n替换为\n

定义一个filter.wxs

// 将\\n替换成\n
var format = function(text) {
  if (!text) {
    return
  }
  var reg = getRegExp('\\\\n', 'g')
  // & nbsp;表示空格
  return text.replace(reg, '\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
}

module.exports = {
  format: format
}

在使用的地方,比如book-detail.wxml中

<wxs src="../../util/filter.wxs" module='filter' />

……
<text class='content' decode='{{true}}'>{{filter.format(book.summary)}}</text>
……

也可以直接在wxml中定义

<wxs module="filter">
  var limit = function(array, length) {
    return array.slice(0, length)
  }
  var format = function(text){
    if(!text){
      return
    }
    var reg = getRegExp('\\\\n','g')
    var text = text.replace(reg,'\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
    return text
  }
  module.exports = {
    limit: limit,
    format:format
  }
</wxs>
  1. 设置段落开头的距离:text-indent(规定文本块中首行文本的缩进,允许使用负值。如果使用负值,那么首行会被缩进到左边)
  2. padding的描述的顺序(margin同理哈)

    image

  3. white-space,它经常和overflow和text-overflow一起使用,比如:
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden

表示多余的不换行,多余的隐藏并显示省略号,参考

  1. 在wxml中写动画,比如:
.rotation{
  /* linear匀速播放,infinite无限播放 */
  animation: rotation 12s linear infinite;
}

@keyframes rotation{
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

image

  1. Promise.all(),可以组合多个promise,使用方法:

const promise4 = Promise.all([promise1,promise2,promise3]),它内部是一个数组,可以有多个promise,然后它会返回一个新的promise

只有当内部所有的promise都返回结果后,才会出发新的promise的then回调方法,比如可以用在一个页面有多个网络请求,但如果要加上Loading的话,需要加在所有页面完成之后,可以使用promise.all

onLoad: function(options) {
    wx.showLoading({
      title: '加载中...',
    })

    const bid = options.bid

    const detail = bookModel.getDetail(bid)
    const comments = bookModel.getComments(bid)
    const likeStatus = bookModel.getLikeStatus(bid)

    //使用Promise.all取代下面三个单独的promise
    Promise.all([detail,comments,likeStatus])
    .then(res=>{
      //这里res返回的是一个数组,一一对应的是传进去的参数的结果
      //这里所有结果都返回后,才会执行该回调
      this.setData({
        book: res[0],
        comments: res[1].comments,
        listStatus: res[2].like_status,
        likeCount: res[2].fav_nums
      })
      wx.hideLoading()
    })


    // detail.then(res => {
    //   this.setData({
    //     book: res
    //   })
    // })
    // comments.then(res => {
    //   this.setData({
    //     comments: res.comments
    //   })
    // })
    // likeStatus.then(res => {
    //   this.setData({
    //     listStatus: res.like_status,
    //     likeCount: res.fav_nums
    //   })
    // })
  },
  1. Promise.race([promise1,promise2,promise3]),返回的将是promise1,promise2,promise3三个promise中,竞争成功的那个promise,也就是返回速度最快的那个
  2.  
//先判断历史记录中是否有该关键词
const has = words.includes(keyword)

//将keyword放到words数组中的第一位
words.unshift(keyword)

words.pop() //删除末尾的元素
  1. 做上拉加载更多可以使用Page页面中的onReachBottom方法,也可以使用scroll-view组件
  2. 如果wxml中,绑定的有data中的变量的话,改变这个值必须要使用setData来进行,如果没有绑定的话,则可以直接使用=来赋值,比如:
    this.data.loading=false
  3. 一个会被多个地方使用到的功能,可以提取成一个behavior,比如上拉加载更多
  4. 不需要用户授权,就能获取到用户头像和昵称的方法(有缺陷):open-data <open-data type="userAvatarUrl">,这个只是微信用来显示相关信息的,并不会获取到相关信息。而如果想在js中拿到用户的相关信息,则需要授权,在老版本中,可以使用wx.getUserInfo接口,然后界面会出现一个弹窗,询问用户是否愿意授权小程序来获取自己的信息。而新版本中,不能这样使用了,现在需要是用组件的方式而不是API的方法来弹窗了。这样是否弹窗的主动权掌握在用户自己手里,而不会一进某个页面就弹窗。wx.getUserInfo能获取到用户信息的前提是:已经获得授权。比如:
    <button open-type="getUserInfo" bind:getuserinfo="onGetUserInfo">
    用户授权后,将不再弹出授权框
  5. wx.getSetting,知道用户是否授权过,返回的值中authSetting如果有值,则为已授权,如果为空,则没授权
  6. 如果想从一个小程序跳转到另外一个小程序,那么这两个小程序,必须都要关注了同一个公众号
  7. 小程序跳转,还有个内置的组件叫navigator,如果要跳转到另外一个小程序,则需要知道另外一个小程序的app-id,比如:
<navigator class="nav" target="miniProgram" app-id="******" open-type="navigate">
  <image class="vendor" src="/images/my/vendor.png"></image>
</navigator>



作者:周南城
链接:https://www.jianshu.com/p/7571cdaea370
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值