微信小程序之入门篇:粘性定位,json-server,scroll-view、swiper、swiper-item
前言
本文将会去探索微信小程序的三个标签scroll-view、swiper、swiper-item的用途,将它们搭配起来使用做成视频和直播等软件常见的业务场景,效果如图所示。源码地址:github。(大佬可跳过)
页面部分
1、scroll-view
scroll-view一般用于可滚动视图区域,所以广泛用于导航菜单栏等业务场景。
<scroll-view class="hy-unlogin-navbar" enable-flex="true" scroll-x="true" scroll-left="{{navScrollLeft}}" scroll-with-animation="true" scroll-anchoring="true">
<block wx:for="{{navtabs}}"
wx:for-index="id"
wx:key="index">
<view class="navbar-item {{currentTab == id ?'active':''}}"
data-current="{{id}}"
bindtap="switchNav"
>
{{item.nameText}}
</view>
</block>
</scroll-view>
2、swiper与swiper-item
swiper与swiper-item是一对标签,一般搭配使用用于轮播图等业务场景。
<swiper class="tab-box" style="height: {{conHeight}}rpx;" current="{{currentTab}}" bindchange="switchTab" skip-hidden-item-layout="true">
<swiper-item class="tab-express" wx:for="{{navCont}}" wx:key="index">
<view class="hy-allLives-content">
<view class="hy-allLives-content-small" wx:for="{{navCont[index]}}" wx:key="index" data-id="{{item.id}}" bindtap="gotoDetail">
<image src="{{item.image}}"></image>
<view class="hy-allLives-content-text">
<text>{{item.descText}}</text>
</view>
</view>
</view>
</swiper-item>
</swiper>
js部分
数据放在.js文件中,用module.exports抛出,在index.js中用require引入。
const navCont = require('../../assets/db/tabs2')
通过点击事件引起currentTab的值变化从而改变swiper标签的current属性值变化,从而实现导航栏与之对应内容之间的切换。这是实现导航栏切换的其中一种方式,另外一种实现方式是采用WeUI(一套同微信原生视觉体验一致的基础样式库)的Navbar的思想。想体验一下weui的视觉效果,请点击WeUI,Navbar的wxml源码。
注意:由于weui最近更新了版本至v2.3.0,上述Navbar所涉及的版本是v2.0.1。
另一种实现具体代码如下
<scroll-view id="navfix" scroll-x="true" scroll-with-animation="true" enable-flex="true" scroll-left="{{navScrollLeft}}"
class="hy-navbar {{isfixed ? 'hy-navbar-fix' : ''}}">
<block wx:for="{{navtabs}}" wx:key="index">
<view data-id="{{item.id}}" data-index="{{index}}" bindtap="switchTab"
class="hy-navbar__item {{curId === item.id ? 'on' : ''}}">
<view class="hy-navbar__tilte">{{item.nameText}}</view>
</view>
</block>
</scroll-view>
<view class="hy-allLives">
<view class="hy-allLives-content">
<view class="hy-allLives-content-small" wx:for="{{allLives}}"
hidden="{{curId == 'all' ? '' : (curId != item.categoryId)}}"
bindtap="gotoDetail" data-id="{{item.id}}">
<image src="{{item.image}}"></image>
<view class="hy-allLives-content-text">
<text>{{item.descText}}</text>
</view>
</view>
</view>
</view>
这种实现方式的原理就是不是此分类页面下的内容就隐藏掉。但此方式并不能实现滑动切换菜单(可能是我太菜了,可根据需求选择),因此采用第一种方式通过给swiper绑定bindchange属性添加change事件,每当用户水平滑动页面时,触发change事件,监听change事件从事件参数中获取current值,并赋值给currentTab,从而达到滑动切换菜单的效果。
可能会踩的“坑”
在你使用scroll-view和swiper时,会出现swiper-item中的内容超出可视范围,无法上下滑动的问题,如何解决呢?首先想到的是swiper高度自适应。
const conHeight = Math.ceil(navCont[idx].length / 2) * 290
idx是从事件参数中获取的值,并且会赋值给currentTab。Math.ceil()是向上取整的方法,Math.round()四舍五入的方法并不合适,因为(navCont[idx].length / 列数)只要除不尽就得往上加1。
高亮(被选中)菜单始终在可视区域内
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let w = wx.getSystemInfoSync().windowWidth // 获取窗口宽度
console.log(w)
this.setData({
windowWidth: w
})
}
switchNav (e) {
// console.log(e)
let idx = e.currentTarget.dataset.current
var singleNavWidth = this.data.windowWidth / 8
this.setData({
currentTab: idx,
navScrollLeft: (idx - 1) * singleNavWidth
})
}
switchTab (e) {
// console.log(e)
var singleNavWidth = this.data.windowWidth / 8
if (e.detail.source == 'touch') {
this.setData({
currentTab: e.detail.current,
navScrollLeft: (e.detail.current - 1) * singleNavWidth
})
}
}
导航栏粘性定位
1、监听scroll事件
// 实时监控滚动距离顶部的位置
onPageScroll: function (e) {
// console.log(e)
this.setData({
scrollTop: e.scrollTop
})
var that = this // this作用域不会改变,可不指定
if (e.scrollTop >= that.data.topheight + that.data.height) {
that.setData({
isfixed: true
})
} else if (e.scrollTop < that.data.topheight + that.data.height) {
that.setData({
isfixed: false
})
}
}
通过实时监控距离顶部的位置当大于某一临界值时,就让导航栏通过position:fixed属性固定在某一位置,从而达到粘性定位效果。(添加类名实现,否则则取消。缺点:不是太顺滑,会闪现一下,需要优化)
临界值你可以根据自己需要定义,也可以用微信小程序自带的方法获取。wx.createSelectorQuery().select()选取所需要定位的元素节点,然后分别获取当前元素节点距离页面顶部的高度以及自身的高度。
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
wx.createSelectorQuery().select('#navfix')
.boundingClientRect( rect =>{
// console.log(rect)
this.setData({
topheight: rect.top,
height: rect.height
})
}).exec();
}
2、CSS3新属性position:sticky
在所需要定位的元素节点的css中加上position:sticky;top:0;
top指的是当前元素节点定位时距离页面顶部的高度(位置),但此属性有个缺点,兼容性不太好,但在微信小程序中还是可以的。有关更多此属性的兼容性问题和“坑”,请看 position: sticky 详解(防坑指南)这篇文章。
提出问题
以上两种方法虽然实现了所需的导航菜单栏效果,但是数据这一块都是全部一次性请求回来,然后根据数组下标或隐藏来实现相关内容的切换效果。但是一旦数据过于庞大,一次性请求全部数据回来就会造成浏览器性能消耗过大甚至页面卡顿,显然在实际情况中这是不可行的。实际情况中肯定是页面切换到哪个菜单就会向后端去请求哪个菜单的相应数据回来,那没有服务器又该咋实现呢?
使用json-server
本文采用了一种“投机取巧”的办法,使用json-server这个Node模块来模拟一下数据的请求,json-server可以直接把一个json文件直接托管成一个简易的web服务器。具体操作流程如下:
- 新建一个文件夹,然后npm install json-server安装这个模块。
-
在此文件夹下新建一个.json格式的文件。
- 启动该服务,把package.json中的scripts改成"dev": "json-server db.json",然后使用命令npm run dev启动即可(默认启动在3000端口上),如果此命令失效,换成.\node_modules.bin\json-server .\db.json,这个命令是一定有效的,db是文件名。
"scripts": {
"dev": "json-server db.json"
}
至此,一个简易的模拟服务器就搭建而成了,此时去前端页面请求数据即可。
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
wx.request({
url: 'http://localhost:3000/navData', //菜单选项
success: (res) => {
// console.log(res.data)
this.setData({
navtabs: res.data
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.requestCart(this.data.currentTab) // 默认显示菜单
let w = wx.getSystemInfoSync().windowWidth // 获取窗口宽度
console.log(w)
this.setData({
windowWidth: w
})
},
switchNav (e) {
let idx = e.currentTarget.dataset.current
var singleNavWidth = this.data.windowWidth / 8
this.setData({
currentTab: idx,
navScrollLeft: (idx - 1) * singleNavWidth
})
this.requestCart(idx)
},
switchTab (e) {
var singleNavWidth = this.data.windowWidth / 8
if (e.detail.source == 'touch') {
this.setData({
currentTab: e.detail.current,
navScrollLeft: (e.detail.current - 1) * singleNavWidth
})
}
this.requestCart(e.detail.current)
},
requestCart(idx) { // 模拟向后端接口发起请求
wx.request({
url: `http://localhost:3000/${idx}`,
success: (res) => {
// console.log(res.data)
const conHeight = Math.ceil(res.data.length / 2) * 290
this.setData({
allLiveCont: res.data,
conHeight: conHeight
})
}
})
}
注意:这里可能会遇到数据请求不回来,这时一般是遇到了跨域问题。在详情=>本地设置=>勾选不校验合法域名即可解决。附:前端常见跨域解决方案
结语
本文(第一次写)是一篇随笔,算是微信小程序的入门篇,希望对各位有所帮助。如果文中有什么错误或者不足之处,欢迎大家斧正!如果各位对某处知识点有什么更好的建议,欢迎留言,前端小白在线求教^^!
如果你喜欢这篇文章或者可以帮到你,不妨点个赞吧!