目录
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.jsimport { 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.categoryscategorys: (state) => state.category.categorys
}
// src/store/modules/category.jsimport { 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 中的 keykey: 'imooc-front',// 需要保存的模块paths: ['category']})]
})export default store
3. 浏览器中存储的格式:
08: 小结
这里我们处理了 navigationBar 的响应式内容。
对于它的响应式内容处理,我们采取了 抽离公用逻辑、封装私有逻辑 的方案。
把 数据部分 抽离到了 vuex 中,并封装了一系列的动作进行统一处理。
把 视图逻辑 部分,在各个业务组件中进行了单独处理。