Vuex的基本概念、項目搭建以及入坑點
前言:Vuex是一個專門為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式, 它采用集中式存儲管理所有組件的公共狀態(tài), 并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化.
Vuex的四大核心
1.state 驅(qū)動應(yīng)用的數(shù)據(jù)源
2.mutations 基因突變 類如C# 屬性get set
3.actions 行為
4.getters 讀取器
上圖中綠色虛線包裹起來的部分就是Vuex的核心, state
中保存的就是公共狀態(tài), 改變 state
的唯一方式就是通過 mutations
進行更改. 可能你現(xiàn)在看這張圖有點不明白, 等經(jīng)過本文的解釋和案例演示, 再回來看這張圖, 相信你會有更好的理解.
如何引入Vuex?
1.npm install vuex
2.裝好了之后,在全局上去使用你的Vuex
3.創(chuàng)建Store對象,最好在src創(chuàng)建一個store這樣的文件夾然后創(chuàng)建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,其中包括了登錄注冊以及其中的父組件向子節(jié)點傳值等,我們給項目安裝相關(guān)的modules
npm install bootstrap npm install axios
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,用于所有組件公共數(shù)據(jù),而其中mutations就像C#中g(shù)et\set,屬性賦值器,其中方法的兩個參數(shù)除了state只能帶一個參數(shù)。
actions是操作數(shù)據(jù)的方法,說過說你的actions中需要改變state中的數(shù)據(jù),那么必須要通過commit關(guān)鍵字去提交給mutations,還有一點就是actions中很多操作都是關(guān)于異步處理的,最關(guān)鍵就是它是操作state數(shù)據(jù)的,那getters是什么呢?它是組件訪問vuex的入口,里面寫好了方法去操作,它也是過濾器,就像程序中的三層架構(gòu)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 = { //加載產(chǎn)品數(shù)據(jù) 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去調(diào)用actions中的方法,其中有趣的是commit的參數(shù)竟然被方法名給..這個以后在思考。。
<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>
本文結(jié)語知識總結(jié):
獲取url中的參數(shù)
let id = this.$route.params.id; this.details = this.$store.getters.GET_PRODUCT_BYID(id);
有的小伙伴在復制我的代碼運行報錯,說什么未初始化;一定要在index.vue添加這個代碼,LOAD_PRODUCTS給數(shù)據(jù)初始化
created(){ this.$store.dispatch('LOAD_PRODUCTS'); }
跳轉(zhuǎn)路由
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:'到底是人性的扭曲,還是道德的淪喪. 青年男子為何突然脫發(fā),中年男人為何刪庫跑路。', 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是可以調(diào)用父頁面的方法的。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用vue/cli出現(xiàn)defineConfig?is?not?function錯誤解決辦法
這篇文章主要給大家介紹了關(guān)于使用vue/cli出現(xiàn)defineConfig?is?not?function錯誤的解決辦法,當我們在做打包配置的時候,出現(xiàn)了這個錯誤,需要的朋友可以參考下2023-11-11vue查詢數(shù)據(jù)el-table不更新數(shù)據(jù)的解決方案
這篇文章主要介紹了vue查詢數(shù)據(jù)el-table不更新數(shù)據(jù)的問題及解決方案,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-12-12vue添加錨點,實現(xiàn)滾動頁面時錨點添加相應(yīng)的class操作
這篇文章主要介紹了vue添加錨點,實現(xiàn)滾動頁面時錨點添加相應(yīng)的class操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Element-UI 多個el-upload組件自定義上傳不用上傳url并且攜帶自定義傳參(文件序號)
有多個upload組件,每個都需要單獨上傳獲取文件(JS File類型),不需要action上傳到指定url,自定義上傳動作和http操作,下面通過本文給大家分享Element-UI 多個el-upload組件自定義上傳不用上傳url并且攜帶自定義傳參(文件序號),感興趣的朋友一起看看吧2024-06-06