之前学习到了 使用vue+webpack构建项目(一)基本配置 这里,这次学习在这个基础项目中引入 vuex、 vue-resource、vue-router等。
首先是安装依赖
npm i --save-dev vuex vue-resource vue-router element-ui
其中
vuex 是 状态管理库
vue-resource 是 异步加载数据
vue-router 是 路由管理器
element-ui 是 后台管理系统的组件UI,和Antd类似。
这部分内容我搞了好久才大概有点懂,官网的文档很详细,但是初学者就是有点搞不来。
我也只能是写个简单的demo,先将这些知识点都用上。
首先看 src下的项目目录
api/index.js
主要是封装一个全局的ajax异步请求,用到的是 vue-resource,它封装了promise对象,所以建议了解ES6语法。
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource);
// HTTP相关
Vue.http.options.emulateJSON = true
Vue.http.options.crossOrigin = true
function ajax(url, options) {
// 使用 aysnc await
const result = Vue.http[options.method](url,options.data).then(res => {
return res.json();
}).then(resp => {
return resp;
});
return result;
}
export default ajax;
在调用ajax函数的时候,也是需要按照形参传入。
router/index.js
这里使用的是vue-router,路由状态管理,因为页面有两个,list和detail,所以是支持跳转的。
import Vue from 'vue'
import Router from 'vue-router'
import List from '../components/list'
import Detail from '../components/detail'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'list',
component: List
},
{
path: '/list',
name: 'list',
component: List
},
{
path: '/detail',
name: 'detail',
component: Detail
}
]
})
根路径默认展示 list 页面
修改 App.vue文件 如下:
<template>
<div id="app">
<!-- 调用路由 -->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style></style>
main.js 修改如下:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
import VueResource from 'vue-resource';
// 引入路由
import router from './router'
// 引入Vuex
import store from './store'
// 注册 全部引入
Vue.use(ElementUI)
// 注册 请求数据
Vue.use(VueResource)
// 挂载
const root = document.createElement('div');
document.body.appendChild(root);
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
render: h => h(App),
router,
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
// 每个应用将仅仅包含一个 store 实例
store,
components: { App },
template: ' '
}).$mount(root)
接下来就是重头戏,页面组件,数据状态管理。
components/list/index.vue
<template>
<div class="rowcolCenter">
<!-- ele中属性比较少 class都是自定义 -->
<el-card shadow='hover'>
<!-- 头部 -->
<div slot="header">
<h2 style="line-height: 36px; color: #20A0FF">豆瓣电影排行榜</h2>
<p>sfdsf</p>
</div>
<div v-for="item in items">
{{item.title}}
</div>
</el-card>
<el-row>
<el-button type="success" @click="getData">获取</el-button>
<el-button type="primary">
<router-link to='./detail'>跳转详情</router-link>
</el-button>
</el-row>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
// 使用Vuex时,之后在页面vue中只写 生命周期钩子,计算属性,方法等
// 对于 初始化data,actions,getters,mutations 已经更改数据源 都放在对应的 vuex文件中
data(){
return {
// items: this.$store.getters.itemsaaa //获取store中state的数据
}
},
// 计算属性 复杂逻辑时使用
computed: mapState({
// 匿名函数作为属性reversedMessage 的getter函数
// 计算属性的 getter
items: function(state) {
// 不使用 modules时
// return state.items
// 使用modules时,需要使用 state.moduleA.xx 来取值
return state.list.items
}
}),
// 周期函数
// 所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算
// 不能使用 箭头函数 定义生命周期函数 这是因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同,
mounted: function(){
// 触发action
this.$store.dispatch('actionItems'); // 使用actions 异步触发
// 提交 mutations
// this.$store.commit('getItems') // 使用 mutations 同步触发
// this.getData();
console.log(this)
},
methods: {
...mapActions({
'getData': 'actionItems'
})
}
}
</script>
<style scoped>
.rowcolCenter {
width: '100%';
height: '600px';
display: flex;
justify-content: center
}
</style>
components/detail/index.vue
<template>
<div class="rowcolCenter">
{{ msg }}
<router-link to='./list'>跳转列表</router-link>
</div>
</template>
<script>
export default {
data(){
return {
msg: 'this is detail'
}
}
}
</script>
<style scoped>
.rowcolCenter {
width: '100%';
height: '600px';
display: flex;
justify-content: center
}
</style>
页面逻辑比较简单,就是查个数据然后显示出来。
store文件夹中就是 vuex数据状态管理
因为有两个页面,所以我就直接使用到了modules属性。其实也可以只在index.js中全部写上。
首先看一下不使用modules的方法
import Vue from 'vue';
import Vuex from 'vuex';
import ajax from '../api'
//注册 状态管理
Vue.use(Vuex)
const store = new Vuex.Store({
// 子模块注入到总的store中
modules: {
list
},
// 初始状态
state: {
items: []
},
// 相当于 组件的 computed属性
getters: {
itemsaaa: (state) => {
return state.items //获取store中state的数据
}
},
//相当于methods属性
//使用commit() 进行分发
mutations: {
// state 当前state
// aa 自定义参数
async getItems (state, aa) {
const result = await ajax('https://api.douban.com/v2/movie/top250?count=10', {
method: 'jsonp',
data: {}
})
state.items = result.subjects
},
},
// 类似于 mutations
actions: {
// 第一个参数是context, 是一个与store实例具有相同属性和方法的对象
// aa 自定义参数
actionItems(context, aa) {
console.log('aaa')
console.log(this)
setTimeout( () => {
context.commit( 'getItems', aa ); //context提交
}, 2000)
}
},
//生成状态快照的插件应该只在开发阶段使用
//这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数:
plugins: []
//日志插件用于一般的调试,设置如下:
// logger 插件会生成状态快照,所以仅在开发环境使用
// plugins: process.env.NODE_ENV !== 'production' ? [createLogger()] : []
// 开启严格模式
// 只能在开发环境下启动,在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到
// 不要在生产环境中启动,避免性能损失
// strict: process.env.NODE_ENV !== 'production'
})
console.log(store)
export default store;
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
// 区别
在组件中使用
使用:如果是同步操作,那么直接在页面中调用 mutations函数就可以。如果需要异步操作,则需要在组件中调用actions方法。
只能通过mutations 改变状态,所以即使是使用了actions,也需要用action来提交mutations
// 子模块注入到总的store中
modules: {
list
},
再加一个文件 modules/list.js
import ajax from '../../api'
// state
const state = {
items: []
}
//getters
const getters = {
}
// actions
const actions = {
// getItems({ commit }){
// console.log('aaaaa')
// // 分发mutations 修改 store 实例中的状态
// commit('ADD_TODO')
// state.items = ajax('https://api.douban.com/v2/movie/top250?count=10', {} );
// }
// 第一个参数是context, 是一个与store实例具有相同属性和方法的对象
// aa 自定义参数
actionItems(context, aa) {
console.log('aaa')
console.log(this)
setTimeout( () => {
context.commit( 'getItems', aa ); //context提交
}, 2000)
}
}
// mutations
const mutations = {
// state 当前state
// aa 自定义参数
async getItems (state, aa) {
const result = await ajax('https://api.douban.com/v2/movie/top250?count=10', {
method: 'jsonp',
data: {}
})
state.items = result.subjects
console.log(state.items)
},
}
export default {
// 设置为true后表示 独立的带命名空间的模块,模块更具封装性和独立性
// 都会变得有路径,在全局就找不到了
// namespaced: true,
state,
getters,
actions,
mutations
}
结果页面:
基本到这里就算是结束了,有一些凌乱,有什么问题可以一起交流~
ps:
关注我获取更多前端资源和经验分享
感谢大佬们阅读,希望大家头发浓密,睡眠良好,情绪稳定,早日实现财富自由~