本文所使用技术, 无经验者请先阅读学习vuejs
1 2 3 4
| @vue/cli 4.1.1 vue 2.6.10 typescript 3.5.3 shards-vue 1.0.7
|
准备工作
■ 利用cli创建项目后,安装shards-vue
■ 修改shims-vue.d.ts
添加
1
| declare module 'shards-vue';
|
■ 修改main.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; import ShardsVue from 'shards-vue';
import 'bootstrap/dist/css/bootstrap.css'; import '@/scss/shards-dashboards.scss'; import '@/assets/scss/date-range.scss';
import Default from '@/layouts/Default.vue';
Vue.config.productionTip = false;
Vue.use(ShardsVue);
Vue.component('default-layout', Default);
new Vue({ router, store, render: h => h(App) }).$mount('#app');
|
这里先注册一个布局组件
在下文中,会介绍如何创建
■ 创建.prettierrc
1 2 3 4 5 6 7
| { "printWidth": 120, "tabWidth": 2, "useTabs": false, "singleQuote": true, "proseWrap": "preserve" }
|
创建layout
■ 修改App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <component :is="layout"> <router-view /> </component> </template>
<script> import { Component, Vue } from 'vue-property-decorator';
@Component({}) export default class App extends Vue { get layout() { return 'default-layout'; } } </script>
|
原生写法中computed
所返回的对象皆为只读,对应class
写法的话即get attributeName
■ 创建src/layouts/Default.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <d-container fluid> <d-row> <!-- Main Sidebar -->
<d-col class="main-content offset-lg-2 offset-md-3 p-0" tag="main" lg="10" md="9" sm="12"> <!-- Main Navbar -->
<!-- Content --> <slot />
<!-- Main Footer --> </d-col> </d-row> </d-container> </template>
<script> import { Component, Vue } from 'vue-property-decorator';
@Component({}) export default class DefaultLayout extends Vue {} </script>
|
先预留main slidebar navbar footer,待会儿我们进行填充时,放置在对应注释下方即可
状态管理
■ 介绍背景
传统开发中声明了多个全局并分布于各个文件总变量来管理数据
表面上看不出问题,但一旦出现,会发现难以调试,随着项目的增大,更是一场灾难,达到了解决一个Bug生成10个bug的效果
状态管理实际上是以单一全局变量来管理数据,这样我们可以只追踪一个变量
这样还不够,即使如此,深层次的结构仍然难以管理,并且程序仍然难以预知对象是否发生了更改,更改的位置在何处
为了解决上述问题,每次某个深度的对象结构发生改变我们就重新生成一个变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let data = { posts: { a: [], b: [1, 2, 3] }, list: [1, 2, 3] };
data = { ...data, posts: { a:[2, 3, 4] b:[1, 2, 3] }, };
|
可以看出,这样写还是有问题,data.posts.b
并没有更新,这里却更新了,所以还是需要引用覆盖用来的data.posts.b
这样看好像又没有问题,但一旦对象属性随着项目深入而增长,每次更新一个变量就要做很多重复工作,而这难免会有疏漏,仍然难以追踪调试
解决这些问题后,还有异步带来的问题,多个异步操作等带来的增删改等问题都容易出错,难以把握
于是针对状态管理出现了很多方案。其中较为有名的是redux
。
而vuex
和redux
类似, 都拆分为type
action
reducer
。只是命名不一样,究其原理几乎一样。
vuex
更像是进一步封装后的redux
。
redux
入门简单,深入却很难,因为前段自由性太强,既然使用框架,为的就是规范团队开发,让大家统一规范,带来开发的便捷
下面开始介绍vuex
的用法
定义状态树,其中post
app
user
为三个状态模块,分别管理应用的三个模块
store/index.ts
1 2 3 4 5 6 7 8 9 10 11 12
| import Vue from 'vue'; import Vuex from 'vuex';
import posts from '@/store/posts'; import app from '@/store/app'; import user from '@/store/user';
Vue.use(Vuex);
export default new Vuex.Store({ modules: { posts, app, user } });
|
使用
1 2 3 4 5 6 7
| import store from './store';
new Vue({ router, store, render: h => h(App) }).$mount('#app');
|
状态模块定义
每个模块必须包含state
actions
mutations
三个对象, namespaced
推荐使用,在组件发起dispatch
相关代码中易于阅读和理解结构
state
是状态定义,这里设置初始值
actions
状态不应该直接修改,直接修改的情况容易引起混乱,无法判定是否已经更新等未知问题
mutations
接收由action
中commit
过来的修改值,修改状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import sidebarItems from '@/store/data/sidebar-items';
const state = { sidebar: { items: sidebarItems, visible: true, hideLogoText: false, stickyTop: true } };
const actions = { toggleSidebar({ commit, state: { sidebar } }: any) { const { visible } = sidebar; commit('toggleSidebar', !visible); } };
const mutations = { toggleSidebar(state: any, value: boolean) { state.sidebar.visible = value; } };
export default { namespaced: true, state, actions, mutations };
|
组件中使用状态
template
1 2 3 4 5
| <nav class="nav d-md-none d-lg-none" v-if="islogin"> <a href="#" @click="toggleSidebar" class="nav-link nav-link-icon toggle-sidebar d-md-inline d-lg-none text-center"> <i class="material-icons"></i> </a> </nav>
|
script
通过vuex-class
方便引入state
及action
,通过改变islogin
状态值控制页面元素
1 2 3 4 5 6 7 8
| import { Component, Vue } from 'vue-property-decorator'; import { State, Action } from 'vuex-class';
@Component({}) export default class NavBarNav extends Vue { @State(states => states.user.islogin) islogin; @Action('app/toggleSidebar') toggleSidebar; }
|
持续更新