HarmonyOS ArkUI之自定義組件側(cè)滑菜單(JS)
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
前言
鴻蒙這次API7更新除了新增TS聲明式開發(fā)之外,還有JS開發(fā)也增加了很多API,JS開發(fā)自定義組件越來越方便了。
本項目基于ArkUI中JS擴展的類Web開發(fā)范式,關(guān)于語法和概念直接看官網(wǎng)官方文檔地址:
基于JS擴展的類Web開發(fā)范式1 基于JS擴展的類Web開發(fā)范式2
本文介紹最新出的插槽用法,實現(xiàn)側(cè)滑菜單、支持兩種風(fēng)格、支持快速滑動打開關(guān)閉。
ArKUI系列文章
- 【HarmonyOS ArkUI之仿微信朋友圈圖片預(yù)覽】
- 【HarmonyOS ArkUI之仿微信圖片選擇】
- 【HarmonyOS ArkUI之自定義組件側(cè)滑菜單(JS)】
效果演示
風(fēng)格一:內(nèi)容頁在菜單上面風(fēng)格二:內(nèi)容頁在菜單下面


主要知識點
觸摸事件、自定義組件父子組件傳遞參數(shù)、api=7新出的slot插槽
實現(xiàn)思路
自定義組件的邏輯都在此目錄下:entry/js/default/pages/drawer
主要使用onTouch相關(guān)事件,滑動改變菜單布局或內(nèi)容布局的left偏移量,手指抬起使用動畫完成偏移量
1、onTouch相關(guān)事件
只貼出了關(guān)鍵代碼
- /**
- * 觸摸按下
- */
- onTouchStart(event) {
- // 記錄首次按下的x坐標(biāo)
- this.pressX = event.touches[0].localX
- // 記錄上次的x坐標(biāo)
- this.lastX = this.pressX
- .....
- },
- /**
- * 觸摸移動
- */
- onTouchMove(event) {
- // 當(dāng)前x坐標(biāo)
- let localX = event.touches[0].localX
- // 計算與上次的x坐標(biāo)的偏移量
- let offsetX = this.lastX - localX;
- // 記錄上次的x坐標(biāo)
- this.lastX = localX
- // 累計偏移量
- this.offsetLeft -= offsetX
- // 設(shè)置偏移量的范圍
- .....
- }
- **
- * 觸摸抬起
- */
- onTouchEnd(event) {
- ......
- // 手指抬起,根據(jù)情況,判斷toX的值,也就是判斷關(guān)閉或開啟菜單的情況
- // 當(dāng)移動偏移量大于菜單一半寬度,完全打開菜單,否則反之
- if (this.offsetLeft > this.menuWidth / 2) {
- toX = this.menuWidth
- } else {
- toX = 0
- }
- ......
- // 開啟動畫
- this.startAnimator(toX)
- }
- /**
- * 開啟動畫
- */
- startAnimator(toX) {
- // 設(shè)置動畫參數(shù)
- let options = {
- duration: ANIMATOR_DURATION, // 持續(xù)時長
- fill: 'forwards', // 啟停模式:保留在動畫結(jié)束狀態(tài)
- begin: this.offsetLeft, // 起始值
- end: toX // 結(jié)束值
- };
- // 更新動畫參數(shù)
- this.animator.update(options)
- // 監(jiān)聽動畫值變化事件
- this.animator.onframe = (value) => {
- this.offsetLeft = value
- this.changeMenuOffsetLeft()
- }
- // 開啟動畫
- this.animator.play()
- },
2、showStyle
0 第一種樣式下,解決設(shè)置z-index之后菜單界面在內(nèi)容下面,但點擊事件卻還在內(nèi)容上面的問題。
初始化設(shè)置left偏移量
動畫結(jié)束,判斷菜單是否關(guān)閉,關(guān)閉直接設(shè)置菜單偏移量為負的菜單寬度
注意:目前使用插槽之后,預(yù)覽器不走生命周期方法:onShow。
- export default {
- // 使用外部傳入
- props: ['showStyle'],// 顯示樣式:0菜單在下面,1菜單在上面
- ......
- }
- **
- * 界面顯示
- */
- onShow() {
- .....
- // 設(shè)置菜單偏移量為負的菜單寬度,為了解決z-index設(shè)置后,菜單界面到內(nèi)容下面,
- // 事件還停留到內(nèi)容上面,導(dǎo)致點擊菜單區(qū)域,響應(yīng)的還是菜單點擊事件
- this.menuOffsetLeft = -this.menuWidth
- }
3、使用具名插槽封裝
- <div id="drawer-container" class="drawer-container" on:touchstart="onTouchStart"
- on:touchmove="onTouchMove" on:touchend="onTouchEnd">
- <div class="drawer-content" style="left : {{ showStyle == 0 ? offsetLeft : 0 }} px;
- z-index : {{ zIndexContent }};" on:click="closeMenu">
- <!--具名插槽,根據(jù)名稱加入對應(yīng)的插槽中-->
- <slot name="content"></slot>
- </div>
- <stack class="drawer-menu" style="z-index : {{ zIndexMenu }};">
- <div class="drawer-menu-background" style="opacity : {{ menuBgOpacity }};"></div>
- <div style="width : {{ menuWidth }} px; height : 100%;
- left : {{ menuOffsetLeft }} px;" on:click="clickMenu">
- <!--具名插槽,根據(jù)名稱加入對應(yīng)的插槽中-->
- <slot name="menu"></slot>
- </div>
- </stack>
- </div>
4、index頁面使用
- <!--引入自定義組件-->
- <element name='drawer' src='../drawer/drawer.hml'></element>
- <div class="container">
- <!--通過傳值設(shè)置樣式-->
- <drawer show-style="0">
- <!--根據(jù)名稱加入對應(yīng)的插槽中-->
- <div slot='content' class="content-layout">
- <div class="title-bar">
- <text>主頁</text>
- </div>
- <div class="mainpage-content">
- <text class="content1">我是內(nèi)容頁面</text>
- <text class="content2">V1.0.0</text>
- <text class="content2">梁迪迪</text>
- </div>
- </div>
- <div slot='menu' class="menu-layout">
- <div class="my-info">
- <image src="common/images/head_photo.png"></image>
- <text>登錄 | 注冊</text>
- </div>
- <div class="menu-content">
- <div for="{{ listMenu }}" tid="{{ $item.id }}" on:click="menuSkip({{ $item.name }})">
- <image src="{{ $item.icon }}"></image>
- <text>{{ $item.name }}</text>
- </div>
- </div>
- </div>
- </drawer>
- </div>
結(jié)尾
每天進步一點點、需要付出努力億點點。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)