1.效果預(yù)覽:

效果圖
2. 已實(shí)現(xiàn)功能:
- 點(diǎn)擊頂部工具欄,打開側(cè)欄
- 點(diǎn)擊關(guān)閉按鈕,關(guān)閉側(cè)欄
- 點(diǎn)擊頂部不同工具欄,切換側(cè)欄內(nèi)容
- 箭頭指向點(diǎn)擊位置
- 側(cè)欄入場和出場動畫
3. 功能分析
3.1 遮罩效果
將div的背景設(shè)置成黑色,透明度0.5,并設(shè)置z-index使其可以蓋在主體頁面之上
.cover {
position: fixed;
left: 0;
top: 50px;
width: 100%;
height: 100%;
background: #000000;
opacity: 0.5;
z-index: 500;
}
3.2 箭頭實(shí)現(xiàn)
- 通過css畫一個白色背景到三角形
- 通過 :style="{right:position} 控制right的位置實(shí)現(xiàn)其移動
- 通過調(diào)用"openSlider('message','130px')" 傳遞合適的值
<div class="pointer">
<div ref="triangle" class="triangle" :style="{right:position}" />
</div>
<style lang="scss" scoped>
.pointer {
height: 14px;
width: 100%;
background: transparent;
position: relative;
}
.triangle{
width: 0;
height: 0;
border: 7px solid transparent;
border-bottom-color: #fff ;
position: absolute;
top: 0;
}
</style>
3.3 動畫實(shí)現(xiàn)
- 通過 <transition> 標(biāo)簽將需要進(jìn)行動畫的元素進(jìn)行包裹, vue會添加如下到class
- v-enter:定義進(jìn)入過渡的開始狀態(tài)。在元素被插入之前生效,在元素被插入之后的下一幀移除。
- v-enter-active:定義進(jìn)入過渡生效時的狀態(tài)。在整個進(jìn)入過渡的階段中應(yīng)用,在元素被插入之前生效,在過渡/動畫完成之后移除。這個類可以被用來定義進(jìn)入過渡的過程時間,延遲和曲線函數(shù)。
- v-enter-to: 2.1.8版及以上 定義進(jìn)入過渡的結(jié)束狀態(tài)。在元素被插入之后下一幀生效 (與此同時 v-enter 被移除),在過渡/動畫完成之后移除。
- v-leave: 定義離開過渡的開始狀態(tài)。在離開過渡被觸發(fā)時立刻生效,下一幀被移除。
- v-leave-active:定義離開過渡生效時的狀態(tài)。在整個離開過渡的階段中應(yīng)用,在離開過渡被觸發(fā)時立刻生效,在過渡/動畫完成之后移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函數(shù)。
- v-leave-to: 2.1.8版及以上 定義離開過渡的結(jié)束狀態(tài)。在離開過渡被觸發(fā)之后下一幀生效 (與此同時 v-leave 被刪除),在過渡/動畫完成之后移除。
name屬性定義了需要調(diào)用動畫到前置,如我這里設(shè)置了name = "my",那么相應(yīng)的自定義動畫將前綴v改成my
@keyframes lightSpeedIn {
from {
transform: translate3d(100%, 0, 0);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
.my-enter-active {
transform-origin: left center;
animation: lightSpeedIn 0.4s;
}
@keyframes lightSpeedOut {
from {
opacity: 1;
}
to {
transform: translate3d(100%, 0, 0);
opacity: 0;
}
}
.my-leave-active {
transform-origin: left center;
animation: lightSpeedOut 0.4s;
}
3.4 側(cè)欄內(nèi)容切換
通過v-show控制當(dāng)前顯示的組件
<todo v-show="openIndex === 'todo'" />
<message v-show="openIndex === 'message'" />
4.代碼展示
rightslide.vue
<template>
<div>
<div v-show="openIndex" class="cover" />
<transition name="my">
<div v-show="openIndex" class="slider-container">
<div class="pointer">
<div ref="triangle" class="triangle" :style="{right:position}" />
</div>
<div class="slider-content">
<div>
<span @click="closeSlide">X</span>
</div>
<todo v-show="openIndex === 'todo'" />
<message v-show="openIndex === 'message'" />
</div>
</div>
</transition>
</div>
</template>
<script>
import Todo from '@/views/todo'
import Message from '@/views/message'
export default {
components: {
Todo,
Message
},
data() {
return {
show: true
}
},
computed: {
openIndex() {
return this.$store.state.rightSlider.openIndex
},
position() {
return this.$store.state.rightSlider.trianglePosition
}
},
methods: {
closeSlide() {
this.$store.dispatch('closeSlide')
},
handleClick: function() {
this.show = !this.show
}
}
}
</script>
<style lang="scss" scoped>
.cover {
position: fixed;
left: 0;
top: 50px;
width: 100%;
height: 100%;
background: #000000;
opacity: 0.5;
z-index: 500;
}
.slider-container {
width: 506px;
height: 100%;
top: 36px;
right: 0px;
position: fixed;
z-index: 1000;
}
.slider-content {
background: #fff;
height: 100%;
}
.pointer {
height: 14px;
width: 100%;
background: transparent;
position: relative;
}
.triangle{
width: 0;
height: 0;
border: 7px solid transparent;
border-bottom-color: #fff ;
position: absolute;
top: 0;
}
@keyframes lightSpeedIn {
from {
transform: translate3d(100%, 0, 0);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
.my-enter-active {
transform-origin: left center;
animation: lightSpeedIn 0.4s;
}
@keyframes lightSpeedOut {
from {
opacity: 1;
}
to {
transform: translate3d(100%, 0, 0);
opacity: 0;
}
}
.my-leave-active {
transform-origin: left center;
animation: lightSpeedOut 0.4s;
}
</style>
vuex
const state = {
openIndex: '', // 標(biāo)識側(cè)欄顯示的組件
trianglePosition: '' // 側(cè)欄指向按鈕距離右邊到距離
}
const mutations = {
changeIndex(state, { index, position }) {
state.openIndex = index
state.trianglePosition = position
},
closeSlide(state) {
state.openIndex = ''
},
setPosition(state, position) {
state.trianglePosition = position
}
}
const actions = {
changeIndex({ commit }, { index, position }) {
commit('changeIndex', { index, position })
},
closeSlide({ commit }) {
commit('closeSlide')
},
setPosition({ commit }, { position }) {
commit('setPosition', position)
}
}
export default {
state,
mutations,
actions
}
調(diào)用:
<template>
<div>
<span @click="openSlider('message','130px')">消息中心</span>
<span @click="openSlider('todo','210px')">待辦事項(xiàng)</span>
</div>
</template>
<script>
methods: {
openSlider(value, position) {
this.$store.dispatch('changeIndex', { index: value, position: position })
}
}
</script>