vue、vuex、vue-router、vue-i18n、vue-http實踐
參考資料:
- Vue.js 教程
- Vue.js 官方文檔
- Vuex 文檔
- 震驚!喝個茶的時間就學會了vuex
- 使用vue-i18n實現多語言
- Vuex的Getter學習
- Vue-自帶vue-resource插件實現http請求
專門寫了個demo來做vue框架筆記,demo是基於VuexExplanation項目(Vuex項目)實現狀態管理,糅合vue-router-and-multi-lang項目(vue-i18n結合vue-router)實現多語言和路由跳轉,再加入vue-http來實現數據獲取。demo的github地址如下:vuexlearning。
環境準備
git拉取代碼後,執行cnpm install
後,執行npm run dev
成功後,可以在瀏覽器中查看到項目運行效果:
代碼講解
項目的主要代碼在src目錄,static/lang目錄存放的是多語言文件,static/data目錄存放的是http請求的json文件。
store.js
store.js定義了state狀態內容,計算訂餐總價totalPrice
、訂餐總量totalNum
,根據商品下標獲取商品信息getGoodById
,定義增減訂餐的方法,定義了添加商品的方法。
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// state 類似 data //這裏面寫入數據
name: '極品粥鋪', //店鋪名
minPrice: '20', //起送價格
deliveryPrice: '4', // 配送費
goods: [ //店鋪商品
{
"id": "0000001",
"name": "皮蛋瘦肉粥",
"price": 10,
"oldPrice": "12",
"description": "鹹粥",
"sellCount": 229,
"rating": 100,
"image": require('../assets/pdsrz.jpg'),
"num": 0,
"info": "皮收瘦肉粥是一種營養豐富的粥品,這種粥的主要食材是大米、瘦肉和皮蛋,它們的都含有大量的蛋白質和多種維生素以及適量的脂肪和微量元素,人們食用以後能快速把這些營養吸收,滿足身體各器官對不同營養成分的需要。",
},
...
]
},
getters: {
// getters 類似 computed
// getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被重新計算。
// Getter 接受 state 作爲其第一個參數
// getter 在通過屬性訪問時是作爲 Vue 的響應式系統的一部分緩存其中的。
totalPrice(state){
let totalP = 0;
state.goods.forEach((val, index) => {
totalP += val.num * val.price;
});
if (totalP > 0) {
totalP = parseFloat(totalP) + parseInt(state.deliveryPrice)
} else {
totalP = 0;
}
return totalP.toFixed(2);
},
totalNum(state){
let totalN = 0;
state.goods.forEach((val, index) => {
totalN += val.num;
})
return totalN;
},
// getter 在通過方法訪問時,每次都會去進行調用,而不會緩存結果。
getGoodById: (state) => (index) => {
return state.goods[index];
},
},
mutations: {
// mutations 類似methods
// 寫方法對數據做出更改(同步操作)
goodsReduce(state, index){
if (state.goods[index].num > 0) {
state.goods[index].num -= 1;
}
},
goodsAdd(state, index){
state.goods[index].num += 1;
},
insertGood(state, good){
state.goods.push(good);
}
},
actions: {
// actions 類似methods
// 寫方法對數據做出更改(異步操作)
// Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象
insertGood(context, good){
context.commit('insertGood', good);
}
// // 可簡寫爲
// insertGood({commit},good){
// commit('insertGood',good);
// } }
})
main.js
main.js創建Vue根實例,導入公共樣式,注入狀態管理store、路由跳轉router、多語言vueI18n、Http請求vueResoure。
import Vue from 'vue';
import App from './App';
import store from "@/store/store.js";
import "@/style/init.css";
import router from '@/router.js'
import VueI18n from 'vue-i18n'
import LangEn from '../static/lang/en'
import LangZhCHS from '../static/lang/zhCHS'
import VueResource from 'vue-resource'
Vue.config.productionTip = false
Vue.use(VueI18n)
Vue.use(VueResource)
// i18n多語言只能在Vue實例使用
const i18n = new VueI18n({
locale: 'zhCHS', // 語言標識
messages: {
'en': LangEn,
'zhCHS': LangZhCHS
}
})
/* eslint-disable no-new */
new Vue({
el: '#app',
i18n,//注入i18n組件
router,//注入router組件
store,//注入store組件
components: {App},
template: '<App/>'
})
router.js
router.js定義了頁面跳轉的路由配置。
import Vue from 'vue'
import Router from 'vue-router'
import List from '@/page/list'
import Detail from '@/page/detail'
Vue.use(Router)
// 定義路由
export default new Router({
mode: 'history',
base: '/cnycard2018/',
routes: [// 每個路由應該映射一個組件
{
path: '/:lang',
name: 'list',
component: List,
},
{
path: '/:lang/detail/:index',
name: 'detail',
component: Detail
},
{// 設置默認路由
path: '*',
redirect: "/zhCHS"
},
]
})
App.vue
App.vue設置了模板頁面結構,頭部和尾部不變,通過路由跳轉修改中間內容。App.vue設置了多語言切換的方法changeLanguage
。
<template>
<div id="app">
<section id="goods" class="goods-box">
<oHeader class="goods-header" :title="name" @changeAppLocale="changeAppLocale" v-bind:lang="lang"></oHeader>
<router-view v-bind:lang="lang"></router-view>
<oFooter></oFooter>
</section>
</div>
</template>
<script>
import oHeader from "@/components/Header.vue";
import oFooter from "@/components/Footer.vue";
import {mapState} from "vuex";
export default {
name: 'App',
data(){
return {
lang: '',
}
},
computed: {
...mapState(['name']),
},
components: {
oHeader,
oFooter
},
methods: {
changeLanguage(lang){
this.$i18n.locale = lang;
this.lang = lang;
},
changeAppLocale(locale){
this.changeLanguage(locale);
this.$router.push({name: this.$route.name, params: {lang: this.lang}})
}
},
mounted(){
this.changeLanguage(this.$route.params.lang);
}
}
</script>
<style>
</style>
Vue實例生命週期圖示
list.vue
list.vue展示所有的商品。當點擊“加載更多”時,會通過http請求獲取good.json的數據,然後將數據添加到goods中。可以通過store的同步操作mutations執行insertGood
來添加數據,或通過派發器派發store的異步操作actions執行insertGood
來添加數據。
<template>
<main class="goods-mian">
<Scroll>
<ul class="goods-list">
<div @click="goDetail(index)"
v-for="(good,index) in goods"
:key="good.id">
<oGood v-bind:goodInfo="good" v-bind:index="index"></oGood>
</div>
<div class="show-more" @click="addGood">
<span>{{$t("message.showMore")}}</span>
</div>
</ul>
</Scroll>
</main>
</template>
<script>
import Scroll from "@/components/Scroll.vue";
import oGood from "@/components/Good.vue";
import {mapState, mapGetters, mapMutations} from "vuex";
export default{
name: 'List',
props: ['lang'],
computed: {
...mapState(['goods']),
...mapGetters(['totalPrice', 'totalNum'])
},
components: {
Scroll,
oGood
},
methods: {
...mapMutations(['insertGood']),
goDetail(index){
this.$router.push({name: 'detail', params: {lang: this.lang, index: index}})
},
addGood(){
this.$http.get('../static/data/good.json').then((data) => {
// console.log(data)
// this.insertGood(data.body);
var goodData = data.body;
goodData.id = '000' + this.goods.length;
// console.log(goodData.id);
this.$store.dispatch('insertGood', goodData);
})
}
}
}
</script>
detail.vue
detail.vue顯示具體某條數據。
<template>
<oGood v-bind:goodInfo="goodInfo" v-bind:index="index"></oGood>
</template>
<script>
import oGood from "@/components/Good.vue";
import {mapState, mapGetters, mapMutations} from "vuex";
export default{
name: 'Detail',
computed: {
goodInfo(){//使用路由參數獲取數據
// console.log(this.$router.currentRoute.params);
// console.log(this.$store.getters.getGoodById(this.$router.currentRoute.params.index));
return this.$store.getters.getGoodById(this.$router.currentRoute.params.index);
},
index(){
return this.$router.currentRoute.params.index;
}
},
components: {
oGood
},
}
</script>