使用vue+webpack构建项目(二) 引入vuex vue-resource vue-router

之前学习到了 使用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: '<App/>'
}).$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的方法

  • 不使用modules
    store/index.js
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

// 区别

  • mutation 必须同步执行
  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

在组件中使用

  • this.$store.commit(type, payload) 来调用mutations中的函数
  • this.$store.dispatch(fun) 来调用actions中的函数

使用:如果是同步操作,那么直接在页面中调用 mutations函数就可以。如果需要异步操作,则需要在组件中调用actions方法。
只能通过mutations 改变状态,所以即使是使用了actions,也需要用action来提交mutations

  • 使用 modules属性
    store/index.js
    其余属性都可以不要了。因为都将在子模块中做操作,然后注入到总的。
// 子模块注入到总的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:

关注我获取更多前端资源和经验分享
在这里插入图片描述

感谢大佬们阅读,希望大家头发浓密,睡眠良好,情绪稳定,早日实现财富自由~

发布了102 篇原创文章 · 获赞 202 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/zr15829039341/article/details/86580471