Vue07 vue-resource 插槽 vuex工作原理 求和案例 vuex开发者工具 getters mapState 多组件共享数据 vuex模块化+namespaced

vue-resource

也是对xhr的封装。是一个插件库。官方已经不再维护。推荐axios。

Vue.use(vueResource);

应用插件后,vc上有$http:

默认插槽

多个子组件需要展示不同的内容.

在父组件的模板里写内容,子组件申明一个插槽。内容会在插槽中显示。

父组件解析完结构再传过去。

<template>
  <div class="container">
    <category title="美食" :data="foods">
      <img src="https://s3.ax1x.com/2021/01/16/srJIq0.jpg" alt="" />
    </category>

    <category title="游戏" :data="games">
      <ul>
        <li v-for="(item, index) in games" :key="index">{{ item }}</li>
      </ul>
    </category>

    <category title="电影" :data="films">
      <video controls src="https://clips.vorwearts-gmbh.de/big_buck_bunny.mp4"></video>
    </category>
  </div>
</template>

具名插槽

当使用template时,可用v-slot:name.指明插槽位置。

<template>
  <div class="ItemList">
    <h3>{{title}}</h3>
    <slot name='center'></slot>
    <slot name='footer'></slot>
  </div>
</template>
<template>
  <div class="container">
    <ItemList title="美食" :data="foods">
      <img
        slot="center"
        src="https://s3.ax1x.com/2021/01/16/srJIq0.jpg"
        alt=""
      />
      <div class="foot" slot="footer">
        <a href="https://www.atguigu.com" >更多美食</a>
      </div>
      
    </ItemList>

    <ItemList title="游戏" :data="games">
      <ul slot="center">
        <li v-for="(item, index) in games" :key="index">{{ item }}</li>
      </ul>
      <div slot="footer" class="foot">
        <a href="https://www.atguigu.com">单击游戏</a>
        <!-- 可以追加-->
        <a href="https://www.atguigu.com">网络游戏</a>
      </div>
    </ItemList>

    <ItemList title="电影" :data="films">
      <video
        slot="center"
        controls
        src="https://clips.vorwearts-gmbh.de/big_buck_bunny.mp4"
      ></video>
      <template v-slot:footer>
        <div class="foot">
          <a href="">经典</a>
          <!-- 可以追加-->
          <a href="https://www.atguigu.com">热门</a>
          <a href="https://www.atguigu.com">推荐</a>
        </div>
        <h4 slot="footer">welcome to watch!</h4>
      </template>
    </ItemList>
  </div>
</template>

作用域插槽

(也可以有名字)

数据在子组件,结构需要由父组件决定。

需求第一次是无序,第二次是有序,第三次是h4。

可以在app组件传递数据,子组件根据数据进行条件渲染。

弊端是需要写的判断太多。

使用插槽:如果此时games数据不在app里,无法使用。

现需要app组件获取子组件里的数据。

 App里面需要使用Category组件,组件里有一个插槽,且在App里需要数据,数据来自于定义插槽的组件。

数据是一个对象属性名是games,值是数组。所以<slot>可以传递多个数据。

<template>
  <div class="ItemList">
    <h3>{{title}}</h3>
    <slot :gamesMsg='games'></slot>
  </div>
</template>
<template>
  <div class="container">
    
    <ItemList title="游戏" >
      <template scope="gamesMsg">
        <ul>
          <li v-for="(item, index) in gamesMsg.games" :key="index">{{ item }}</li>
        </ul>
      </template>
    </ItemList>

    <ItemList title="游戏">
      <template scope="{gamesMsg}">
        <ol>
          <li style="color:red;" v-for="(item, index) in gamesMsg" :key="index">{{ item }}</li>
        </ol>
      </template>
    </ItemList>

    <ItemList title="游戏" >
       <template slot-scope="{gamesMsg}">
        <h4 v-for="(item, index) in gamesMsg" :key="index">
         {{ item }}
        </h4>
      </template>
    </ItemList>
  </div>
</template>

插槽总结

 

Vuex 

刷新页面时,vue实例重新加载,从而,store也被重置了。store是用来存储组件状态的,而不是用来做本地数据存储的。所以,对于不希望页面刷新之后被重置的数据,使用本地存储来进行存储。

获取数据的时候,在state和cookie中都保存一份。

在Vue的created钩子中,重新commit   store中的方法,从cookie中获取数据设置到state中。

共享数据---全局事件总线实现,bcd需要访问到a里面的x,则需要在bcd中给$bus绑定事件和回调。a中触发事件并传递参数,bcd中触发回调,获取参数。

如果此时bcd中都需要修改x这个数据,此时a需要x修改的值,则此时在a中绑定事件和回调,获取参数,触发回调,在bcd中触发事件,传递参数给a。

 共享数据---vuex实现

求和案例

<template>
  <div class="ItemList">
    <h1>
        sum =:{{sum}}
    </h1>

    <select v-model.number="n">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="evenIncrement">求和为偶数再加</button>
    <button @click="waitIncrement">等一等再加</button>
  </div>
</template>

<script>
export default {
  name:'ItemList',
  
  data() {
    return {
      n:1,
      sum:0,
    };
  },
  methods: {
    increment(){
      this.sum += this.n;
    },
    decrement(){
      this.sum -= this.n; 
    },
    evenIncrement(){
      if(!(this.sum % 2)){

        this.sum += this.n;
      }
    },
    waitIncrement(){
      setTimeout(()=>{
        this.sum += this.n;
      },500)
    }
  },


}
</script>

<style>
  button{
    margin-left: 7px;
  }

</style>

Vuex工作原理图

     在组件中操作,调用dispatch("操作",数据),Actions是一个object对象,Actions里有个key叫"操作",value是一个函数,函数就会被调用,且会收到数据,在这个函数里面,调用commit,Mutations也是一个object对象,Mutations里也有个key叫"操作",value是一个函数,该函数会得到state和数据,在该函数写state.sum += 2,底层自动mutate,State里面的sum就变为了2,然后render,重新解析组件。

     Actions,里面可以发请求,从后端接口中获取数据。也可以进行逻辑判断,如奇数再加,等一等在加等。Vuex运行不通过Actions。

    Mutations是真正操作数据的对象。

    Actions,Mutations,State这三个对象都需要store进行管理。如store.dispatch,store.commit。

需要让所有的组件实例对象都能看见store。

把store传入创建实例的new Vue()的配置参数对象中,会出现在$options中,$options中出现了会在你Vue.use()时执行this.$store = $options.store的操作。

在组件中可使用 this 访问原型上的属性,template 拥有组件实例的上下文,

可直接通过 {{ $store.state.userName }} 访问,等价于 script 中的 this.$store.state.userName。

至于 {{ store.state.userName }},script 中的 data 需声明过 store 才可访问。

对比全局事件总线:

搭建Vuex环境

npm i vuex@3.

必须在创建store实例之前调用Vue.use(Vuex).

在脚手架中, import语句自动提前。

App,子组件上可以看见store。

 index.js:

//该文件用于创建Vuex中最为核心的store

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex);//use Vuex后 ,在Vue配置项可以传入store。

//actions 用于响应组件中的动作
const actions = {};

//mutations 用于真正去操作数据
const mutations = {};

//state 用于存储数据
const state = {};


//创建并导出store
export default new Vuex.Store({
    actions,mutations,state
});

 main.js:
 

/*
该文件为入口文件
*/
import Vue from 'vue'

//引入App组件  所有组件的父组件
import App from './App.vue'
 
//引入store
import store from './store/index';

//关闭vue生产提示
Vue.config.productionTip = false


//创建vue实例对象
new Vue({
  //将App组件放入容器中
  render: h => h(App),
  //store:{},  vm和vc都能看见
  store,
  beforeCreate() {
    //安装全局事件总线
    Vue.prototype.$bus = this;
  },


}).$mount('#app')

求和案例vuex

若只是直接+和-则可以直接调用commit,

若有业务逻辑,则需要先调用dispatch。

methods: {
    increment(){
      this.$store.commit('PLUS',this.n);
    },
    decrement(){
      this.$store.commit('REDUCE',this.n);
    },
    evenIncrement(){
      this.$store.dispatch('evenPlus',this.n);
      
    },
    waitIncrement(){
      this.$store.dispatch('waitPlus',this.n);
    }
  },
//actions 用于响应组件中的动作
const actions = {
    //context:上下文对象
    /*plus(context,value){
        context.commit('PLUS',value)
    },
    reduce(context,value){
        context.commit('REDUCE',value)
    },*/
    evenPlus(context,value){
        if(!(context.state.sum%2)){
            context.commit('PLUS',value)
        }
    },
    waitPlus(context,value){
        setTimeout(() => {
            context.commit('PLUS',value)
        }, 500);
    }
};

//mutations 用于真正去操作数据
const mutations = {
    PLUS(state,value){
        state.sum += value;
    },
    REDUCE(state,value){
        state.sum -= value;
    }
};

//state 用于存储数据  响应式 getset
const state = {
    sum:0,
};

vuex开发工具的使用

Devtools和mutation交互。

为什么在actions中需要使用context而不是直接commit:

在actions的函数里面还可以调用dispatch,还需要context里面的state。

 jiaOdd---demo1----demo2

 为什么在actions中不能通过context.state直接操作数据: 

 此时页面会发生变化,开发者工具失效。

为什么不在组件中进行业务逻辑:

 当业务非常复杂时,代码冗余太高,不存在复用。

 此时所有涉及到该业务的都通过actions。

 因为mutationsactions不支持传递多个参数的,这里的参数又称“载荷”(Payload)。

传递多个参数

let data = {form:form,router:this.$router,message:this.$message}
this.$store.dispatch('user/login',data)

 

getters配置项

计算属性:本组件复用

目前需要跨组件复用

 此时开发者工具也能看见getters

 <h2>
      multiplySum =:{{$store.getters.bigSum}} 
 </h2>



const getters = {
    bigSum(state){
        return state.sum*10;
    }
}



//创建并导出store
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
});

mapState与mapGetters

简化代码: 

ES6语法: 

 只有当a是一个变量的时候才可以简写。

 mapState接收一个对象(数组(名字一致))作为参数,返回的是一个对象:

两者效果相同:

 

computed:{
    /*亲自去写计算属性
    sum(){
      return this.$store.state.sum;
    },*/

    //从state中读取数据,对象写法
    //...mapState({sum:'sum',school:'school',subject:'subject'})

    //从getters中读取数据,数组写法
    ...mapState(['sum','school','subject']),
    ...mapGetters(['bigSum'])
  },

mapActions与mapMutations

此时生成的increment是下面那个:

 当绑定的事件不写小括号时,也会传参,参数是event。

 所以需要这么传参:

也可以这么写:

 

methods: {
    //commit 原始写法
    /*
    increment(){
      this.$store.commit('PLUS',this.n);
    },
    decrement(){
      this.$store.commit('REDUCE',this.n);
    },*/

    //生成对应的方法,方法中会调用commit去联系mutations  对象写法
    ...mapMutations({increment:'PLUS',decrement:'REDUCE'}),
    //数组写法  (需要名字一致)
    //...mapMutations(['PLUS','REDUCE']),


    //dispatch  原始写法
    /*evenIncrement(){
      this.$store.dispatch('evenPlus',this.n);
      
    },
    waitIncrement(){
      this.$store.dispatch('waitPlus',this.n);
    }*/
    //生成对应的方法,方法中会调用commit去联系actions  对象写法
    ...mapActions({evenIncrement:'evenPlus',waitIncrement:'waitPlus'}),
    //数组写法  (需要名字一致)
    //...mapMutations(['evenPlus','waitPlus']),
  },

多组件共享数据

vuex中保存sum和persons,在Item中读取persons,在persons中读取sum。

Vuex:
const state = {
    sum:0,
    school:'atguigu',
    subject:'前端',
    persons:[{id:'001',name:'张三'}]
};


PersonList:
computed:{
        /*personList(){
            return this.$store.state.persons;
        },*/
        ...mapState(['persons']),
        sum(){
            return this.$store.state.sum;
        }
    },
    methods: {
        add(){
            const personObj = {id:nanoid(),name:this.name};
            this.$store.commit('ADD_PERSON',personObj);
            this.name = '';
        },
        
    },


ItemList:
 computed:{
    ...mapState(['sum','school','subject','persons']),
    ...mapGetters(['bigSum'])
  },
  methods: {
    //生成对应的方法,方法中会调用commit去联系mutations  对象写法
    ...mapMutations({increment:'PLUS',decrement:'REDUCE'}),
   
    //生成对应的方法,方法中会调用commit去联系actions  对象写法
    ...mapActions({evenIncrement:'evenPlus',waitIncrement:'waitPlus'}),
  },

vuex模块化+namespace

store里有countOptions,personOptions。

$store.state:

 $store.getters:

 

 item.js:

//求和功能相关的配置
export default{
    namespaced:true,
    actions:{
        evenPlus(context,value){
            if(!(context.state.sum%2)){
                context.commit('PLUS',value)
            }
        },
        waitPlus(context,value){
            setTimeout(() => {
                context.commit('PLUS',value)
            }, 500);
        }
    },
    mutations:{
        PLUS(state,value){
            state.sum += value;
        },
        REDUCE(state,value){
            state.sum -= value;
        },
    },
    state:{
        sum:0,
        school:'atguigu',
        subject:'前端',
    },
    getters:{
        bigSum(state){
            return state.sum*10;
        }
    },
}

persons.js:

import axios from "axios";
import { nanoid } from "nanoid";
//人员管理功能相关的配置
export default{
    namespaced:true,
    actions:{
        addPersonWang(context,value){
            if(value.name.indexOf('王') === 0){
                context.commit('ADD_PERSON',value);
            }else{
                alert('添加的人需要姓王!')
            }
        },
        addPersonSever(context){
            axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
                response => {
                    context.commit('ADD_PERSON',{id:nanoid(),name:response.data});
                },
                error =>{
                    alert(error.message);
                }
            )
        }
    },
    mutations:{
        ADD_PERSON(state,value){
            state.persons.unshift(value);
        }
    },
    state:{
        persons:[{id:'001',name:'张三'}]
    },
    getters:{
        firstPersonName(state){
            return state.persons[0].name;
        }
    },
}

index.js:

//该文件用于创建Vuex中最为核心的store

import Vuex from 'vuex'
import Vue from 'vue'
import countOptions from './item'
import personOptions from './persons'
Vue.use(Vuex);//use Vuex后 ,在Vue配置项可以传入store。

//创建并导出store
export default new Vuex.Store({
    modules:{
        countOptions,
        personOptions
    }
});

personList.vue:
 

<template>
    <div>
        <h1>人员列表</h1>
        <input type="text" value="请输入名字" v-model="name">
        <button @click="add">添加</button>
        <ul>
            <li v-for='p in persons' :key='p.id'>{{p.name}}</li>
        </ul>
        <h3>sum:{{sum}}</h3>
        <h3>列表中第一个人的名字:{{firstPersonName}}</h3>
        <button @click="addWang">添加一个姓王的人</button>
        <button @click="addPersonServer">添加一个随机名字的人</button>
    </div>
</template>



<script>
import {mapState} from 'vuex';
import {nanoid} from 'nanoid';
export default {
    name:'PersonList',
    data(){
        return{
            name:'',
        }
    },
    computed:{
        /*personList(){
            return this.$store.state.persons;
        },*/
        ...mapState('personOptions',['persons']),
        sum(){
            //总的state
            return this.$store.state.countOptions.sum;
        },
        firstPersonName(){
            return this.$store.getters['personOptions/firstPersonName']
        } 
    },
    methods: {
        add(){
            const personObj = {id:nanoid(),name:this.name};
            this.$store.commit('personOptions/ADD_PERSON',personObj);
            this.name = '';
        },
        addWang(){
            const personObj = {id:nanoid(),name:this.name};
            this.$store.dispatch('personOptions/addPersonWang',personObj);
            this.name = '';
        },
        addPersonServer(){
            this.$store.dispatch('personOptions/addPersonSever')
        }
        
    },
}
</script>


<style>

</style>

ItemList.vue:

<template>
  <div class="ItemList">
    <h1>
        sum =:{{sum}}
    </h1>
    <h2>
      multiplySum =:{{bigSum}} 
    </h2>
    <h2>
      I am at{{school}} learn {{subject}}
    </h2>
    <h2>
      人数:{{persons.length}}
    </h2>

    <select v-model.number="n">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="evenIncrement(n)">求和为偶数再加</button>
    <button @click="waitIncrement(n)">等一等再加</button>
    
  </div>

</template>

<script>
import {mapState,mapGetters, mapMutations,mapActions} from 'vuex';
export default {
  name:'ItemList',
  data() {
    return {
      n:1,
    };
  },
  computed:{
    ...mapState('countOptions',['sum','school','subject']),
    ...mapState('personOptions',['persons']),
    ...mapGetters('countOptions',['bigSum'])
  },
  methods: {
    //生成对应的方法,方法中会调用commit去联系mutations  对象写法
    ...mapMutations('countOptions',{increment:'PLUS',decrement:'REDUCE'}),
   
    //生成对应的方法,方法中会调用commit去联系actions  对象写法
    ...mapActions('countOptions',{evenIncrement:'evenPlus',waitIncrement:'waitPlus'}),
  },
}
</script>

<style>
  button{
    margin-left: 7px;
  }

</style>

 this.$store:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值