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>