Vuex的基本概念、项目搭建以及入坑点


Posted in Javascript onNovember 04, 2018

前言:Vuex是一个专门为Vue.js应用程序开发的状态管理模式, 它采用集中式存储管理所有组件的公共状态, 并以相应的规则保证状态以一种可预测的方式发生变化.

Vuex的四大核心

1.state 驱动应用的数据源

2.mutations 基因突变 类如C# 属性get set

3.actions 行为

4.getters 读取器

Vuex的基本概念、项目搭建以及入坑点 

上图中绿色虚线包裹起来的部分就是Vuex的核心, state 中保存的就是公共状态, 改变 state 的唯一方式就是通过 mutations 进行更改. 可能你现在看这张图有点不明白, 等经过本文的解释和案例演示, 再回来看这张图, 相信你会有更好的理解.

如何引入Vuex?

1.npm install vuex

2.装好了之后,在全局上去使用你的Vuex

3.创建Store对象,最好在src创建一个store这样的文件夹然后创建index.js

4.在main.js中注册使用

import Vuex from 'vuex'

 

Vue.use( Vuex );

 

const store = new Vuex.Store({

  //待添加

})

new Vue({

  el: '#app',

  store,

  render: h => h(App)

})

为了讲解Vuex,我们做了一个项目,这个项目需要连接apicloud,异步操作使用了axios以及样式bootstrap,其中包括了登录注册以及其中的父组件向子节点传值等,我们给项目安装相关的modules

npm install bootstrap
npm install axios

Vuex的基本概念、项目搭建以及入坑点

router.js

import Vue from 'vue'

import Router from 'vue-router'

 

Vue.use(Router)

 

export default new Router({

 routes: [

  {

   path: '/',

   name: 'index',

   component:()=>import('../views/index.vue')

  },

  {

   path:'/detail/:id',

   name:'detail',

   component:()=>import ('../views/detail.vue')

  },

  {

   path:'/login',

   name:'login',

   component:()=>import ('../views/login.vue')

  },

  {

   path:'/register',

   name:'register',

   component:()=>import ('../views/register.vue')

  }

 ]

})

store.js

我们来上述代码中来讲解其中vuex的奥秘,State就是所有组件提出来的data,用于所有组件公共数据,而其中mutations就像C#中get\set,属性赋值器,其中方法的两个参数除了state只能带一个参数。

actions是操作数据的方法,说过说你的actions中需要改变state中的数据,那么必须要通过commit关键字去提交给mutations,还有一点就是actions中很多操作都是关于异步处理的,最关键就是它是操作state数据的,那getters是什么呢?它是组件访问vuex的入口,里面写好了方法去操作,它也是过滤器,就像程序中的三层架构BLL.

main.js

// The Vue build version to load with the `import` command

// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'

import App from './App'

import router from './router'

import boostrap from 'bootstrap/dist/css/bootstrap.css'

import store from './store/index.js'

 

Vue.config.productionTip = false

 

/* eslint-disable no-new */

new Vue({

 el: '#app',

 router,

 store,//在全局对象上加载仓库

 components: { App },

 template: '<App/>'

}) 

两个组件

import Vue from 'vue'
import Vuex from 'vuex'
import API from '../utils/api.js'

var api = new API('goods')
var userApi = new API('userinfo');

Vue.use(Vuex);

const state = {
  user: null,
  products: []
}
const mutations = {
  //加载产品数据
  INIT_PRODUCTS(state, data) {
    state.products = data;
  },
  SET_LOGIN_USER(state, u) {
    state.user = u;
  }
}
const actions = {
  LOAD_PRODUCTS({ commit }) {
    api.Select().then(res => {
      commit('INIT_PRODUCTS', res.data);
    })
  },
  LOGIN({ commit }, user) {
    return userApi.Select().then(res => {
      let users = res.data;//所有的用户
      for (let u of users) {
        if (u.name == user.name && u.password == user.password) {
          commit('SET_LOGIN_USER', u);
          return u;
        }
      }
    })
  },
  REGISTER({ commit }, user) {
    return userApi.Insert(user).then(res => {
      console.log(res.data);
      return 'OK';
    }).catch(err => {
      return err;
    })
  }

}
const getters = {
  ALL_PRODUCTS(state) {
    return state.products;
  },
  GET_PRODUCT_BYID: (state) => function (id) {
    //遍历 is == id
    for (let p of state.products) {
      if (p.id == id) {
        return p;
      }
    }
    return null;
  }
}

//仓库
const store = new Vuex.Store({
  state: state,
  mutations: mutations,
  actions: actions,
  getters: getters
})
export default store;

navbar.vue

<template>
   <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
      <a class="navbar-brand" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >购物车</a>
      <ul class="navbar-nav ml-auto">
        <li class="nav-item active dropdown" v-if="user!==null">
          <a class="nav-link dropdown-toggle" data-toggle="dropdown" @click="showDropdown=!showDropdown">欢迎你:{{user.name}} </a>
          <div class="dropdown-menu show">
            <a class="dropdown-item" href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >我的订单</a>
            <div class="dropdown-divider"></div>
            <a class="dropdown-item" >注销</a>
          </div>
        </li>
        <li class="nav-item active" style="margin-right:5px" v-if="user===null">
          <router-link class="nav-link btn btn-warning btn-sm" style="color:#fff" to="/login">登录</router-link>
        </li>
        <li class="nav-item active" v-if="user===null">
          <router-link class="nav-link btn btn-danger btn-sm" style="color:#fff" to="/register">注册</router-link>
        </li>
      </ul>
    </div>
  </nav>
</template>

<script>
export default {
  data(){
    return{
      showDropdown:false
    }
  },
  computed:{
    user(){
      return this.$store.state.user;
    }
    
  }
}
</script>

product.vue 该组件用于显示商品的详细信息

<template>
  <div class="card">
    <img class="card-img-top" src="../../assets/logo.png" alt="Card image cap">
    <div class="card-body">
      <h5 class="card-title">{{product.name}}</h5>
      <p class="card-text">{{product.description===null?"暂无描述":product.description}}</p>
      <p>价格: {{product.price}}</p>
      <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="btn btn-warning float-left" @click="goDetail">查看详情</a>
      <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="btn btn-primary float-right">加入购物车</a>
    </div>
  </div>
</template>

<script>
export default {
  props:['product'],
  methods:{
    goDetail(){
      console.log(this.product.id);
      this.$router.push(`/detail/${this.product.id}`);
    }
  }
}
</script>

程序入口APP.vue

<template>
 <div id="app">
  <nav-bar></nav-bar>
  <router-view></router-view>
 </div>
</template>

<script>
import NavBar from './views/components/navbar'
export default {
  name: 'App',
  components:{NavBar}
}
</script>

注册:通过 this.$store.dispatch去调用actions中的方法,其中有趣的是commit的参数竟然被方法名给..这个以后在思考。。

<template>
  <div class="container">
    <div class="row">
      <div class="card" style="margin:50px auto;width:400px">
        <div class="card-body">
          <h5 class="card-title">注册</h5>
          <hr>
          <div class="form-group">
            <label for="">用户名</label>
            <input type="text" class="form-control" v-model="user.name">
          </div>
          <div class="form-group">
            <label for="">真实姓名</label>
            <input type="text" class="form-control" v-model="user.realname">
          </div>
          <div class="form-group">
            <label for="">密码</label>
            <input type="password" class="form-control" v-model="user.password">
          </div>
          <div class="form-group">
            <button class="btn btn-primary btn-block" @click="register">注册</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data(){
    return{
      user:{
        name:'',
        realname:'',
        password:''
      }
    }
  },methods:{
    register(){
      this.$store.dispatch('REGISTER',this.user).then(res=>{
        if(res=="OK")
          this.$router.push('/index');
      })
    }
  }
}
</script> 

登录

<template>
  <div class="container">
    <div class="row">
      <div class="card" style="margin:50px auto;width:400px">
        <div class="card-body">
          <h5 class="card-title">登录</h5>
          <hr>
          <div class="form-group">
            <label for="">用户名</label>
            <input type="text" class="form-control" v-model="user.name">
          </div>
          <div class="form-group">
            <label for="">密码</label>
            <input type="password" class="form-control" v-model="user.password">
          </div>
          <div class="form-group">
            <button class="btn btn-primary btn-block" @click="login">登录</button>
          </div> 
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      user:{
        name:'',
        password:''
      }
    }
  },
  methods:{
    login(){
      this.$store.dispatch('LOGIN',this.user).then(res=>{
        console.log(res);
        if (res){
          this.$router.push('/')
        }
      })
    }
  }
}
</script>

主页面

<template>
  <div class="container">
    <h1>商品列表</h1>
    <div class="row">
       <div class="col-md-4" v-for="p in products" :key="p.id">
        <!-- 传递商品信息到子组件 -->
        <product-card :product="p"></product-card>
      </div>
    </div>
  </div>
</template>

<script>
import ProductCard from './components/product.vue'
export default {
  components:{ProductCard},
  computed:{
    products(){
      return this.$store.getters.ALL_PRODUCTS;
    }
  },
  created(){
    this.$store.dispatch('LOAD_PRODUCTS');
  }
}
</script>

本文结语知识总结:

获取url中的参数

let id = this.$route.params.id;
this.details = this.$store.getters.GET_PRODUCT_BYID(id);

有的小伙伴在复制我的代码运行报错,说什么未初始化;一定要在index.vue添加这个代码,LOAD_PRODUCTS给数据初始化

created(){
    this.$store.dispatch('LOAD_PRODUCTS');
  }

跳转路由

this.$router.push('/')

ApiClound万能帮助类

import crypto from 'crypto'   // 加密
import axios from 'axios'
class API {
  constructor(classname){
    this.api = `https://d.apicloud.com/mcm/api/${classname}`;
    let ID = '';
    let KEY = '';
    let now = Date.now(); //当前时间
    let sha1 = crypto.createHash('sha1');
    sha1.update(ID + "UZ" + KEY + "UZ" + now); 
    axios.defaults.headers["X-APICloud-AppId"] = ID;
    axios.defaults.headers["X-APICloud-AppKey"] = sha1.digest('hex') + "." + now;
  }
  
  Select(){
    return axios.get(this.api);
  }
  Insert(obj){
    return axios.post(this.api,obj);
  }
  Update(id,obj){
    // RESTFUL API 
    return axios.put(this.api+`/${id}`,obj);
  }
  Delete(id){
    return axios.delete(this.api + `/${id}`);
  }
}

export default API;

还有同学问我父组件和子组件如何传值?

在父页面引用的地方以":"表示的值都可以在子页面的props获取到

<template>
<div>
  <h3>图书管理</h3><hr>
  <div class="row">
    <div class="col-md-4 col-sm-4" v-for="b in books" :key="b.id">
      <book-detail @abc="xyz" :Book="b" :MSG="abc"></book-detail>
    </div>
  </div>
</div>
</template>
<script>
  import BookDetail from './components/BookDetails.vue'
  export default{
    components:{BookDetail},
    data(){
      return {
        abc:'heheda',
        books:[{
          id:1,
          name:'7天 JAVA 从入门到放弃',
          text:'到底是人性的扭曲,还是道德的沦丧. 青年男子为何突然脱发,中年男人为何删库跑路。',
          price:20,
          img:'img2.jpg',
          showHehe:true
        },{
          id:2,
          name:'7天 C# 从入门到自杀',
          text:'到底是人性的扭曲啊,还是道德的沦丧啊. 祖国的花朵为何自杀。',
          price:20,
          img:'../../static/img2.jpg',
          showHehe:false
        }]
      }
    },
    methods:{
      xyz(bid){
        alert(bid);
      }
    }
  }
</script>

在子页面中可以这么搞

<script>
export default{
  props:["Book","MSG"],
  created(){
    console.log(this.Book.name);
  },
  methods:{
    select(id){
      this.$emit('abc',id);
    },
    detail(bid){
      this.$router.push(`/admin/Details/${bid}`);
    }
  }
}
</script>

而其中的$emit是可以调用父页面的方法的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery使用手册之三 CSS操作
Mar 24 Javascript
Javascript 写的简单进度条控件
Jan 22 Javascript
js遍历td tr等html元素
Dec 13 Javascript
jQuery的remove()方法使用详解
Aug 11 Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
Aug 21 Javascript
JS动态改变浏览器标题的方法
Apr 06 Javascript
JavaScript 事件对内存和性能的影响
Jan 22 Javascript
解决webpack打包速度慢的解决办法汇总
Jul 06 Javascript
vue悬浮可拖拽悬浮按钮的实例代码
Aug 20 Javascript
浅析JavaScript 函数防抖和节流
Jul 13 Javascript
vue使用watch监听属性变化
Apr 30 Vue.js
JS开发前端团队展示控制器来为成员引流
Aug 14 Javascript
微信小程序实现登录注册tab切换效果
Dec 29 #Javascript
原生js实现淘宝放大镜效果
Oct 28 #Javascript
微信小程序如何获取手机验证码
Nov 04 #Javascript
微信小程序实现弹出层效果
May 26 #Javascript
微信小程序实现预览图片功能
Oct 22 #Javascript
详解如何使用koa实现socket.io官网的例子
Nov 04 #Javascript
微信小程序实现多选功能
Nov 04 #Javascript
You might like
探讨各种PHP字符串函数的总结分析
2013/06/05 PHP
PHP的一个完美GIF等比缩放类,附带去除缩放黑背景
2014/04/01 PHP
php7安装mongoDB扩展的方法分析
2017/08/02 PHP
jQuery 快速结束当前正在执行的动画
2013/11/20 Javascript
javascript ajax的5种状态介绍
2014/08/18 Javascript
用循环或if语句从json中取数据示例
2014/08/18 Javascript
浅谈JavaScript中运算符的优先级
2015/07/07 Javascript
HTML5 Shiv完美解决IE(IE6/IE7/IE8)不兼容HTML5标签的方法
2015/11/25 Javascript
Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)
2016/09/09 Javascript
js仿百度音乐全选操作
2017/01/13 Javascript
jquery 手势密码插件
2017/03/17 Javascript
JS排序之冒泡排序详解
2017/04/08 Javascript
vue 动态修改a标签的样式的方法
2018/01/18 Javascript
vue2.0实现音乐/视频播放进度条组件
2018/06/06 Javascript
react实现换肤功能的示例代码
2018/08/14 Javascript
PHPStorm中如何对nodejs项目进行单元测试详解
2019/02/28 NodeJs
layui给下拉框、按钮状态、时间赋初始值的方法
2019/09/10 Javascript
element-ui 弹窗组件封装的步骤
2021/01/22 Javascript
Python中使用PIPE操作Linux管道
2015/02/04 Python
python代码实现ID3决策树算法
2017/12/20 Python
Windows下anaconda安装第三方包的方法小结(tensorflow、gensim为例)
2018/04/05 Python
python使用xlrd和xlwt读写Excel文件的实例代码
2018/09/05 Python
python3实现逐字输出的方法
2019/01/23 Python
使用Python做定时任务及时了解互联网动态
2019/05/15 Python
Tensorflow 卷积的梯度反向传播过程
2020/02/10 Python
python使用正则表达式去除中文文本多余空格,保留英文之间空格方法详解
2020/02/11 Python
python中温度单位转换的实例方法
2020/12/27 Python
全球领先的美容用品专卖店:Beauty Plus Salon
2018/09/04 全球购物
TALLY WEiJL法国网上商店:服装、时装及配饰
2019/08/31 全球购物
通息工程毕业生自荐信
2013/10/16 职场文书
财务会计应届生求职信
2013/11/24 职场文书
党的群众路线教育实践方案
2014/05/11 职场文书
2014年学校领导班子对照检查材料
2014/09/19 职场文书
维稳工作情况汇报
2014/10/27 职场文书
2015年国庆节新闻稿
2015/07/18 职场文书
【DOTA2】高能暴走TK秀!PSG LGD vs ASTER - DPC 2022 WINTER TOUR CN
2022/04/02 DOTA