目录
01: 前言
数据
视图
小结
03: 抽离公用逻辑,封装系列动作
07: category数据缓存,覆盖初始数据
08: 小结
01: 前言
目前我们已经完成过一个 移动端的 navigationBar 了。对于 navigationBar 这个功能,我们还需要在 PC 端同样进行实现。通常我们把这样的一套功能称之为 响应式(多指响应式布局:一套样式在多端展示)。
当前项目不光是一个简单的响应式布局,而是一个复杂的前中台系统。在这样的前中台系统中,又应该如何应对这种响应式的问题呢?
在 样式复用、逻辑复用、代码可维护性 之间,又应该如何去进行权衡呢?
02: 响应式下navigtionBar实现方案分析
通常情况下 复杂功能的响应式处理,一般有三种处理方案:
1. 一套代码处理多端:
1. 优势:代码量相对较少
2. 劣势:耦合性强,不利于后期维护
2. 多套代码分别处理各端:
1. 优势:逻辑清晰
2. 劣势:可能会产生很多重复的逻辑
3. 结合以上两种方案,抽离公用逻辑,封装私有逻辑:
1. 优势:结合以上两点优势
2. 劣势:需要对业务和逻辑足够清楚
综合来看,肯定是第三种方式更好,所以咱们的 navigationBar 就通过第三种方式进行实现。
那么具体我们应该怎么去做呢?哪些是公用逻辑?哪些是私有逻辑?
我们知道一个功能由两部分组成:
1. 数据
2. 视图
数据
首先我们先来分析数据,双方(移动端和 PC 端)的数据是一样的。这一点是完全可以复用的。
目前咱们的数据是通过 src/views/main/components/navigation/index.vue 进行获取,然后进行传递的。目前情况是我们期望进行数据的复用,如果一直进行数据传递的话,未免有些过于复杂了。可以直接通过 vuex 来封装这一系列的 获取、切换 行为。
视图
双方的视图在展示中的逻辑具备较大差异,为了综合 可维护性,视图逻辑部分我们期望单独封装到各自的组件中进行处理。
小结
这样我们就分析好了 navigationBar 的公有和私有部分:
1. 数据为公有数据,可以在 vuex 中进行抽离处理。
2. 视图为私有部分,需要在各自的组件中进行单独处理。
03: 抽离公用逻辑,封装系列动作
- src
- - store
- - - modules
- - - - category.js
- - - index.js
// src/store/index.js
import { createStore } from 'vuex'
import getters from './getters'
import category from './modules/category'
const store = createStore({
getters,
modules: {
category
}
})
export default store
// src/store/getters.js
// 如果直接通过 store 来访问 category 模块下的 categorys 数据,未免变得过于麻烦。
// 通常情况下,可以创建一个 getters(简单访问)。
export default {
// 简单访问
// 使用:store.getters.categorys
categorys: (state) => state.category.categorys
}
// src/store/modules/category.js
import { ALL_CATEGORY_ITEM } from '@/constants'
import { getCategory } from '@/api/category'
/**
* 处理 navigationBar 中的数据 categorys
*/
export default {
// 独立作用域( vuex 中定义模块必须要做的东西)
namespaced: true,
state: () => {
return {
categorys: [ ALL_CATEGORY_ITEM ]
}
},
mutations: {
setCategorys(state, newCategorys) {
state.categorys = [ ALL_CATEGORY_ITEM, ...newCategorys ]
}
}
// 思路:封装一个动作,我们期望触发这样一个动作,可以完成一整套的 categorys 的赋值。
actions: {
/**
* 获取 category 数据,并自动保存到 vuex 中
*/
async useCategoryData(context) {
const { categorys } = await getCategory()
context.commit('setCategorys', categorys)
}
}
}
// 组件中使用 vuex 内的数据
// src/views/main/components/navigation/index.vue 中
<script setup>
import { useStore } from 'vuex'
const store = useStore()
store.dispatch('category/useCategoryData')
</script>
// src/views/main/components/navigation/mobile/index.vue 中
<template>
<li v-for="(item, index) in $store.getters.categorys">
</li>
</template>
04: PC端navigationBar私有逻辑处理
<li :class="{
'text-zinc-900 bg-zinc-200': currentCategoryIndex === index
}">
</li>
// 展开状态切换处理
const isOpenCategory = ref(false)
const triggerState = () => {
isOpenCategory.value = !isOpenCategory.value
}
// 选中状态处理
const currentCategoryIndex = ref(0)
const onItemClick = (index) => {
currentCategoryIndex.value = index
}
05: 分析 navigationBar 闪烁问题
问题描述:navigationBar 开始只展示 ‘全部’ 选项,获取完数据后才展示所有数据选项。 这样的话,刷新页面会出现 navigationBar 闪烁问题。
解决思路:
1. 让 categorys 数据项具备一个初始化数据。
2. 从服务端获取数据,替换初始化数据。
3. 为了防止初始化数据太老,我们把每次获取到的新数据,作为下一次的初始化数据。
06: 处理 navigationBar 闪烁问题
// src/constants/index.js
// categorys 的初始化数据
export const CATEGORYS_NOMAR_DATA = [
ALL_CATEGORY_ITEM,
{ id: 'web_app_icon', name: 'UI/UX' },
{ id: 'design', name: '平面' },
{ id: 'illustration', name: '插画/漫画' },
{ id: 'photography', name: '摄影' },
{ id: 'games', name: '游戏' },
{ id: 'anime', name: '动漫' },
{
id: 'industrial_design',
name: '工业设计'
},
{
id: 'industrial_design',
name: '建筑设计'
},
{
id: 'industrial_design',
name: '人文艺术'
},
{
id: 'industrial_design',
name: '家居/家装'
}
]
07: category数据缓存,覆盖初始数据
方案:每次从接口得到的数据,进行缓存(localstorage)。在下次运行时,把缓存的数据作为初始值。
想要实现这一步的功能,可以利用 vuex-persistedstate
vuex-persistedstate: 可以自动保存 vuex 中的数据到 localstorage。并且在下次开始的时候,自动读取这个数据到对应的 state 中。
接下来就利用这个库来实现我们的功能:
1. 安装 vuex-persistedstate
npm i --save vex-persistedstate@4.1.0
2. 在 src/store/index.js 中导入,并注册 plugin
import createPersistedState from 'vuex-persistedstate'
const store = createStore({
……
plugins: [
createPersistedState({
// 保存到 localStorage 中的 key
key: 'imooc-front',
// 需要保存的模块
paths: ['category']
})
]
})
export default store
3. 浏览器中存储的格式:
08: 小结
这里我们处理了 navigationBar 的响应式内容。
对于它的响应式内容处理,我们采取了 抽离公用逻辑、封装私有逻辑 的方案。
把 数据部分 抽离到了 vuex 中,并封装了一系列的动作进行统一处理。
把 视图逻辑 部分,在各个业务组件中进行了单独处理。