通過專案梳理vuex模組化 與vue元件管理

李赫feixuan發表於2018-09-02

故事: 其實很久一段時間想通過一個簡單的專案學習vuex以及vue元件裡面的細節知識點 因此在工作之餘寫了一個非常簡單以及粗暴的案例來加深記憶,案例涉及到 vuex  localstorage  登入攔截  


vuex模組化的使用:

安裝vuex 並且建立vuex檔案的結構

npm install vuex --save複製程式碼

在src資料夾下新建 store夾 然後新建index.js  type.js 以及子資料夾modules 目錄結構如圖

通過專案梳理vuex模組化 與vue元件管理

type.js 定義常量 使用常量代替mustation事件型別;

modules 資料夾裡的global.js ,user.js 分別是我定義的模組化檔案 分別代表 賬戶中心 和全域性vuex模組,每個模組都有自己的 state  actions  getters  mutations;

index.js 掛載store如下

--------------index.js
import 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.js
import 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: '<App/>'
})複製程式碼

Hello.vue 如下

<template>
 <div>
  <button type="button" style="margin-top: 20px" @click="getLogin">獲取登入狀態</button><br/>
  <button type="button" style="background:#f60;margin-top: 20px;color:#fff;" @click="setTheme('orange')">設定主題f60</button><br/>
  <button type="button" style="background:#2577e3;margin-top: 20px;color:#fff;" @click="setTheme('blue')">設定主題f60</button><br/>

  <router-link tag="div" to="/user">
   <button type="button" style="margin-top: 20px">去賬戶中心</button>
  </router-link>
 </div>
</template>

<script>
 import ajax from '@/fetch/index'
 import {Cookie} from '@/storage/index'
 import { mapState, mapGetters ,mapActions,mapMutations} from 'vuex'
 export default {
  data() {
   return {
   }
  },
  mounted() {
  },
  methods: {
   getLogin() {
    console.log(this.isLogin)
    //console.log(this.$store.getters.isLogin)
   },
   setTheme(color) {
    this.$store.dispatch('setbgColor',color)
    //console.log(this.$store.getters.bgColor)
   }
  },
  created() {
   const _this = this;
   
   ajax.get('apis/register/wap/member/check',{})
     .then(function(res) {
      _this.$store.dispatch('isLogin',{"isLogin": res.data.result.isLogin})
     })
  },
  computed: {
   ...mapGetters([
     'isLogin'
    ])
  }
 }
</script>

<style>
 button {
  border: none;
  width: 120px;
  height: 40px;
  cursor: pointer;
  outline: none;
 }
 .button {
  display:inline-block;
  background:#f60;margin-top: 20px;
  color:#fff;
  height:40px;
  width:120px;
  text-decoration: none;
  line-height: 40px;
  text-align: center;
 }
</style>複製程式碼

注意: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.js
const 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

<template>
	<transition name="fade">
		<div class="toast-wrap" v-show="show">
			<span>{{msg}}</span>
		</div>
	</transition>
</template>

<script>
	export default {
		data() {
			return {
				msg: "",
				show: true
			}
		},
		methods: {

		}
	}

</script>


<style>
 	.fade-enter-active, .fade-leave-active {
		transition: opacity .3s;
	}
	.fade-enter, .fade-leave {
	 	opacity: 0;
	}
	.toast-wrap {
		position: fixed;
		max-width: 80%;
		left: 50%;
		top:50%;
		padding: 20px;
		border-radius: 10px;
		text-align: center;
		transform: translate3d(-50%,-50%,0);
		color: #fff;
		background: rgba(0, 0, 0, 0.7);
		font-size: 14px;
	}
</style>

複製程式碼

----------------------------------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
}

複製程式碼


相關文章