vuex--vuex安装使用state和mutations、vuex中的action、组件之间使用vuex传递数据、store文件拆分----获取加载数据dem

362 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

vuex

vuex是vue中的状态管理插件,可以实现全局统一的状态管理。在一个项目中只有一棵状态树,所有的数据都存储在上面

单向数据流

图片十分重要,要理解,可去官网查看详细解释

在这里插入图片描述 在这里插入图片描述

数据是单向流动的,view视图通过dispatch派发一个action(行为),改变state(数据),数据改变之后视图重新渲染

所有的和服务器端交互相关的,都放在actions里,比如和接口有关的

mutation——commit actions——dispatch——接口

如何使用vuex

npm i vuex # 安装插件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)


在这里插入图片描述

==demo 部分内容==

1.此demo使用的是前面创建的vue目录,所以有很多的东西不是本篇文章主要讲解的,还有一些配置没有此处说明但是并不是没有写, 2.因为获取接口数据用到了axios,所以还需要输入命令行安装axios:npm i axios 3.在src源文件中创建一个store目录,并在其中创建一个index.js文件,是用来文件拆分的

4.文件运行 npm run serve 打开localhost:8080 或者npm run build 然后在打包好的dist文件中双击打开index.html

本篇文章主要的文件是: /src/store/index.js /src/main.js /src/App.vue /src/pages/Home.vue

/src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 1,
    list: [],
    pages: 1,
    totals: 1,
    page: 1,
    cartCount: 0
  },
  mutations: {
    plus(state, step = 1) {
      state.count += step
    },
    reduce(state) {
      state.count--
    },
    loadDataEnd(state, payload) {
      // 形参payload接收传参过来的数据也就是从接口那获得的数据,必须在下面写成详细的payload.movies,因为还要获取pages,要是直接就接收到详细的movies数据列表,那并排的pages和totals就获取不到了
      this.state.list = [...state.list, ...payload.movies]
      state.pages = payload.pages
      state.totals = payload.totals
      state.page++
    },
    buy(state) {
      this.state.cartCount++
    }
  },
  actions: {
    loadData({ commit }, { page }) {
      axios
        .get('http://localhost:3000/api/v1/m', {
          params: {
            page
          }
        })
        .then(res => {
          console.log(res.data)
          commit('loadDataEnd', res.data)
        })
    }
  }
})

export default store

/src/main.js

import Vue from 'vue'
// import Vuex from 'vuex'
import App from './App.vue'
import router from './router'

import store from './store'

Vue.config.productionTip = false
// Vue.use(Vuex)

/* const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    plus(state, step = 1) {
      state.count += step
    },
    reduce(state) {
      state.count--
    }
  }
}) */

new Vue({
  router,
  store,// store: store,以后所有的组件中可以使用$store获取vuex中的数据
  render: h => h(App)
}).$mount('#app')

/src/App.vue 给购物车哪里增加了购买数量

<template>
  <div id="app" class="container">
    <div class="header">芒果商城-{{ $store.state.count }}</div>
    <router-view class="content"></router-view>
    <ul class="footer">
      <li class="active">
        <i class="fa fa-home"></i>
        <span>首页</span>
      </li>
      <li>
        <i class="fa fa-fire"></i>
        <span>热卖</span>
      </li>
      <li style="position:relative;">
        <span class="dot" v-show="$store.state.cartCount>0">{{$store.state.cartCount}}</span>
        <i class="fa fa-shopping-cart"></i>
        <span>购物车</span>
      </li>
      <li>
        <i class="fa fa-user"></i>
        <span>我的</span>
      </li>
    </ul>
  </div>
</template>

<style>
* {
  margin: 0;
  padding: 0;
}
html,
body,
.container {
  width: 100%;
  height: 100%;
}
.container {
  display: flex;
  flex-direction: column;
}
.container .header {
  height: 40px;
  text-align: center;
  background: rgb(14, 184, 184);
  line-height: 40px;
  color: white;
  font-weight: 900;
}
.container .content {
  flex: 1;
  overflow: auto;
}
.container .footer {
  height: 50px;
  display: flex;
  justify-content: space-around;
  align-items: center;
  background: rgb(14, 184, 184);
  color: white;
}
ul li {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
ul li i {
  font-size: 1.6rem;
}
ul li span {
  font-size: 0.6rem;
}
ul li.active {
  color: black;
  font-weight: 900;
}
img {
  max-width: 100%;
}
.dot {
  background: palevioletred;
  color: white;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  position: absolute;
  padding: 0.2rem;
  top: -10px;
  left: 16px;
  text-align: center;
}
</style>

/src/pages/Home.vue

<template>
  <div class="home">
    <h1>{{ $store.state.count }}</h1>
    <button @click="countAdd">计数值+1</button>
    <button @click="countAddStep(5)">计数值+5</button>
    <button @click="countReduce">计数值-1</button>
    <ul>
      <li v-for="item in $store.state.list" :key="item._id">
        {{ item.title }}-----------
        <button @click="buyHandle">购买</button>
      </li>
    </ul>
    <keep-alive>
      <button v-show="isShowLoadMore" @click="loaData">加载数据</button>
    </keep-alive>

    <!-- <img :src="img" alt="巴卫" /> -->
    <!-- <img alt="Vue logo" src="../assets/logo.png" />
    <img :src="img" alt="巴卫" />
    <HelloWorld msg="Welcome to Your Vue.js App" />-->
  </div>
</template>

<script>
// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'
// import xx from '../assets/images/4.jpeg'

export default {
  name: 'Home',
  components: {
    // HelloWorld
  },
  data() {
    return {
      // img: require('../assets/images/4.jpeg')
      // img: xx,
      isShowLoadMore: true
    }
  },
  methods: {
    countAdd() {
      // commit 操作会传递两个参数 type payload
      //  type表示mutation中的名字
      //  payload(载荷)表示参数
      this.$store.commit('plus')
    },
    countAddStep(buchang) {
      this.$store.commit('plus', buchang)
    },
    countReduce() {
      this.$store.commit('reduce')
    },
    loaData() {
    	//  	这里的判断不可以写等号即不能写成<=,因为两者可能相等,要是写了等号,这个if就无效了
      if (this.$store.state.pages < this.$store.state.page) {
        this.isShowLoadMore = false
        return
      }
      this.$store.dispatch('loadData', { page: this.$store.state.page })
    },
    buyHandle() {
      this.$store.commit('buy')
    }
  }
}
</script>
<style scoped>
img {
  max-width: 100%;
}
ul {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  width: 100%;
}
ul li {
  flex: 1;
  flex-direction: row;
  height: 50px;
  display: flex;
  padding: 0.5rem 0.3rem;
}
</style>

``

==demo 注释==

/src/store/index.js

// 做模块拆分
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
import axios from 'axios'

// 使用veux
Vue.use(Vuex)

// 创建一个全局的vuex实例
const store = new Vuex.Store({
  // 表示全局的state数据
  // 以后所有的组件中可以使用$store获取vuex中的数据
  state: {
    count: 1,
    list: [], // 数据
    pages: 1, // 总页数
    totals: 0, // 总数量
    page: 1, // 当前页页码
    cartCount: 0
  },
  // 是用来同步的改变数据的(所有的数据改变都是在这里进行的)
  // 只能通过commit才可以提交(触发)一个mutation
  mutations: {
    // 参数一固定state(表示原始状态)  参数二 可以接收commit传的参数
    plus(state, step = 1) {
      state.count += step
    },
    reduce(state) {
      state.count--
    },
    loadDataEnd(state, payload) {
      // 如果没有分页直接这样取就可以了
      // state.list = payload
      // 如果有分页做加载更多的效果 需要:
      state.list = [...state.list, ...payload.products]
      state.pages = payload.pages
      state.totals = payload.totalCount
      // 点一次 页码加一 做加载更多的效果
      state.page++
    },
    buy(state) {
      state.cartCount++
    }
  },
  // 如何派发 actions? 在Home里面派发了
  // dispatch 派发actions actions和服务器端交互
  actions: {
    // 接收两个参数
    // 参数一 context表示上下文是个对象 包含了vuex中的所有数据比如commit
    // 参数二 表示接收传递的数据
    // 在接收参数的时候 直接解构赋值
    loadData({ commit }, { page }) {
      // console.log(context)
      // console.log(payload)
      // 获取里面的commit
      // const { commit } = context
      axios
        .get('http://localhost:3009/api/v1/products', {
          params: {
            page // page: page // 把页码传到服务器
          }
        })
        .then((res) => {
          console.log(res.data)
          // 调出数据 通过 commit 提交一个mutations  改变state的数据
          commit('loadDataEnd', res.data)
        })
    }
  }
})

export default store