vue part 10

vue-resource

在vue1.0时代讲的比较多,是vue.插件库,

javascript 复制代码
import vueResource from 'vue-resource'

Vue.use(vueResource)

在vc和vm中会多出如下F12代码即,$http:()

他的用法和返回值和axios一模一样,但是不常维护了

插槽

默认插槽

App.vue的Category标签不起作用,因为在Category.vue的????究竟放在哪vue不知道;因此通过slot来表明位置

App.vue

html 复制代码
<template>
   <div class="container">
     <Category title="美食">
       <img src="" alt="delicious food"/>
     </Category>

     <Category title="游戏" :listData="games">
       <ul>
         <li v-for="(g , index) in games" :key="index">{{ g }}</li>
       </ul>
     </Category>

     <Category title="电影">
       <video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" controls></video>
     </Category>
   </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  components:{
    Category
  },
  data(){
    return {
      foods:['火锅','烧烤','小龙虾','牛排'],
      games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
      films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
    }
  }
}
</script>
<style lang="css" scoped>
   .container{
     display: flex;
     justify-content: space-around;
   }
   video {
     width: 100%;
   }
   img{
     width: 100%;
   }
</style>

components文件夹的 category.vue

html 复制代码
<template>
  <div class="category">
    <h3>{{ title }}</h3>
    <!--插槽,等着组件的使用者进行填充-->
    <slot>我是默认值,当使用者没有传递具体结构时,我会出现</slot>
  </div>
</template>

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

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

最基础的main.js

javascript 复制代码
//引入Vue
import Vue from "vue";
//引入vue-resource
//引入App
import App from './App';

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


new Vue({
    el: '#app',
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this;
    }
});

具名插槽

如果有一天出现多个插槽,就需要多个名字来联合使用

看见两个插槽,vue默认给了double双份,因此必须给各自的name,

如果不向插槽里面放东西,就会出现slot里面的文字,因此App.vue就需要slot

slot现在弃用了 用v-slot 并且只能在template里使用 或者v-slot="name"简写为#name

此话存疑,因为在vue官网上仍然可以搜索到。好吧,上述更新是2.6提出的版本更新

App.vue

html 复制代码
<template>
   <div class="container">
     <Category title="美食">
       <img slot="center" src="" alt="delicious food"/>
       <a href="https://www.baidu.com" slot="footer">百度</a>
     </Category>

     <Category title="游戏" :listData="games">
       <ul slot="center">
         <li v-for="(g , index) in games" :key="index">{{ g }}</li>
       </ul>
       <div slot="footer" class="foot">
         <a href="https://www.baidu.com">单机游戏</a>
         <a href="https://www.baidu.com">网络游戏</a>
       </div>
     </Category>

     <Category title="电影">
       <video slot="center" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" controls></video>
       <!--但是注意v-slot仅仅只能被用在组件上或者template标签上-->
       <template v-slot:footer>
         <div class="foot">
           <a href="https://www.baidu.com">经典</a>
           <a href="https://www.baidu.com">热门</a>
           <a href="https://www.baidu.com">推荐</a>
         </div>
         <h4>欢迎来到影院观赏</h4>
       </template>
     </Category>
   </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  components:{
    Category
  },
  data(){
    return {
      foods:['火锅','烧烤','小龙虾','牛排'],
      games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
      films:['《教父》','《拆弹专家》','《你好,李焕英》','《尚硅谷》']
    }
  }
}
</script>
<style lang="css" scoped>
   .container, .foot{
     display: flex;
     justify-content: space-around;
   }
   h4{
     text-align: center;
   }
</style>

main.js无变化,Category.vue如下

html 复制代码
<template>
  <div class="category">
    <h3>{{ title }}</h3>
    <!--插槽,等着组件的使用者进行填充-->
    <slot name="center">我是默认值</slot>
    <slot name="footer">我是默认值</slot>
  </div>
</template>

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

<style scoped>
   .category{
     background: skyblue;
     width: 200px;
     height: 300px;
   }
   h3{
     text-align: center;
     background: orange;
   }
   img{
     width: 100%;
   }
   video{
     width: 100%;
   }
</style>

作用域插槽

App组件是Category组件的使用者,Category的数据即data,当数据放在App里面,

104_尚硅谷Vue技术_作用域插槽_哔哩哔哩_bilibili

vuex

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

2.Github地址:https://github.com/vuejs/vuex

单纯的使用全局事件总线导致线太多了,在较多组件容易混淆哎

因此映入了Vuex,

1.多个组件依赖于同一状态

2.来自不同组件的行为需要变更同一状态,总结就是一个"共享"

小案例

Count.vue

html 复制代码
<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="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>
<script>
export default {
    name: 'Count',
    data() {
        return {
            n: 1,// 用户选择的数字
            sum: 0 //当前的和
        }
    },
    methods:{
        //可以整合但没必要,真实开发中后期不断加新需求一个方法会变得很乱
        increment() {
            this.sum += this.n;
        },//导致字符串拼接,导致类型错误.就是13+2=132
        //因此在option用冒号,直接认为成JS表达式,数字解析
        //或者v-model.number
        decrement() {
            this.sum -= this.n;
        },
        incrementOdd() {
            if(this.sum % 2 === 0) {
                this.sum += this.n;
            }
        },
        incrementWait() {
            setTimeout(() => {
                this.sum += this.n;
            }, 1000);
        }
    }
}
</script>
<style lang="css">

App.vue

html 复制代码
<template>
   <div>
     <Count/>
   </div>
</template>

<script>
import Count from "@/components/Count";
export default {
  name: "App",
  components:{
    Count
  },
}
</script>
<style lang="css" scoped>

</style>

main.js仍然保持相同

Vuex工作原理

简单说:Mutations 能直接操作 State,但不能进行异步操作;而 Actions 可以进行异步操作,但不能直接操作 State,所以异步后通过 Mutations 修改 State 这个actions主要处理mounted,向服务器发异步请求,然后获取数据,修改,保存到state仓库中,然后通过mapState组件能拿到,然后进行遍历数组动态展示数据,这就是前台项目的大部分功能

store来管理vuex那三部分,store.commit()

vue2中要用vuex的3版本,vue3中vuex的4版本,所以要安装vuex3版本。

bash 复制代码
npm i vuex@3

main.js

javascript 复制代码
//引入Vue
import Vue from 'vue' //App
import App from './App. vue' //引入插件
import vueResource from 'vue-resource' //引入vuex
import Vuex from 'vuex' 

//关闭Vue的生产提示
Vue. config. productionTip false 
//使用插件
Vue.use(vueResource) 
Vue.use(Vuex)

//创建vm 
new Vue({ 
    //可以传入store配置项,vc,vm均可
    el:'#app',
    render: h = h(App), 
    beforeCreate(){
    Vue.prototype.$bus =this 
    }
}) 

有两种选择:

1.在项目文件夹中新建vuex文件夹,里面store.js 2.新建的store文件夹,里面有index.js(官网写法)

index.js 脚手架解析import规则:..........................................................................................

开发环境搭建是import语句顺序调换,文件改写等等

求和案例vuex版

main.js

javascript 复制代码
//引入Vue
import Vue from "vue";
//引入App
import App from './App';
//引入store
import store from './store';

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

new Vue({
    el: '#app',
    store,
    render: h => h(App),
});

store的index.js

javascript 复制代码
/**
 * 该文件用于创建vuex中最核心的store
 */

//引入Vuex
import Vuex from 'vuex';
import Vue from "vue";

//使用vuex来集中管理状态,必要
//new store的前提是必须要使用Vuex插件
Vue.use(Vuex);

//创建actions(本质就是对象) 用于响应组件中的动作
const actions = {
    //收到上下文对象(包含commit)和dispatch过来的值
    // increment(context, value){
    //     context.commit('INCREMENT', value);
    // },
    // decrement(context, value){
    //     context.commit('DECREMENT', value);
    // },
    incrementIfOdd(context, value) {
        // console.log(`action中的incrementIfOdd被调用`);
        // console.log('处理了一些事情');
        // context.dispatch('demo1', value);
        if (context.state.sum % 2) {
            console.log('@')
            context.commit('INCREMENT', value);
            // context.state.sum += 1;//这样可以实现但是记住本次对状态的改变开发者工具将无法捕获,因为开发者工具是对mutations对话的
        }
    },
    incrementWait(context, value) {
        setTimeout(() => {
            context.commit('INCREMENT', value);
        }, 500)
    },
    // demo1(context, value){
    //     console.log('处理了一些事情---demo1');
    //     context.dispatch('demo2', value);
    // },
    // demo2(context, value){
    //     console.log('在action的demo中完成最终的逻辑');
    //     if(context.state.sum % 2) {
    //         console.log('@')
    //         context.commit('INCREMENT',value);
    //     }
    // }
}

//创建mutations(本质也是对象) 用于修改数据(state)
const mutations = {
    //收到state和要操作数value
    INCREMENT(state, value) {
        state.sum += value;
    },
    DECREMENT(state, value) {
        state.sum -= value;
    },
}

//准备getters用于加工state,将其共享于各个组件当中
const getters = {
    bigSum(state) {
        return state.sum * 10;
    }
}

//准备state(数据) 存储数据
//类似于各个组件里的computed(计算属性),只不过它是共享的
const state = {
    sum: 0,
    school: 'Wust',
    subject: 'Computer Science',
}


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

App.vue

html 复制代码
<template>
   <div>
     <Count/>
   </div>
</template>

<script>
import Count from "@/components/Count";
export default {
  name: "App",
  components:{
    Count
  },
  mounted() {
    console.log('App', this);
  }
}
</script>
<style lang="css" scoped>

</style>

components的Count.vue

html 复制代码
<template>
  <div>
    <h1>当前求和为: {{ sum }}</h1>
    <!--让其收集到的数据全是number类型的 number修饰符-->
    <h3>当前求和放大3倍为:{{ bigSum }}</h3>
    <h3>我在{{ school }}, 学习{{ subject }}</h3>
    <select v-model.number="n">
      <!--让所有的value全部绑定为数字-->
      <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="incrementIfOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions} from 'vuex';
export default {
  //计数组件
  name: "Count",
  data(){
    return {
      n: 1,// 代表用户在select框开始的时候选择的数字
    }
  },
  computed:{
    //借助mapState从state中生成计算属性,对象写法
    // ... mapState({
    //   sum:'sum',
    //   school: 'school',
    //   subject: 'subject'
    // }),
    //借助mapState从state中生成计算属性,数组写法(即代表了生成的计算属性名为sum,同时也代表了从state找到sum)
    ... mapState(['sum', 'school', 'subject']),

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

  },
  methods:{
    // increment(){
    //   this.$store.commit('INCREMENT', this.n);
    // },
    // decrement(){
    //   this.$store.commit('DECREMENT', this.n);
    // },
    //借助mapMutations生成对应方法,方法会调用commit去联系mutations,对象写法
    ...mapMutations({
      increment: 'INCREMENT',
      decrement: 'DECREMENT',
    }),
    //借助数组写法生成方法,但注意你生成的方法名和mutations里对应的方法名将会一样的
    // ...mapMutations(['increment', 'decrement']),

    // incrementOdd(){
    //   this.$store.dispatch('incrementIfOdd', this.n);
    // },
    // incrementWait(){
    //   this.$store.dispatch('incrementWait', this.n);
    // }

    //借助mapMutations生成对应方法,方法会调用dispatch去联系actions,对象写法
    // ...mapActions({
    //   incrementIfOdd: 'incrementIfOdd',
    //   incrementWait: 'incrementWait',
    // }),

    ...mapActions(['incrementWait', 'incrementIfOdd']), //数组写法,同上
  },
}
</script>

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

因为本来就是为中大型项目设计的,小项目vue页不推荐

vuex开发者工具

和vue工具同属一套,在界面上的action都会显示了可以时间穿梭,如果提前穿梭清除某事件,该事件之后的全部消失

点击下载按钮会把当前操作全部汇总到base state中

dispatch的作用

2.组件中读取vuex中的数据:store.state.sum

3.组件中修改vuex中的数据:store.dispatch('action中的方法名',数据)store.commit('mutations中的方法名',数据 66

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

getters可以跨组件使用,比如替代computed的使用,

对代码的优化

写太多$store.state了

重写sum成return this.$store.state.sum,以此类推

但是然后进一步思考,vuex官方有一个这种批量生成的库:

python 复制代码
import {mapState} from 'vuex'

4个map的方法mapState mapGetters 与mapActions mapMutaions

前两个主要用于computed做简写,那后两个是methods的简写

113_尚硅谷Vue技术_mapActions与mapMutations_哔哩哔哩_bilibili最体现对vue理解的一集

多组件共享数据

placeholder 属性提供可描述输入字段预期值的提示信息(hint)。 该提示会在输入字段为空时显示,并会在字段获得焦点时消失。

只要在mapState中声明一下personList即可

Person.vue

html 复制代码
<template>
   <div>
     <h1>人员列表</h1>
     <h2 style="color:skyblue;">Count组件求和为:{{ sum }}</h2>
     <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 { mapState } from 'vuex';
import {nanoid} from "nanoid";
export default {
  name: "Person",
  data(){
    return {
      name: '',
    }
  },
  methods:{
     add(){
       const perObj = {
         id: nanoid(),
         name: this.name,
       }
       console.log(perObj);
       this.name = '';
       this.$store.commit('ADD_PERSON', perObj);
     }
  },
  computed:{
    // ...mapState(['personList']),
    personList(){
      return this.$store.state.personList;
    },
    sum(){
      return this.$store.state.sum;
    }
  },
}
</script>

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

现在就有两个组件了,在index.js中state添加,Count.vue修改如下

html 复制代码
<template>
  <div>
    <h1>当前求和为: {{ sum }}</h1>
    <!--让其收集到的数据全是number类型的 number修饰符-->
    <h3>当前求和放大3倍为:{{ bigSum }}</h3>
    <h3>我在{{ school }}, 学习{{ subject }}</h3>
    <h3 style="color: red">下方列表的总人数 {{ personList.length }}</h3>
    <select v-model.number="n">
      <!--让所有的value全部绑定为数字-->
      <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="incrementIfOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions} from 'vuex';
export default {
  //计数组件
  name: "Count",
  data(){
    return {
      n: 1,// 代表用户在select框开始的时候选择的数字
    }
  },
  computed:{
    //借助mapState从state中生成计算属性,对象写法
    // ... mapState({
    //   sum:'sum',
    //   school: 'school',
    //   subject: 'subject'
    // }),
    //借助mapState从state中生成计算属性,数组写法(即代表了生成的计算属性名为sum,同时也代表了从state找到sum)
    ... mapState(['sum', 'school', 'subject', 'personList']),

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

  },
  methods:{
    // increment(){
    //   this.$store.commit('INCREMENT', this.n);
    // },
    // decrement(){
    //   this.$store.commit('DECREMENT', this.n);
    // },
    //借助mapMutations生成对应方法,方法会调用commit去联系mutations,对象写法
    ...mapMutations({
      increment: 'INCREMENT',
      decrement: 'DECREMENT',
    }),
    //借助数组写法生成方法,但注意你生成的方法名和mutations里对应的方法名将会一样的
    // ...mapMutations(['increment', 'decrement']),

    // incrementOdd(){
    //   this.$store.dispatch('incrementIfOdd', this.n);
    // },
    // incrementWait(){
    //   this.$store.dispatch('incrementWait', this.n);
    // }

    //借助mapMutations生成对应方法,方法会调用dispatch去联系actions,对象写法
    // ...mapActions({
    //   incrementIfOdd: 'incrementIfOdd',
    //   incrementWait: 'incrementWait',
    // }),

    ...mapActions(['incrementWait', 'incrementIfOdd']), //数组写法,同上
  },
}
</script>

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

如果写成...mapMutations({'add':'ADD_PERSON'}),那么在模板里button的click事件要传参 @click="add({id:id,name:name})"

index.js

javascript 复制代码
/**
 * 该文件用于创建vuex中最核心的store
 */

//引入Vuex
import Vuex from 'vuex';
import Vue from "vue";

//使用vuex来集中管理状态,必要
//new store的前提是必须要使用Vuex插件
Vue.use(Vuex);

//创建actions(本质就是对象) 用于响应组件中的动作
const actions = {
    //收到上下文对象(包含commit)和dispatch过来的值
    // increment(context, value){
    //     context.commit('INCREMENT', value);
    // },
    // decrement(context, value){
    //     context.commit('DECREMENT', value);
    // },
    incrementIfOdd(context, value){
        // console.log(`action中的incrementIfOdd被调用`);
        // console.log('处理了一些事情');
        // context.dispatch('demo1', value);
        if(context.state.sum % 2) {
            console.log('@')
            context.commit('INCREMENT',value);
            // context.state.sum += 1;//这样可以实现但是记住本次对状态的改变开发者工具将无法捕获,因为开发者工具是对mutations对话的
        }
    },
    incrementWait(context, value){
        setTimeout(() => {
            context.commit('INCREMENT', value);
        },500)
    },
    // demo1(context, value){
    //     console.log('处理了一些事情---demo1');
    //     context.dispatch('demo2', value);
    // },
    // demo2(context, value){
    //     console.log('在action的demo中完成最终的逻辑');
    //     if(context.state.sum % 2) {
    //         console.log('@')
    //         context.commit('INCREMENT',value);
    //     }
    // }
}

//创建mutations(本质也是对象) 用于修改数据(state)
const mutations = {
    //收到state和要操作数value
    INCREMENT(state, value) {
        state.sum += value;
    },
    DECREMENT(state, value) {
        state.sum -= value;
    },
    ADD_PERSON(state, value){
        state.personList.unshift(value);
    }
}

//准备getters用于加工state,将其共享于各个组件当中
const getters = {
    bigSum(state){
        return state.sum * 10;
    }
}

//准备state(数据) 存储数据
//类似于各个组件里的computed(计算属性),只不过它是共享的
const state = {
    sum: 0,
    school: 'Wust',
    subject: 'Computer Science',
    personList: [
        { id: '001', name: '张三'}
    ],
}


//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
});
相关推荐
小曲曲12 分钟前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
学不会•1 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS2 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜4 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点4 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow4 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o4 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
刚刚好ā5 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
yqcoder6 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
会发光的猪。7 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js