【Vue】Vue2.0+Vue3.0学习笔记day11(Vuex)

目录

102.默认插槽

103.具名插槽

104.作用域插槽

105.Vuex简介

106.就和案例_纯vue版

107.Vuex工作原理图

108.搭建Vuex环境

109.求和案例_Vuex版

110.Vuex开发者工具的使用

111.getter配置项

112.mapState和mapGetters

113.mapAction与mapMutations

114.多组件共享数据

115.Vuex模块化_namespace1

116.Vuex模块化_namespace2


102.默认插槽

  不使用插槽

<template> 
  <div class="container">
    <Category title="美食" :listData="foods"></Category>
    <Category title="游戏" :listData="games"></Category>
    <Category title="电影" :listData="filsm"></Category>
</div>
</template>

<script>
    import Category from "./components/Category.vue";
    export default {
        name:'App',
        components:{
           Category
        },
        data() {
            return {
               foods:['火锅','烧烤','小龙虾'],
               games:['王者','吃鸡','lol'],
               filsm:['《功夫》','《大话西游》','《喜剧之王》']               
            }
        },       
    }
</script>

<style>
    .container{
        display: flex;
        justify-content: space-around;
    }
</style>

<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <ul>
            <li v-for="(item, index) in listData" :key="index">{{item}}</li>
        </ul>
    </div>
</template>

<script>

export default {
    name:'Category',
    props:['listData','title']
}
</script>

<style>
    .category{
        background-color: skyblue;
        width: 200px;
        height: 200px;
    }
    h3{
        text-align: center;
        background-color: orange;
    }
</style>

 使用默认插槽

<template> 
  <div class="container">
    <Category title="美食" :listData="foods">
        <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg">
    </Category>
    <Category title="游戏" :listData="games">
        <ul>
            <li v-for="(g, index) in games" :key="index">{{g}}</li>
        </ul>
    </Category>
    <Category title="电影" :listData="filsm">
        <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    </Category>
</div>
</template>

<script>
    import Category from "./components/Category.vue";
    export default {
        name:'App',
        components:{
           Category
        },
        data() {
            return {
               foods:['火锅','烧烤','小龙虾'],
               games:['王者','吃鸡','lol'],
               filsm:['《功夫》','《大话西游》','《喜剧之王》']               
            }
        },       
    }
</script>

<style>
    .container{
        display: flex;
        justify-content: space-around;
    }
    video{
        width: 100%;
    }
    img{
        width: 100%;
    }
</style>

<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <!-- 定义一个插槽 -->
        <slot></slot>
    </div>
</template>

<script>

export default {
    name:'Category',
    props:['title']
}
</script>

<style>
    .category{
        background-color: skyblue;
        width: 200px;
        height: 300px;
    }
    h3{
        text-align: center;
        background-color: orange;
    }
</style>

103.具名插槽

<template> 
  <div class="container">
    <Category title="美食" :listData="foods">
        <img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg">
        <a slot="footer" href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">更多美食</a>
    </Category>
    <Category title="游戏" :listData="games">
        <ul slot="center">
            <li v-for="(g, index) in games" :key="index">{{g}}</li>
        </ul>
        <div class="foot" slot="footer">
            <a href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">单机游戏</a>
            <a href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">网络游戏</a>
        </div>
    </Category>
    <Category title="电影" :listData="filsm">
        <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
        <template v-slot:footer>
            <div class="foot">
                <a href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">经典</a>
                <a href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">热门</a>
                <a href="https://blog.csdn.net/weixin_58214412?spm=1008.2028.3001.5343">推荐</a>
            </div>
            <h4>欢迎来观影</h4>
        </template>
    </Category>
</div>
</template>

<script>
    import Category from "./components/Category.vue";
    export default {
        name:'App',
        components:{
           Category
        },
        data() {
            return {
               foods:['火锅','烧烤','小龙虾'],
               games:['王者','吃鸡','lol'],
               filsm:['《功夫》','《大话西游》','《喜剧之王》']               
            }
        },       
    }
</script>

<style>
    .container,.foot{
        display: flex;
        justify-content: space-around;
    }
    video{
        width: 100%;
    }
    img{
        width: 100%;
    }
    h4{
        text-align: center;
    }
</style>

<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <!-- 定义一个插槽 -->
        <slot name="center"></slot>
        <slot name="footer"></slot>
    </div>
</template>

<script>

export default {
    name:'Category',
    props:['title']
}
</script>

<style>
    .category{
        background-color: skyblue;
        width: 200px;
        height: 300px;
    }
    h3{
        text-align: center;
        background-color: orange;
    }
</style>

104.作用域插槽

<template> 
  <div class="container">
    <Category title="游戏" :listData="games">
        <template scope="a">
            <ul>
                <li v-for="(g, index) in a.games" :key="index">{{g}}</li>
            </ul>   
        </template>
    </Category>
    <Category title="游戏" :listData="games">
        <!-- {games}结构赋值 -->
        <template scope="{games}">
            <ol>
                <li v-for="(g, index) in games" :key="index">{{g}}</li>
            </ol>   
        </template>
    </Category>
    <Category title="游戏" :listData="games">
        <!-- slot-scope新的API -->
        <template slot-scope="{games}">
            <h4 v-for="(g, index) in games" :key="index">{{g}}</h4>
        </template>
    </Category>
</div>
</template>

<script>
    import Category from "./components/Category.vue";
    export default {
        name:'App',
        components:{
           Category
        },      
    }
</script>

<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <!-- 定义一个插槽 -->
        <slot :games="games">我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    </div>
</template>

<script>

export default {
    name:'Category',
    props:['title'],
    data() {
        return {
            games:['王者','吃鸡','lol']         
        }
    }, 
}
</script>
## 插槽
   1.作用:让父组件可以向子组件指定位置插入HTML结构,也是一种组件间通信的方式,使用于父组件===>子组件
   2.分类:默认插槽、具名插槽、作用域插槽
   3.使用方法:作用域插槽的数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定

105.Vuex简介

概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件通信

什么时候使用Vuex

1.多个组件依赖于同一状态      2.来自不同组件的行为需要变更同一状态

 

106.就和案例_纯vue版

<template>
    <div>
       <h1>当前求和为:{{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="decteent">-</button>
       <button @click="incerentOdd">当前求和为奇数再加</button>
       <button @click="incerentWait">等一等再加</button>
    </div>
</template>

<script>

export default {
    name:'Count',
    data() {
        return {
            n:1, //用户选择的数字
            sum:0 //当前的和
        }
    },
    methods: {
        increment(){
            this.sum +=this.n
        },
        decteent(){
            this.sum -= this.n
        },
        incerentOdd(){
            // 0的布尔值是false
            if(this.sum % 2){
                this.sum += this.n
            }
        },
        incerentWait(){
            setTimeout(()=>{
                this.sum += this.n
            },500)
        },
    },
}
</script>

<style>
    button{
        margin-left: 5px;
    }
</style>
<template> 
  <div>
    <Count></Count>
</div>
</template>

<script>
    import Count from "./components/Count.vue";
    export default {
        name:'App',
        components:{
           Count
        },      
    }
</script>

107.Vuex工作原理图

actions行为动作,mutations加工维护,state保存数据,dispatch和commit是两个API,backend api后端接口,devtools开发者调式工具

 当发生一个动作的值需要发送Ajax请求获取的时候,在action发送Ajax请求

组件可以直接调用commit ,没有需要判断的简单业务逻辑可以直接调用

 store(仓库)管理actions,mutations和state,提供ispatch和commit这两个API

108.搭建Vuex环境

   安装vuex

npm i vuex

 在src下创建store文件夹

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

// 引入vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用vuex
Vue.use(Vuex)

// 准备actions用于响应组件中的动作
const actions = {}
// 准备mutations用于操作数据(state)
const mutations = {}
// 准备state用于存储数据
const state = {}

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

在main.js引入store并在传入配置项

// 引入vue
import Vue from 'vue'
// 引入App组件,它是所有组件的父组件
import App from './App.vue'

// 引入store
import store from './store/index'
// 关闭vue的生产提示
Vue.config.productionTip = false

// 创建vue的实例对象--vm
new Vue({
  // 将App组件放入容器中
  render: h => h(App),
  store,
  beforeCreate(){
    Vue.prototype.$bus = this
  }
}).$mount('#app')

109.求和案例_Vuex版

<template>
    <div>
       <h1>当前求和为:{{$store.state.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="decteent">-</button>
       <button @click="incerentOdd">当前求和为奇数再加</button>
       <button @click="incerentWait">等一等再加</button>
    </div>
</template>

<script>

export default {
    name:'Count',
    data() {
        return {
            n:1, //用户选择的数字
        }
    },
    methods: {
        increment(){
            // this.$store.dispatch('jia',this.n)
            this.$store.commit('JIA',this.n)
        },
        decteent(){
            // this.$store.dispatch('jian',this.n)
            this.$store.commit('JIAN',this.n)
        },
        incerentOdd(){
            this.$store.dispatch('jiaOdd',this.n)
        },
        incerentWait(){
            this.$store.dispatch('jiaWait',this.n)
        },
    },
}
</script>

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

 在store中

// 引入vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用vuex
Vue.use(Vuex)

// 准备actions用于响应组件中的动作
const actions = {
    /* jia(context,value){
        context.commit('JIA',value)
    },
    jian(context,value){
        context.commit('JIAN',value)
    }, */
    jiaOdd(context,value){
        if(context.state.sum % 2)
        context.commit('JIA',value)
    },
    jiaWait(context,value){
        setTimeout(() => {
            context.commit('JIA',value)
        }, 500);
    },
}
// 准备mutations用于操作数据(state)
const mutations = {
    JIA(state,value){
        state.sum += value
    },
    JIAN(state,value){
        state.sum -= value
    },
}
// 准备state用于存储数据
const state = {
    sum:0 //当前的和
}

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

110.Vuex开发者工具的使用

111.getter配置项

​
// 准备getters用于将stade中的数据进行加工
const getters = {
    bigSum(state){
        return state.sum*10
    }
}

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

​
<template>
    <div>
       <h1>当前求和为:{{$store.state.sum}}</h1> 
       <h3>当前求和放大10倍为:{{$store.getters.bigSum}}</h3>
       <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="decteent">-</button>
       <button @click="incerentOdd">当前求和为奇数再加</button>
       <button @click="incerentWait">等一等再加</button>
    </div>
</template>

112.mapState和mapGetters

<template>
    <div>
       <h1>当前求和为:{{sum}}</h1> 
       <h3>当前求和放大10倍为:{{bigSum}}</h3>
       <h3>我在{{school}}学习{{subject}}</h3>
       <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="decteent">-</button>
       <button @click="incerentOdd">当前求和为奇数再加</button>
       <button @click="incerentWait">等一等再加</button>
    </div>
</template>

<script>
import { mapState,mapGetters } from "vuex";
export default {
    name:'Count',
    data() {
        return {
            n:1, //用户选择的数字
        }
    },
    methods: {
        increment(){
            // this.$store.dispatch('jia',this.n)
            this.$store.commit('JIA',this.n)
        },
        decteent(){
            // this.$store.dispatch('jian',this.n)
            this.$store.commit('JIAN',this.n)
        },
        incerentOdd(){
            this.$store.dispatch('jiaOdd',this.n)
        },
        incerentWait(){
            this.$store.dispatch('jiaWait',this.n)
        },
    },
    computed:{
        // 靠程序员自己亲自去写计算属性
        /* sum(){
            return this.$store.state.sum
        },
        school(){
            return this.$store.state.school
        },
        subject(){
            return this.$store.state.subject
        },
         bigSum(){
            return this.$store.getters.bigSum
        } 
        */
        // 借助mapState生成计算属性,从state中读取数据(对象写法)
        // ...mapState({sum:'sum',school:'school',subject:'subject'}),
        // 借助mapState生成计算属性,从state中读取数据(数组写法)
        ...mapState(['sum','school','subject']),

        // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
        // ...mapGetters({bigSum:'bigSum'})
        ...mapGetters(['bigSum'])
    },
    
}
</script>

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

// 准备state用于存储数据
const state = {
    sum:0, //当前的和
    school:'新东方',
    subject:'颠大锅'
}

113.mapAction与mapMutations

备注:mapAction与mapMutations使用时,若需要传递参数要在模板绑定事件时传递好参数,否则参数是事件对象

<template>
    <div>
       
       <button @click="increment(n)">+</button>
       <button @click="decteent(n)">-</button>
       <button @click="incerentOdd(n)">当前求和为奇数再加</button>
       <button @click="incerentWait(n)">等一等再加</button>
    </div>
</template>

<script>
import { mapState,mapGetters,mapMutations,mapActions } from "vuex";
export default {
    name:'Count',
    
    methods: {
        /* increment(){
            // this.$store.dispatch('jia',this.n)
            this.$store.commit('JIA',this.n)
        },
        decteent(){
            // this.$store.dispatch('jian',this.n)
            this.$store.commit('JIAN',this.n)
        }, */
        // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
        ...mapMutations({increment:'JIA',decteent:'JIAN'}),
        // ...mapMutations(['JIA','JIAN']),

        /* incerentOdd(){
            this.$store.dispatch('jiaOdd',this.n)
        },
        incerentWait(){
            this.$store.dispatch('jiaWait',this.n)
        }, */
        // 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
        ...mapActions({incerentOdd:'jiaOdd',incerentWait:'jiaWait'}),
        // ...mapActions(['jiaOdd','jiaWait'])
    },
   
    
}
</script>

114.多组件共享数据

 新建组件person

<template>
  <div>
      <h1>人员列表</h1>
      <h3 style="color:red">Count组件求和为:{{sum}}</h3>
      <input type="text" placeholder="请输入名字" v-model="name">
      <button @click="add">添加</button>
      <ul>
          <li v-for="p in personList" :key="p.id">{{p.name}}</li>
      </ul>
  </div>
</template>

<script>
import { nanoid } from 'nanoid'
export default {
    name:'Person',
    data() {
        return {
            name:''
        }
    },
    computed:{
        personList(){
            return this.$store.state.personList
        },
        sum(){
            return this.$store.state.sum
        }
    },
    methods:{
        add(){
            const personObj = {id:nanoid(),name:this.name}
            this.$store.commit('ADD_PERSON',personObj)
            this.name = ''
        }
    }   
}
</script>

 在store/index.js中 

// 准备mutations用于操作数据(state)
const mutations = {
    JIA(state,value){
        state.sum += value
    },
    JIAN(state,value){
        state.sum -= value
    },
    ADD_PERSON(state,value){
        state.personList.unshift(value)
    }
}

 在count中

<h3 style="color:red">person组件列表的总人数是:{{personList.length}}</h3>

 computed:{
        // 借助mapState生成计算属性,从state中读取数据(对象写法)
        // ...mapState({sum:'sum',school:'school',subject:'subject'}),
        // 借助mapState生成计算属性,从state中读取数据(数组写法)
        ...mapState(['sum','school','subject','personList']),

        // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
        // ...mapGetters({bigSum:'bigSum'})
        ...mapGetters(['bigSum'])
    },

115.Vuex模块化_namespace1

 新建src/store/count.js文件

// 求和相关的配置
export default {
    // 开启命名空间
    namespaced:true,
    actions:{
        jiaOdd(context,value){
            if(context.state.sum % 2)
            context.commit('JIA',value)
        },
        jiaWait(context,value){
            setTimeout(() => {
                context.commit('JIA',value)
            }, 500);
        },
    },
    mutations:{
        JIA(state,value){
            state.sum += value
        },
        JIAN(state,value){
            state.sum -= value
        },
    },
    state:{
        sum:0, //当前的和
        school:'新东方',
        subject:'颠大锅',
    },
    getters:{
        bigSum(state){
            return state.sum*10
        }
    },
}

新建src/store/person.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('添加的人必须姓王')
            }
        },
        addPersonServer(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.personList.unshift(value)
        }
    },
    state:{
        personList:[
            {id:'001',name:'张三'}
        ]
    },
    getters:{
        firstPersonName(state){
            return state.personList[0].name
        }
    },
}

 在store/index.js中

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

// 引入vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
import countOptions from './count'
import personOptions from './person'
// 使用vuex
Vue.use(Vuex)


// 创建并导出store
export default new Vuex.Store({
    // 模块化分类
    modules:{
        a:countOptions,
        b:personOptions
    }
})

 main.js 

// 引入vue
import Vue from 'vue'
// 引入App组件,它是所有组件的父组件
import App from './App.vue'

// 引入store
import store from './store/index'
// 关闭vue的生产提示
Vue.config.productionTip = false

// 创建vue的实例对象--vm
new Vue({
  // 将App组件放入容器中
  render: h => h(App),
  store,
  beforeCreate(){
    Vue.prototype.$bus = this
  }
}).$mount('#app')

<template>
    <div>
       <h1>当前求和为:{{sum}}</h1> 
       <h3>当前求和放大10倍为:{{bigSum}}</h3>
       <h3>我在{{school}}学习{{subject}}</h3>
       <h3 style="color:red">person组件列表的总人数是:{{personList.length}}</h3>
       <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="decteent(n)">-</button>
       <button @click="incerentOdd(n)">当前求和为奇数再加</button>
       <button @click="incerentWait(n)">等一等再加</button>
    </div>
</template>

<script>
import { mapState,mapGetters,mapMutations,mapActions } from "vuex";
export default {
    name:'Count',
    data() {
        return {
            n:1, //用户选择的数字
        }
    },
    methods: {
        // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
        ...mapMutations('a',{increment:'JIA',decteent:'JIAN'}),
        // 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
        ...mapActions('a',{incerentOdd:'jiaOdd',incerentWait:'jiaWait'}),
    },
    computed:{
        // 借助mapState生成计算属性,从state中读取数据(数组写法)
        ...mapState('a',['sum','school','subject']),
        ...mapState('b',['personList']),

        ...mapGetters('a',['bigSum'])
    },
    
}
</script>

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

<template>
  <div>
      <h1>人员列表</h1>
      <h3 style="color:red">Count组件求和为:{{sum}}</h3>
      <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
      <input type="text" placeholder="请输入名字" v-model="name">
      <button @click="add">添加</button>
      <button @click="addWang">添加一个姓王的人</button>
      <button @click="addServer">添加一个人,名字随机</button>
      <ul>
          <li v-for="p in personList" :key="p.id">{{p.name}}</li>
      </ul>
  </div>
</template>

<script>
import { nanoid } from 'nanoid'
export default {
    name:'Person',
    data() {
        return {
            name:''
        }
    },
    computed:{
        personList(){
            return this.$store.state.b.personList
        },
        sum(){
            return this.$store.state.a.sum
        },
        firstPersonName(){
            return this.$store.getters['b/firstPersonName']
        }
    },
    methods:{
        add(){
            const personObj = {id:nanoid(),name:this.name}
            this.$store.commit('b/ADD_PERSON',personObj)
            this.name = ''
        },
        addWang(){
            const personObj = {id:nanoid(),name:this.name}
            this.$store.dispatch('b/addPersonWang',personObj)
            this.name = ''
        },
        addServer(){
             this.$store.dispatch('b/addPersonServer')
        }
    }   
}
</script>

<template> 
  <div>
    <Count></Count>
    <hr>
    <Person></Person>
</div>
</template>

<script>
    import Count from "./components/Count.vue";
    import Person from "./components/Person.vue";
    export default {
        name:'App',
        components:{
           Count,
           Person
        },      
    }
</script>

116.Vuex模块化_namespace2

## 模块化+命名空间
   1.目的:让代码更好维护,让多种数据分类更加明确
   2.开启命名空间后,组件中读取state数据:
      this.$store.state.a.sum
      ...mapState('a',['sum','school','subject']),
   3.开启命名空间后,组件中读取getters数据:
      this.$store.getters['b/firstPersonName']
      ...mapGetters('a',['bigSum'])
   4.开启命名空间后,组件中读取dispatch数据:
      this.$store.dispatch('b/addPersonWang',personObj)
      ...mapActions('a',{incerentOdd:'jiaOdd',incerentWait:'jiaWait'}),
   5.开启命名空间后,组件中读取commit数据:\
      this.$store.commit('b/ADD_PERSON',personObj)
      ...mapMutations('a',{increment:'JIA',decteent:'JIAN'}),

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值