微信小程序之scroll-view swiper swiper-item

微信小程序之入門篇:粘性定位,json-server,scroll-view、swiper、swiper-item

前言

本文將會去探索微信小程序的三個標(biāo)簽scroll-viewswiperswiper-item的用途,將它們搭配起來使用做成視頻和直播等軟件常見的業(yè)務(wù)場景,效果如圖所示。源碼地址:github。(大佬可跳過)

效果圖

頁面部分

1、scroll-view

scroll-view一般用于可滾動視圖區(qū)域,所以廣泛用于導(dǎo)航菜單欄等業(yè)務(wù)場景。

<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是一對標(biāo)簽,一般搭配使用用于輪播圖等業(yè)務(wù)場景。

<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部分

數(shù)據(jù)放在.js文件中,用module.exports拋出,在index.js中用require引入。

const navCont = require('../../assets/db/tabs2')

通過點擊事件引起currentTab的值變化從而改變swiper標(biāo)簽的current屬性值變化,從而實現(xiàn)導(dǎo)航欄與之對應(yīng)內(nèi)容之間的切換。這是實現(xiàn)導(dǎo)航欄切換的其中一種方式,另外一種實現(xiàn)方式是采用WeUI(一套同微信原生視覺體驗一致的基礎(chǔ)樣式庫)的Navbar的思想。想體驗一下weui的視覺效果,請點擊WeUI,Navbar的wxml源碼

注意:由于weui最近更新了版本至v2.3.0,上述Navbar所涉及的版本是v2.0.1。

另一種實現(xiàn)具體代碼如下

<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>

這種實現(xiàn)方式的原理就是不是此分類頁面下的內(nèi)容就隱藏掉。但此方式并不能實現(xiàn)滑動切換菜單(可能是我太菜了,可根據(jù)需求選擇),因此采用第一種方式通過給swiper綁定bindchange屬性添加change事件,每當(dāng)用戶水平滑動頁面時,觸發(fā)change事件,監(jiān)聽change事件從事件參數(shù)中獲取current值,并賦值給currentTab,從而達(dá)到滑動切換菜單的效果。

可能會踩的“坑”

在你使用scroll-view和swiper時,會出現(xiàn)swiper-item中的內(nèi)容超出可視范圍,無法上下滑動的問題,如何解決呢?首先想到的是swiper高度自適應(yīng)

const conHeight = Math.ceil(navCont[idx].length / 2) * 290

idx是從事件參數(shù)中獲取的值,并且會賦值給currentTab。Math.ceil()是向上取整的方法,Math.round()四舍五入的方法并不合適,因為(navCont[idx].length / 列數(shù))只要除不盡就得往上加1。

高亮(被選中)菜單始終在可視區(qū)域內(nèi)

/**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  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
      })
    }
  }

導(dǎo)航欄粘性定位

1、監(jiān)聽scroll事件
// 實時監(jiān)控滾動距離頂部的位置
  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
      })
    }
  }

通過實時監(jiān)控距離頂部的位置當(dāng)大于某一臨界值時,就讓導(dǎo)航欄通過position:fixed屬性固定在某一位置,從而達(dá)到粘性定位效果。(添加類名實現(xiàn),否則則取消。缺點:不是太順滑,會閃現(xiàn)一下,需要優(yōu)化

臨界值你可以根據(jù)自己需要定義,也可以用微信小程序自帶的方法獲取。wx.createSelectorQuery().select()選取所需要定位的元素節(jié)點,然后分別獲取當(dāng)前元素節(jié)點距離頁面頂部的高度以及自身的高度。

/**
   * 生命周期函數(shù)--監(jiān)聽頁面顯示
   */
onShow: function () {
  wx.createSelectorQuery().select('#navfix')
    .boundingClientRect( rect =>{
      // console.log(rect) 
      this.setData({
        topheight: rect.top,
        height: rect.height
      })
    }).exec();
}
2、CSS3新屬性position:sticky

在所需要定位的元素節(jié)點的css中加上position:sticky;top:0;

top指的是當(dāng)前元素節(jié)點定位時距離頁面頂部的高度(位置),但此屬性有個缺點,兼容性不太好,但在微信小程序中還是可以的。有關(guān)更多此屬性的兼容性問題和“坑”,請看 position: sticky 詳解(防坑指南)這篇文章。

提出問題


以上兩種方法雖然實現(xiàn)了所需的導(dǎo)航菜單欄效果,但是數(shù)據(jù)這一塊都是全部一次性請求回來,然后根據(jù)數(shù)組下標(biāo)或隱藏來實現(xiàn)相關(guān)內(nèi)容的切換效果。但是一旦數(shù)據(jù)過于龐大,一次性請求全部數(shù)據(jù)回來就會造成瀏覽器性能消耗過大甚至頁面卡頓,顯然在實際情況中這是不可行的。實際情況中肯定是頁面切換到哪個菜單就會向后端去請求哪個菜單的相應(yīng)數(shù)據(jù)回來,那沒有服務(wù)器又該咋實現(xiàn)呢?


使用json-server

本文采用了一種“投機取巧”的辦法,使用json-server這個Node模塊來模擬一下數(shù)據(jù)的請求,json-server可以直接把一個json文件直接托管成一個簡易的web服務(wù)器。具體操作流程如下:

  1. 新建一個文件夾,然后npm install json-server安裝這個模塊。
  2. 在此文件夾下新建一個.json格式的文件。


    內(nèi)容格式
  3. 啟動該服務(wù),把package.json中的scripts改成"dev": "json-server db.json",然后使用命令npm run dev啟動即可(默認(rèn)啟動在3000端口上),如果此命令失效,換成.\node_modules.bin\json-server .\db.json,這個命令是一定有效的,db是文件名。
"scripts": {
    "dev": "json-server db.json"
}

至此,一個簡易的模擬服務(wù)器就搭建而成了,此時去前端頁面請求數(shù)據(jù)即可。

/**
   * 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
   */
  onReady: function () {
    wx.request({
      url: 'http://localhost:3000/navData', //菜單選項
      success: (res) => {
        // console.log(res.data)
        this.setData({
          navtabs: res.data
        })
      }
    })
  },
/**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    this.requestCart(this.data.currentTab) // 默認(rèn)顯示菜單
    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) { // 模擬向后端接口發(fā)起請求
    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
        })
      }
    })
  }

注意:這里可能會遇到數(shù)據(jù)請求不回來,這時一般是遇到了跨域問題。在詳情=>本地設(shè)置=>勾選不校驗合法域名即可解決。附:前端常見跨域解決方案

解決跨域

結(jié)語

本文(第一次寫)是一篇隨筆,算是微信小程序的入門篇,希望對各位有所幫助。如果文中有什么錯誤或者不足之處,歡迎大家斧正!如果各位對某處知識點有什么更好的建議,歡迎留言,前端小白在線求教^^!

如果你喜歡這篇文章或者可以幫到你,不妨點個贊吧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容