序文
モバイル開発者としては、HTML を使用して開発されたアプリやネイティブ API を使用して開発されたアプリを誰もが多かれ少なかれ経験していると思います。それぞれに長所と短所がありますが、今回はネイティブ アプリの効果を参照し、同様のネイティブ効果を持つアプリケーションを vue.js フレームワークを使用して実装します。
プロジェクトの説明
Lianhua会員向けのオンライン返品プロセスの実装。主な機能ポイント:店舗の選択、位置決め、写真のアップロード、販売後の問い合わせ。実装計画:vue.js
エフェクトのプレビュー
プロジェクト中に遭遇した困難とその解決策
1. ネイティブページプッシュジャンプは右から左に入るアニメーション、ポップ操作は左から右にフェードアウトするアニメーションです。vue のルーターとトランジションを使用してこの効果を実現する方法を次に示します。
- すべてのページは vue-router で管理され、router-view にアニメーションが追加されます。
<transition :name="transitionName">
<keep-alive>
<router-view class="Router"></router-view>
</keep-alive>
</transition>
- 現在のページがプッシュ操作であるかポップ操作であるかを取得するにはどうすればよいですか? ブラウザのpopstateイベントをリッスンします。エントリ ファイルの Popstate イベントをリッスンして、現在のページがポップ操作であるかどうかをマークします。ポップ操作である場合は、属性 isBack を現在のルートに追加します。
window.addEventListener('popstate', function (e) {
router.isBack = true
}, false)
- ルートの isBack 属性をリッスンし、現在のページのプッシュ アニメーションまたはポップ アニメーションを設定します。この時点で、このアニメーション効果が実現されています。
watch: {
$route(to, from) {
// 切换动画
let isBack = this.$router.isBack
if (isBack) {
this.transitionName = 'slide-left'
} else {
this.transitionName = 'slide-right'
}
this.$router.isBack = false
}
}
2. ページのキャッシュと破棄の問題:
ネイティブ アプリのプッシュ操作はロードされたページをキャッシュし、ポップ操作はページを破棄します。H5 ジャンプは vue-router を使用して管理されます。ページ上で特別なキャッシュ処理が実行されない場合、h5 ページはプッシュ時に現在のページを破棄し、新しいページを再作成します。このエクスペリエンスは明らかにネイティブ エクスペリエンスほど良くありません。このネイティブ効果を実現するには、vue のページ キャッシュ メカニズムを使用します。
- keep-alive は Vue によって提供される抽象コンポーネントであり、コンポーネントをキャッシュしてパフォーマンスを節約するために使用されます。これには、よく使用される 2 つの属性 (include 属性と exclude 属性) があります。include 属性は、name 属性が xxx であるコンポーネントのみがキャッシュされることを示します (これはコンポーネントの名前であり、ルートの名前ではないことに注意してください)。exclude 属性は、name 属性が xxx であるコンポーネントを除き、他のすべてのコンポーネントがキャッシュされることを示します。ここでは、 include 属性を使用して、プッシュ操作用にページをキャッシュします。
1) ステップ 1: ページの name 属性を設定する必要があります。
export default new Router({
routes: [
{
path: '/',
name: 'Main',
component: Main,
meta: {
}
}
]
})
2) ステップ 2: main.js エントリ ファイルの router.isBack プロパティを監視して、プッシュかポップかを判断します。プッシュの場合は、ページの名前を配列に保存します。そうでない場合は、ページを削除します。同時に、この配列を vuex を通じて保存します。この配列に格納されているページは、キャッシュする必要があるページです。
router.beforeEach((to, from, next) => {
let isBack = router.isBack
let arr = store.state.keepAlivePages.slice()
if (isBack) {
// 从数组中移除
let index = arr.indexOf(from.name)
if (index !== -1) {
arr.splice(index, 1)
}
} else {
// 加入数组,push操作都要加入缓存数组
let index = arr.indexOf(from.name)
if (index === -1) {
arr.push(from.name)
}
let indexTo = arr.indexOf(to.name)
if (indexTo === -1) {
arr.push(to.name)
}
}
store.commit('SET_KEEPALIVEPAGES', arr)
next()
})
3) 最後に、メインページにキャッシュする必要があるページを設定します。
<transition :name="transitionName">
<keep-alive :include="keepAlivePages">
<router-view class="Router"></router-view>
</keep-alive>
</transition>
3. ネイティブインターフェースの横スライドリターン効果を実現するにはどうすればよいですか?
- ジェスチャーのスライドを判断することで、横スライドの復帰効果を得ることができますが、ネイティブの横スライドと比較すると、まだ効果に差があります。メインページのジェスチャー応答がスライダーのスライドに影響を与える可能性があることに注意してください。スライダーのスライド問題に影響を与えないように、修飾子 @touchmove.stop を使用してジェスチャー応答を防止できます。
<template>
<div id="app" v-on:touchstart="bodyTouchStart" v-on:touchmove="bodyTouchMove" v-on:touchend="bodyTouchEnd">
<transition :name="transitionName">
<keep-alive :include="keepAlivePages">
<router-view class="Router" :style="routerHeightStyle"></router-view>
</keep-alive>
</transition>
</div>
</template>
methods: {
bodyTouchStart(event) {
this.touchStartPoint = event.targetTouches[0].pageX
this.touchStartPointY = event.targetTouches[0].pageY
},
bodyTouchMove(event) {
// 实时计算distance
this.distance = event.targetTouches[0].pageX - this.touchStartPoint
this.distanceY = event.targetTouches[0].pageY - this.touchStartPointY
},
bodyTouchEnd() {
// 滚动视图可能会导致左滑,所以要判断y方向的距离
if (this.distance > 100 && Math.abs(this.distanceY) < 50) {
this.$refs.navigation.clickBack()
} else {
}
this.distance = 0
}
}
4. グローバル ナビゲーション バーを実装するにはどうすればよいですか? そしてナビゲーションバーのタイトルや戻るボタンの表示などの機能は?
- ルーティングを定義するときは、ナビゲーション バーを表示するかどうか、ナビゲーション バーのタイトル、戻るボタンを表示するかどうか、タブバーを表示するかどうかなど、メタを通じていくつかの構成可能なフィールドを定義する必要があります。
{
path: '/',
name: 'Home',
meta: {
title: '推荐', // 导航栏标题
showTabbar: true, // 是否显示Tabbar
showBack: false
},
component: resolve => require(['../views/home.vue'], resolve)
},
- 次に、メイン ページ (通常は App.vue) でナビゲーション バーとその他の構成を設定します。
<template>
<div id="app" v-on:touchstart="bodyTouchStart" v-on:touchmove="bodyTouchMove" v-on:touchend="bodyTouchEnd">
<!--nav-->
<navigation
ref="navigation"
v-if="!$route.meta.hiddenNav"
:title="navTitle"
:showBack="showBack"
:background="$route.meta.navBackground"
:showLine="$route.meta.showLine"></navigation>
<transition :name="transitionName">
<keep-alive :include="keepAlivePages">
<router-view class="Router" :style="routerHeightStyle"></router-view>
</keep-alive>
</transition>
<tabBar v-show="$route.meta.showTabbar"></tabBar>
</div>
</template>
- 上記のデモでは、ナビゲーション バーのタイトルは変数 navTitle であることに注意してください。なぜ変数を通じて値を取得する必要があるのでしょうか。これは、たとえば、製品詳細ページに入るときに、ナビゲーション バーのタイトルがサーバーから返された製品名である場合、ページがレンダリングされており、メタを通じてタイトルを設定するというシナリオがあるためです。効果はありません。したがって、現在の計画では、通知を使用してタイトルを渡し、それを割り当てることです。
mounted() {
// 动态改变详情页面的title
this.bus.$on('changeDetailTitle', (title) => {
this.$set(this.$route.meta, 'title', title)
this.navTitle = title
})
}
概要
確かにネイティブ アプリのエクスペリエンス効果は H5 のエクスペリエンス効果よりも優れていますが、上記のさまざまな効果の最適化により、H5 プロジェクトはネイティブ エクスペリエンス効果に近づけることができるようになりました。特にページ キャッシュは非常に重要です。
最後にレンダリングを貼っておきますが、ポップ後のページ内容にご注目ください、オリジナルとかなり似ているでしょうか…。
24.gif
ちょっとした贈り物を持って建州で私に従ってください
何も理解できない場合は、私の個人用 WeChat 公開アカウントをフォローしてコミュニケーションをとることができます。フロントエンドの詳細と学習体験については、公式アカウントをフォローしてください。ビデオチュートリアルも利用できます。
著者: Darren151666
リンク: https://www.jianshu.com/p/55cc606c3f9f
出典: Jianshu
Jianshu の著作権は著者に帰属し、いかなる形式の転載についても、著者に連絡して許可を得て、出典を明示してください。