故事: 其实很久一段时间想通过一个简单的项目学习vuex以及vue组件里面的细节知识点 因此在工作之余写了一个非常简单以及粗暴的案例来加深记忆,案例涉及到 vuex
localstorage
登录拦截
等
vuex模块化的使用:
安装vuex 并且建立vuex文件的结构
npm install vuex --save复制代码
在src文件夹下新建 store夹 然后新建index.js type.js 以及子文件夹modules 目录结构如图
type.js 定义常量 使用常量代替mustation事件类型;
modules 文件夹里的global.js ,user.js 分别是我定义的模块化文件 分别代表 账户中心 和全局vuex模块,每个模块都有自己的 state actions getters mutations;
index.js 挂载store如下
--------------index.jsimport Vue from 'vue'import Vuex from 'vuex'import user from './modules/user'import global from './modules/global'Vue.use(Vuex)const store = new Vuex.Store({ modules: { user, global }})export default store;复制代码
new Vuex.Store({}) 表示创建一个Vuex实例,通常情况下,他需要注入到Vue实例里. Store是Vuex的一个核心方法,字面上理解为“仓库”的意思。Vuex Store是响应式的,当Vue组件从store中读取状态(state选项)时,若store中的状态发生更新时,他会及时的响应给其他的组件(类似双向数据绑定) 而且不能直接改变store的状态,改变状态的唯一方法就是,显式地提交更改(mutations选项)
type.js 如下
-------------------------type.js/** * * @authors Your Name (you@example.org) * @date 2018-08-27 19:46:08 * @version $Id$ *//*user 用户*/export const IS_LOGIN = 'IS_LOGIN' //设置用户信息/*global全局*/export const GLOBAL_BGCOLOR = 'GLOBAL_BGCOLOR' //设置主题颜色 复制代码
user.js 如下
-----------------------------user.js/** * * @authors Your Name (you@example.org) * @date 2018-08-27 19:55:37 * @version $Id$ */import * as types from '../type'import ajax from '@/fetch/index'const state = { isLogin: false}const actions = { isLogin({ commit },res) { commit(types.IS_LOGIN, res) }}const getters = { isLogin: state => state.isLogin,}const mutations = { [types.IS_LOGIN](state, res) { state.isLogin = res.isLogin }}export default { state, actions, getters, mutations}复制代码
global.js 如下
---------------global.js/** * * @authors Your Name (you@example.org) * @date 2018-08-28 17:54:40 * @version $Id$ *//*通用配置*/import * as types from '../type'import {Local} from '@/storage'const state = { bgColor: Local.get('bgColor') || "blue"}const actions = { setbgColor({commit},color) { commit(types.GLOBAL_BGCOLOR,color) }}const getters = { bgColor: state => state.bgColor}const mutations = { [types.GLOBAL_BGCOLOR](state, color) { state.bgColor = color Local.set('bgColor',color) }}export default { state, actions, getters, mutations}复制代码
在main.js 导入store下的index.js文件 并且注册
--------------------main.jsimport Vue from 'vue'import App from './App'import router from './router/permission'import store from './store'Vue.config.productionTip = false/*全局组件*/import commonComponents from './common-components.js'Vue.use(commonComponents)/* eslint-disable no-new */new Vue({ el: '#app', router, store, components: { App }, template: ''})复制代码
Hello.vue 如下
复制代码
注意:this.$store.dispatch('setbgColor',color) 表示分发actions 或者通过辅助函数 mapActions 如下
methods: { ...mapActions({ setTheme: "setbgColor" })}复制代码
这里会默认传参数color
同样 this.$store.getters.isLogin 可以通过辅助函数 mapGetters 如下
computed: { ...mapGetters([ 'isLogin' ])}复制代码
这里通过辅助函数将 this.isLogin 映射到 this.$store.getters.isLogin 如下
methods: { getLogin() { console.log(this.isLogin) console.log(this.$store.getters.isLogin) }}复制代码
知识点:
页面中通过localStorage 实现换肤功能
在src目录下新建 storage文件夹用来封装 localStrorage 和 cookie 等
-------------------------------index.jsconst ls = window.localStorage;export const Local = { get(key) { if (key) return JSON.parse(ls.getItem(key)) return null }, set(key, val) { const setting = arguments[0] if (Object.prototype.toString.call(setting).slice(8, -1) === 'Object') { for (const i in setting) { ls.setItem(i, JSON.stringify(setting[i])) } } else { ls.setItem(key, JSON.stringify(val)) } }, remove(key) { ls.removeItem(key) }, clear() { ls.clear() }}复制代码
完成toast组件,以及组件管理
--------------------Toast/index.vue复制代码 { {msg}}
----------------------------------Toast/index.js/** * * @authors Your Name (you@example.org) * @date 2018-08-30 14:26:05 * @version $Id$ */import Vue from 'vue'import ToastComponent from './index.vue'let initComponent = null;let timer = null;const merge = ($data, option) => { for ( let prop in option) { if ($data.hasOwnProperty(prop)) { $data[prop] = option[[prop]] } }};/*构造器*/let ToastConstructor = Vue.extend(ToastComponent);const Toast = (option = {}) => { if(initComponent) { initComponent.show = true if (timer) { clearInterval(timer) } initComponent.$el.removeEventListener('transitionend', initComponent.destroyeInitComponent) }else { /*通过 new 创建组件*/ initComponent = new ToastConstructor({ el: document.createElement('div') }); //如果没有 挂载div 可以 initComponent.$mount(); if(typeof option !== 'object') { initComponent.msg = option; }else { merge(initComponent.$data, option) } document.querySelector(option.container || 'body').appendChild(initComponent.$el); } Vue.nextTick(() => { initComponent.show = true timer = setTimeout(() => { initComponent.close() },2000) }) return new Promise((resolve,reject) => { resolve() })}ToastConstructor.prototype.close = function() { this.show = false; this.$el.addEventListener('transitionend', this.destroyeInitComponent.bind(this))}/*销毁组件*/ToastConstructor.prototype.destroyeInitComponent = function() { initComponent = null; this.$destroy(true) this.$el.removeEventListener('transitionend', this.destroyeInitComponent) this.$el.parentNode.removeChild(this.$el)}export default Toast复制代码
新建common-components.js
----------------------------------common-components.js/** * * @authors Your Name (you@example.org) * @date 2018-08-30 14:19:20 * @version $Id$ */import Toast from '@/components/Toast'const install = Vue => { //Vue.prototype.$toast = Toast Vue.$toast = Toast; Vue.prototype.$toast = Vue.$toast}export default install复制代码
在main.js中引用
/*全局组件*/import commonComponents from './common-components.js'Vue.use(commonComponents) 复制代码
调用 toast
Vue.prototype.$toast("请先登录") .then(() => { console.log('回调') })复制代码
登陆拦截
在 router下新建 permission.js
/** * * @authors Your Name (you@example.org) * @date 2018-08-29 15:05:17 * @version $Id$ */import store from '../store'import Vue from 'vue'import { router } from './index'router.beforeEach((to, from, next) => { if(to.meta.login) { if(store.state.user.isLogin == "1") next() else { Vue.prototype.$toast("请先登录") .then(() => { console.log('回调') }) return } }else if(to.meta.page) { next() } })router.afterEach((to, from) => { document.title = to.name})export default router复制代码
axios 封装
/** * * @authors Your Name (you@example.org) * @date 2018-08-28 10:04:37 * @version $Id$ */import axios from 'axios';import qs from 'qs'axios.defaults.withCredentials = true axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';// http request 拦截器 发送时axios.interceptors.request.use(config => { return config}, err => { return Promise.reject(err)})// http response 拦截器 相应时axios.interceptors.response.use(response => { console.log(response.data.result) return response}, err => Promise.resolve(err.response))const get = function (url, params) { return new Promise((resolve, reject) => { axios({ method: "GET", url, params }).then(function(res){ resolve(res); }) })}const post = function (url, params) { return new Promise((resolve, reject) => { axios({ method: "POST", url, params }).then(function(res){ resolve(res); }) })}export default { get, post}复制代码