Vue3+TypeScript+Vuex实现侧边栏导航求助
Vue3(Composition API)+ TypeScript + Vuex 侧边栏导航功能问题
我正在使用Vue3(Composition API setup)、TypeScript和Tailwind CSS开发项目,想要实现基于Vuex+TypeScript的侧边栏导航功能,但目前遇到瓶颈,恳请大家帮忙。
package.json
{ "name": "kalys.io", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build" }, "dependencies": { "@heroicons/vue": "^1.0.6", "@tailwindcss/postcss7-compat": "^2.2.17", "autoprefixer": "^9", "chart.js": "^3.7.1", "core-js": "^3.6.5", "heroicons": "^1.0.6", "postcss": "^7", "query-string": "^7.1.1", "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17", "vue": "^3.0.0", "vue-chartjs": "^4.1.0", "vue-google-maps-typescript": "^0.1.4", "vue-router": "^4.0.0-0", "vueperslides": "^3.3.2", "vuex": "^4.0.0-0" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-typescript": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0", "@vue/cli-service": "~4.5.0", "@vue/compiler-sfc": "^3.0.0", "typescript": "~4.1.5", "vue-cli-plugin-tailwind": "^2.2.18" }, "browserslist": [ "> 1%", "last 2 versions", "not dead" ] }
store/index.ts
import { createStore, Store as VuexStore, CommitOptions, createLogger, DispatchOptions } from 'vuex' import { State, state } from './modules/state' import { Mutations, mutations } from './modules/mutations' import { Actions, actions } from './modules/actions' import { Getters, getters } from './modules/getters' export const store = createStore<State>({ plugins: process.env.NODE_ENV === 'development' ? [createLogger()] : [], state, mutations, actions, getters, modules: { } }) export function useStore() { return store as Store } export type Store = Omit< VuexStore<State>, 'getters' | 'commit' | 'dispatch' > & { commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>( key: K, payload: P, options?: CommitOptions ): ReturnType<Mutations[K]> } & { dispatch<K extends keyof Actions>( key: K, payload?: Parameters<Actions[K]>[1], options?: DispatchOptions ): ReturnType<Actions[K]> } & { getters: { [K in keyof Getters]: ReturnType<Getters[K]> } }
store/modules/state.ts
export type State = { theme: string; showSidebar: boolean; }; export const state: State = reactive({ theme: 'light', showSidebar: true });
store/modules/mutation-types.ts
export enum MutationTypes { SET_THEME = 'SET_THEME', SET_SHOWSIDEBAR = 'SET_SHOWSIDEBAR' }
store/modules/mutation.ts
import { MutationTree } from "vuex"; import { MutationTypes } from "./mutation-types"; import { State } from './state'; export type Mutations<S = State> = { [MutationTypes.SET_THEME](state: S, payload: string | boolean): void; [MutationTypes.SET_SHOWSIDEBAR](state: S, payload: boolean): void; } export const mutations: MutationTree<State> & Mutations = { [MutationTypes.SET_THEME](state: State, payload: string) { state.theme = payload, localStorage.theme = payload }, [MutationTypes.SET_SHOWSIDEBAR](state: State, payload: boolean) { state.showSidebar = payload }, }
store/modules/action-types.ts
export enum ActionTypes { INIT_THEME = 'INIT_THEME', toggle_theme = 'TOGGLE_THEME', toggle_sidebar = 'TOGGLE_SIDEBAR' }
store/modules/action.ts
import { MutationTypes } from './mutation-types'; import { ActionContext, ActionTree } from "vuex"; import { ActionTypes } from "./action-types"; import { Mutations } from "./mutations"; import { State } from "./state"; type ActionAugments = Omit<ActionContext<State, State>, 'commit'> & { commit<K extends keyof Mutations>( key: K, payload: Parameters<Mutations[K]>[1] ): ReturnType<Mutations[K]> } export type Actions = { [ActionTypes.INIT_THEME](context: ActionAugments): void; } export const actions: ActionTree<State, State> & Actions = { [ActionTypes.INIT_THEME]({ commit }) { const cachedTheme: boolean = localStorage.theme ? localStorage.theme : false; const userPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; if(cachedTheme) { commit(MutationTypes.SET_THEME, cachedTheme) } else if(userPrefersDark) { commit(MutationTypes.SET_THEME, 'dark') } else { commit(MutationTypes.SET_THEME, 'light') } }, [ActionTypes.toggle_theme]({ commit }) { switch (localStorage.theme) { case 'light': commit('SET_THEME', 'dark') break; default: commit('SET_THEME', 'light') break; } }, [ActionTypes.toggle_sidebar]({ commit }, state) { let sidebar = MutationTypes.SET_SHOWSIDEBAR ? false : true; commit(MutationTypes.SET_SHOWSIDEBAR, sidebar) } }
store/modules/getters.ts
import { GetterTree } from "vuex"; import { State } from './state'; export type Getters = { GET_THEME(state: State): string GET_SHOWSIDEBAR(state: State): boolean } export const getters: GetterTree<State, State> & Getters = { GET_THEME(state) { return state.theme; }, GET_SHOWSIDEBAR(state) { return state.showSidebar; }, }
Components/TheHeaderUpNav.vue
底部我引入了侧边栏和侧边栏切换按钮
<template> <div class="top-0 fixed lg:relative z-50 flex lg:justify-center justify-end items-center w-full py-1 lg:px-1 bg-gray-900 text-gray-300" > <div class="flex justify-between w-full text-xs md:text-sm lg:justify-around lg:gap-4 xl:gap-16" > <ul class="hidden lg:flex justify-around font-semibold py-2 text-xs xl:text-sm"> <li class="xl:mx-3" v-for="(navup, index) in navups" :key="index"> <router-link :to="navup.to" class="text-gray-300 px-3 py-2 rounded-sm hover:border-b-2 hover:border-white" > {{ navup.title }} </router-link> </li> </ul> <div class="flex items-center mx-5 sm:mr-20 lg:hidden"> <TheMobileButtonHumburger /> <div class="mx-3 flex xs:hidden">LOGO</div> </div> <div class="hidden items-center 2xl:flex">Пн-Пт. 9:00 - 17:30</div> <div class="flex mx-5 lg:mx-0"> <div class="lg:hidden flex items-center"> <MultiLanguage /> </div> <div class="flex items-center right-0 py-1"> <TheToggleTheme /> </div> </div> </div> </div> <TheMobileSidebar /> </template> <script lang="ts" setup> import TheMobileButtonHumburger from "./TheMobileButtonHumburger.vue"; import TheMobileSidebar from "./TheMobileSidebar.vue"; <script/>
Components/TheMobileSidebar.vue
<template> <div class="flex flex-col lg:hidden w-[300px] h-[100%] px-5 py-20 xs:py-10 text-gray-300 bg-black z-30 fixed bg-opacity-50 backdrop-filter backdrop-blur-lg" :class="{ '-left-full': !isShowSidebar }" > <ul class="w-full h-full" v-for="(navup, id) in navups" :key="id"> <li>{{ navup.title }}</li> </ul> </div> </template> <script lang="ts" setup> import { useStore } from "@/store"; import { ref } from "vue"; const store = useStore(); const navups = store.getters.GET_NAVUPS; let isShowSidebar = ref(store.getters.GET_SHOWSIDEBAR); //const theme = computed(() => store.getters.GET_THEME); // watch(isShowSidebar, (newSidebar, oldSidebar) => { // const toggleSidebar = store.getters.GET_SHOWSIDEBAR; // newSidebar === false // ? commit(MutationTypes.SET_SHOWSIDEBAR, true) // : commit(MutationTypes.SET_SHOWSIDEBAR, false); // }); // console.log(isShowSidebar); </script>
Components/TheMobileButtonHumburger.vue
<template> <button class="cursor-pointer border-2 border-white rounded-md" @click="toggleSidebar"> <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" > <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" /> </svg> </button> </template> <script lang="ts"> import { ActionTypes } from "@/store/modules/action-types"; import { defineComponent } from "vue"; import { useStore } from "vuex"; export default defineComponent({ name: "toggleSidebar", setup() { const store = useStore(); const toggleSidebar = () => { store.dispatch(ActionTypes.toggle_sidebar); console.log(store.getters.GET_SHOWSIDEBAR); }; return { toggleSidebar }; }, }); </script>
内容的提问来源于stack exchange,提问作者KaLJack
相关产品推荐
相关产品推荐

