好久没有写新的博客了。最近在联系小程序。所以记录一下小程序的坑与技巧。由于用 mpvue 和原生都撸过小程序,所以记录一些都会面临的情况。
页面相关
最外层占用整个屏幕
1 | .container { |
scroll-view 占满整个屏幕
此方法在 6s 等机型上存在不能滑动的问题,必须要手动设置 scroll-view 的高度才可以解决。所以需要在 scroll-view 外再包裹一个 view,然后通过
wx.createSelectorQuery()
拿到 view 的高度,再设置给 scroll-view。注意拿到的高度是 px 不是 rpx
scroll-view 如果设置 flex: 1
可以让 scroll-view 撑满屏幕。但是你会发现,scroll-view 无法滚动了。我们可以再设置一个样式:
1 | .scroll-view { |
设置超出部分隐藏。这样控件就自动拥有 scroll-view 的滚动功能了。
wxs 使用的坑
虽然我很抗拒 wxs,但是由于小程序不支持 computed,由于代码的美观,少在 data 中放几个字段,就需要借助 wxs 在 wxml 中生成计算后的数据。
但是其中有一个坑就是,定义变量的时候,不能使用 es6 的 let
和 const
只能使用 var
,否则也不报错,但就是无法显示。
绝对定位的居中
绝对定位的左右两边没有占位,所以 align-items
是无效的 align-self
可能无效。这种居中分为两种情况:
- 设置了控件宽度
- 不设置控件宽度
设置了 width
的情况下。我们只要使用 left
设置控件的位置即可。设置 left: 50%
可以让控件向右移动父视图的 50% 宽度。这样会移动过头,还需要设置 margin-left: -{50%的控件宽度}
修正控件的位置。
如果没有设置 width
的情况下。可以同时设置 left
和 right
,让视图撑满剩余的空间。
在外部修改组件库的样式
项目中引入了有赞的组件库。但是使用的时候有些样式不太符合要求。这个时候不要放弃使用,我们可以在外部修改内部的样式。
通过调试工具,找到不符合要求的视图的样式,在外部直接修改其样式:
1 | .van-popup--bottom { |
这里我们修改了 van-popup--bottom
的背景颜色。同时在后面加上了 !important
,这样是为了将我们的样式的权重提升,就不会被组件内部的样式覆盖了。
wx:key 取值
我们知道,无论是 react 还是 vue,在类表渲染的时候都提供了 key 这个关键字。key 相等的时候用来移动和改变状态,key 不等的则会进行销毁和重新创建。
React:
1 | const listItems = numbers.map((number) => |
vue:
1 | <my-component v-for="item in items" :key="item.id"></my-component> |
可以看到,这两种都是拿到 item,然后设置 item 的属性为 key。
小程序则默认key就是 item 中的属性了:
1 | <block wx:for="{{itemList}}" wx:key="id"/> |
这样就是直接设置 item 中的 id 为 key。这样和 React 和 Vue 不统一的写法,让我有点难受。
scroll-view 横向排布排布
scroll-view 横向排布有一些坑,如果按照常规的方式,你会发现 scroll-view 中的视图还是纵向排布的。我们需要做一些设置:
1 | .scroll-view { |
外部的 scroll-view 要设置 white-space
,否则会换行。内部的 item 要把显示设置为 inline-block
,否则还是纵向排布了。
如何只显示3行,超出显示省略号
要对 text 设置样式,一个也不能少:
1 | .text { |
要注意一定要设置 line-height
和 height
,并且要显示几行 height
就是 line-height
的几倍。
如果是单行的省略号改为:
1 | .text { |
注意,宽度一定要有。
滚动监听
小程序中滚动有两种方式。一种是直接视图的平铺,还有一种配合 scroll-view。
获取视图平铺时的滚动 offset
在平铺时候的滚动回调中每次都通过 selectViewport().scrollOffset()
拿到
1 | onPageScroll: function () { |
获取 scrollView 的 offset
1 | // scroll-view 中绑定方法 |
平铺滚动到某一个位置
1 | wx.pageScrollTo({scrollTop: 一个offset}) |
scroll-view 滚动到某一个 view 或者某一个位置
1 | // wxml 中 |
获取平铺或者 scroll-view 中距离顶部的 offset
1 | let query = wx.createSelectorQuery() |
#select
表示当前视图的 id <view id="select />"
绝对定位设置 padding-right 不符合预期
padding 的宽度不在 width 的范围内。所以如果你绝对定位设置宽度为 100% 时,如果设置了 padding-left ,那么视图整体会向右移,即实际宽度大于 720rpx。
这种情况下,只能把视图的宽度设置为 720-2*padding 值,才能让视图正常显示。
CSS 中设置高度为屏幕大小
有时候我们要设置高度或者宽度为屏幕大小,但是使用 100% 不好用。这个时候,我们可以使用 vh
和 vw
这是 CSS3 涌入的属性,分别表示高度/宽度基于窗口的大小,vh = view height,vw = view width:
1 | .window { |
设置多行子元素
为了让子元素能够自动换行,可以使用样式 flex-wrap: wrap
。当然这是第一步,这么做后你会发现,换行后的子元素贴在了一起。如图所示:
你需要设置元素间间隔。你会设置元素的 margin-bottom: 20rpx
。 但是这样的话父元素的 bottom 也会向下移动 20rpx。所以,你可以把父元素的 margin-bottom: -20rpx
。 这样,正负抵消,就是理想的间隔了。
小程序的button的边框
小程序默认的button是有一个边框的,需要设置一个样式:
1 | button::after { |
这样,所有的 button 标签都没有 border了
小程序捕捉事件
小程序默认的事件是冒泡的,也就是说点击了子控件触发方法后,父控件的点击事件还是会触发的,如果要阻止事件冒泡,可以把子控件的 bind:tap
改为 catch:tap
组件中的 class 选择
很多时候我们需要根据组件传入的值,来设置组件使用不同的 class。我们可以使用或或者三元选择符,但是需要使用双括号包裹,只要返回一个 class 的名字即可:
1 | <button |
组件中的 style
很多时候,我们需要传入值来控制 style,传入的值需要使用双括号包裹:
1 | style="width: 100%; height: {{ itemHeight * visibleItemCount + 'px' }}" |
引入 iconfont
首先把 iconfont 下载下来,打开其中的 iconfont.css 文件,应该是下面的样子,把它复制到 app.wxss 中作为全局样式。
1 | @font-face {font-family: "ChameIconfont"; |
由于小程序不会把 ttf 文件打包,所以需要修改 @font-face
中的 src 和 url 为网络路径。我们还是到 iconfont 的网站上,生成一个线上的文件地址,用它替换上面的 @font-face
这样项目中就可以使用了:
1 | <view class='ChameIconfont icon-ickehu'/> |
发布 npm 包
小程序用 npm 包需要把代码放在一个文件夹下,然后在 package.json 中增加一个 miniprogram
字段,标识代码所在目录:
1 | { |
当小程序开发工具 工具->构建npm
的时候,将该目录下的文件从 node_modules 移动到主目录下。
在 工具->构建npm
后,项目最外层目录生成 miniprogram_npm
文件夹,文件夹内包含所有 node_modules 中的模块。
在 app.json
中注册要使用的组件:1
2
3
4
5{
"usingComponents": {
"van-button": "/miniprogram_npm/vant-weapp/button/index"
}
}
或者直接 import
隐藏 scroll-view 滚动条
直接在相应的 wxss 中写入样式:
1 | ::-webkit-scrollbar { |
组件相关
外部全局样式影响组件内样式
在注册组建的时候添加一个选项,addGlobalClass
为 true:
1 | Component({ |
监听组件内数据改变
类似于 watch,组件内通过 observers 字段定义:
1 | Component({ |
父子组件的通信
小程序的父子组件提供了双向通信的方式。子组件可以通过 link 的回调,以及 getRelationNodes 两种方式获取父组件。父组件可以通过 link 回调获取子组件。
1 | // 子组件 path/to/custom-li.js |
1 | // 父组件 |
页面与组件的通信
组件调用页面提供的方法
页面将方法绑定给组件:
1
2
3
4
5
6
7<component-tag-name bind:myevent="onMyEvent" />
Page({
onMyEvent: function(e){
e.detail // 自定义组件触发事件时提供的detail对象
}
})组件内部触发事件:
1
2
3
4
5
6
7
8
9
10
11
12<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({
properties: {},
methods: {
onTap: function(){
var param = {} // 提供给页面的 e.detail 的参数
this.triggerEvent('myevent', param)
}
}
})
页面调用组件提供的方法
页面调用组件方法需要获取组件实例,可以通过 page 的 selectComponent
方法获取:
1 | <some-component id="custom-selector" /> |