目录
一、vue-resource 库
了解即可 在之前的 vue 版本中经常使用 这个库发送 ajax 请求 现在建议使用 axios
我们可以通过使用 vue-resource 库 来实现发送 ajax 请求
它是 vue 的一个插件库
Vue.use() 就能使用我们的插件了
我们引入后去 我们的实例对象 vc 中查看 发现出现了 一个 $http 就是我们引入的东西
然后具体的 使用方法和 axios 一致 把axios 换成 this.$http 即可 用法和 axios 一致
methods: {
searchUsers() {
console.log(this)
this.$bus.$emit("updataListData", {
isFirst: false,
isLoading: true,
errMsg: "",
users: [],
});
this.$http.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
(response) => {
console.log("请求成功了", response.data.items);
this.$bus.$emit("getUsers", response.data.items);
this.$bus.$emit("updataListData", {
isLoading: false,
errMsg: "",
users: response.data.items,
});
},
(error) => {
console.log("请求失败了", error.message);
this.$bus.$emit("updataListData", {
isLoading: false,
errMsg: error.message,
users: [],
});
}
);
二、插槽
让父组件可以项子组件指定位置插入 html 结构,也是一种通讯方式,适用于 ===> 子组件
有三类
(一)默认插槽
我们的组件标签 里面可以放图片 但是 vue 解析时不知道 该把这个图片 放在 组件模板中的什么位置,所以我们需要一个插槽来指定位置
Vue 中的模板结构如下
可以把标签写成两边包裹的形式 把要插入的东西放在里面
<template>
<div class="container">
<Category title="美食" :listData="foods">
<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="" />
</Category>
<Category title="游戏" :listData="games" />
<Category title="电影" :listData="flims" />
</div>
</template>
然后在组件的模板中 用插槽 slot 来指定插入 的位置 图片就出现了
slot 里面也可以写内容 如果没有人传入东西到 插槽中 就显示我们在 插槽中写的内容 如果有东西传入 就显示我们传入的东西
<template>
<div class="category">
<h3>{{title}}分类</h3>
<slot></slot>
</div>
</template>
(二)具名插槽
如果有多个插槽的话我们要使用具名插槽
组件中模板
多个 slot 我们直接分别给它们一个 name 属性,分别叫center 和 footer
<template>
<div class="category">
<h3>{{title}}分类</h3>
<slot name="center"></slot>
<slot name="footer"></slot>
</div>
</template>
在 app 中的代码 分别指定对应的内容显示到对应的 插槽中去
<Category title="美食">
<img
slot="center"
src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg"
alt=""
/>
<a slot="footer" href="">更多美食</a>
</Category>
如果是 tempalte 形式的外层标签 可以使用 slot 绑定 也能使用 特殊的绑定方式 就是 v-slot:后面的slot 名不用加 引号包围
<Category title="游戏">
<template slot="footer">
<ul>
<li v-for="(item, index) in games" :key="index">{{ item }}</li>
</ul>
<a href="">1223</a>
<a href="">122</a>
<a href="">12</a>
</template>
</Category>
(三)作用域插槽
数据在组件的自身 根据数据生成的结构需要组件的使用者来决定
如果数据在儿子里面 父亲想拿到儿子里面的数据并进行 插槽操作时 我们可以自己绑定一个变量
games 并将数组games 的数据传入 使用该组件的人
作用域插槽也能有 name 属性和具名插槽搭配使用
<template>
<div class="category">
<h3>{{ title }}分类</h3>
<slot :games="games">我是默认内容</slot>
</div>
</template>
然后在app 组件中必须使用 template 标签然后使用 属性 scope 接收 后面的名随便定义
这样接收到了 games 数据 但是是对象的形式 我们需要用 duixiang.games 的方式来遍历数组
<template>
<div class="container">
<Category title="游戏">
<template scope="duixiang">
<ul>
<li v-for="(item, index) in duixiang.games" :key="index">{{ item }}</li>
</ul>
</template>
</Category>
</div>
</template>
三、vuex
(一)介绍
专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对Vue 应用中多个组件的共享的状态进行集中式的管理也是一种 组件间通信方式,且适用于任意组件通信
集中式就是把所有人都集中起来 然后讲一遍课
分布式就是 去所有人家每个人都讲一遍课
(二)多组件共享数据
1.通过全局事件总线实现
对 a 中的数据进行读和写,但是使用全局总线时 如果有很多组件的话 需要在所有组件中 使用 $bus$on $bus$emit 很麻烦
2.通过使用 vuex 实现
vuex 不属于任何一个组件 数据直接放在 vuex 中
可以使用 vuex中的api 实现对 vuex 中的数据的读写
(三)使用场景
共享
1.多个组件依赖同一个状态 就是同一个数据
2.来自不同组件的行为 需要变更同一状态
比如点击数字增加1 滑动数字扩大二十倍 都是对同一个数字生效 就是这个意思
(四)vuex 工作原理
Vuex 里面有三个组成部分
第一个是 Actions 是行为
第二个 Mutations 是加工维护的意思
第三个 State 状态就是数据 是对象的形式 里面能放很多数据
Vue Components 就是我们写的 vue 组件 Count
dispatch’是一个函数 调用得用两个参数 第一个参数是动作类型 第二个参数是具体的数字dispatch('jia',2) 就是执行加操作 然后加 2 这个函数会引起 actions 里面的函数调用
Actions 响应 是一个对象里面有动作们 { jia:function }
我们在 加的这个函数中自己调用 commit 函数 commit('jia',2) 然后就进行了提交,然后又调用了multations 里面的加函数
然后就到了 Multations 也是一个对象里面也有 加 函数 {jia:function} 这个函数里面有两个数据 第一个是 state 另一个是 2 然后里面写 state.sum += 2
State中的状态(数据)就更新了
最后 Render 渲染一下即可
注意: 如果有逻辑的话就是得判断条件 什么条件下才能加 2 的话 ,就不能省略 actions 的过程
如果没有逻辑 直接加 2 就能省略
三个组成部分数据类型都是对象 这三个部分都得经过一个人的领导 就是 store 仓库的意思
(五)vuex 的使用
1.初始化代码 vuex 配置
先安装 npm i vuex@3 不然默认是4版本那是 vue3 使用的
然后引入插件 先 import 再 use
这样是为了 让我们创建 vm 时能配置 store 配置项
不引入就不能配置 store 配置项
引入完 查看 vm,vc 中发现里面有了 $store 属性
import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
import Vuex from 'vuex'
Vue.config.productionTip = false
Vue.use(vueResource)
Vue.use(Vuex)
new Vue({
el: '#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this
}
})
现在是假的 store 所以我们有两种方法能配置这个store
第一种是 我们在 src 文件夹中创建一个 vuex 文件夹 里面放上 store.js 文件
第二种是 我们在 src 文件夹中创建一个 store 文件夹 里面放上 index.js
推荐使用第二种比较官方
我们在 index.js 文件中进行配置
const actions = {}
用于响应组件中的动作
const mutations ={}
用于操作数据
const state = {}
用于存储数据
最后引入 Vuex 创建并暴露 store 里面得写上三个配置项 actions mutations state 然后用我们上面创建的东西赋值
配置项成功管理起来了
import Vuex from 'vuex'
const actions = {}
const mutations ={}
const state = {}
export default new Vuex.Store({
actions,
mutations,
state
})
然后去 main.js 中引入 然后配置 store 项 就是自己本身
import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
import Vuex from 'vuex'
import store from './store/index'
Vue.config.productionTip = false
Vue.use(vueResource)
Vue.use(Vuex)
new Vue({
el: '#app',
render: h => h(App),
store,
beforeCreate() {
Vue.prototype.$bus = this
}
})
看上去没啥问题了但是运行会出错 因为我们必须先use (Vuex)再引入 store 才符合规范 所以我们把 use(Vuex)放到 index.js 里面先use 再引入
修正后的代码
index .js 代码
import Vuex from 'vuex'
import Vue from 'vue'
const actions = {}
const mutations = {}
const state = {}
Vue.use(Vuex)
export default new Vuex.Store({
actions,
mutations,
state
})
main.js 代码
import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
import store from './store/index'
Vue.config.productionTip = false
Vue.use(vueResource)
new Vue({
el: '#app',
render: h => h(App),
store,
beforeCreate() {
Vue.prototype.$bus = this
}
})
2.对vuex 中的数据进行读写
首先把数据 sum:0 写入 state 中存储
然后写 加法的函数 里面先使用 this.$store.dispath('jia',this.n) 使用加函数然后 加数字 this.n
increment() {
this.$store.dispatch('jia',this.n)
},
然后得调用 vuex里面的 actions 里面的 jia 函数 会有接收到两个参数 第一个是 迷你版的 store 第二个参数就是我们加的数字 这个store 里面有 commit 函数,我们需要在这个 jia函数中再调用 commit 函数 在store 中 最好函数用大写区别一下
const actions = {
jia(context,value){
context.commit('JIA',value)
}
}
然后下一步 在 mutations 里面调用 JIA 函数 该函数也能收到两个参数 第一个是 state 里面有我们的数据 sum 第二个就是我们的要加的数 value
const mutations = {
JIA(state, value) {
state.sum += value
}
}
最后回来改一下模板即可,最后数据就在 $store.state.sum
<h1>当前求和为{{$store.state.sum}}</h1>
3.成型代码
Count.vue 如果 省略了 actions 中的函数 就不用调用 dispatch 函数了 直接使用 commit 函数调用 mutations 中的大写的函数即可
<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="decrement">-</button>
<button @click="incrementOdd">当前为计奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "Count",
data() {
return {
n: 1,
};
},
methods: {
increment() {
this.$store.commit("JIA", this.n);
},
decrement() {
this.$store.commit("JIAN", this.n);
},
incrementOdd() {
this.$store.dispatch("jiaOdd", this.n);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.n);
},
},
mounted() {
console.log("Count", this);
},
};
</script>
<style>
button {
margin-left: 5px;
}
</style>
index.js 如果在action中没有业务逻辑的判断 就可以在 actions 中省略 但是有业务逻辑不能省略
import Vuex from 'vuex'
import Vue from 'vue'
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)
},
}
const mutations = {
JIA(state, value) {
state.sum += value
},
JIAN(state, value) {
state.sum -= value
},
}
const state = {
sum: 0,
}
Vue.use(Vuex)
export default new Vuex.Store({
actions,
mutations,
state
})
四、Vuex 开发者工具的使用
就是我们一直使用的 vue 开发者工具 vuex 和 vue 工具是合并的
选项卡复习
第一个是看组件的 有什么组件
第三个是看自定义事件的
我们使用的是第二个选项卡 切换 vuex 视图
有两块区域 第一块是选择区 第二块是展示区
选择区中选择 显示区中显示我们所选择的东西
每次执行都会显示一次我们执行的过程
显示的是我们的 mutation 中的函数
页面当前呈现的数据就是 现在最下面的绿色
一个小表的符号是时间穿梭 点击就回到之前的状态了
禁止是消除所选中的过程和依赖它的过程
下载按钮是将我们的选中之前的数据合并并且不呈现 全给到基本数据里面了
右上角
红按钮 关闭就不捕获了 我们在页面中进行任何操作都不会被捕获了 一般不关
禁止号是清除所有的现实的数据
注意:要严格根据我们写的流程规范进行代码编写
五、store 中的 getter 配置项
store 中只有上面图中的 三个配置项
但是其实还有这个 getters 配置项 但是不是必须要有的东西
配置好了 这个 getters 配置项就能 对state 中的数据进行操作了
现在所有组件都能使用我们写的这个功能了
const getters = {
bigSum(state) {
return state.sum * 10
}
}
Vue.use(Vuex)
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
(一)普通写法
然后我们在组件中调用时 直接用 $store.getters.bigSum 就能输出总和了
<h1>当前求和放大十倍为{{$store.getters.bigSum}}</h1>
我们可以设计一个函数来把大括号里面的东西简略一下
methods: {
increment() {
this.$store.commit("JIA", this.n);
},
decrement() {
this.$store.commit("JIAN", this.n);
},
incrementOdd() {
this.$store.dispatch("jiaOdd", this.n);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.n);
},
},
现在里面直接写我们给的名就行了
<h1>当前求和为{{ sum }}</h1>
<h1>当前求和放大十倍为{{ bigSum }}</h1>
<h3>我在{{ school }}学习{{ subject }}</h3>
(二)对象写法
如果我们想简化计算函数内的东西,就得引入另外一个库来帮助我们生成计算函数内的结构
先引入 这个库
import { mapState } from "vuex";
如果我们使用 下面的句子,就能代替我们上面为了缩短 括号代码在计算属性中写的 state 中的属性简短拿出来的方法,但是如果是 getters 中的数据 还不能统一生成简写形式,得自己写简写形式
...mapState({ sum: "sum", school: "school", subject: "subject" }),
computed: {
bigSum() {
return this.$store.getters.bigSum;
},
...mapState({ sum: "sum", school: "school", subject: "subject" }),
},
(三)数组写法 mapState
如果 名字和函数名同名的话就 写成数组的形式 不能用对象简写的形式 对象的那个是 sum:sum
但是这个是 sum:‘sum’ 写成数组的形式就能解决这个问题
必须名字和 state 中的一致 因为 这样写是一个名两个用途的意思,一个是我们起的函数名 另一个是去 state 中找这个属性名
...mapState(["sum","school","subject"]),
注意:
有mapState 就有 mapGetter 一样的用法 也能简化
(四)mapMutation
原本的方法的写法是
methods: {
increment() {
this.$store.commit("JIA", this.n);
},
decrement() {
this.$store.commit("JIAN", this.n);
},
incrementOdd() {
this.$store.dispatch("jiaOdd", this.n);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.n);
},
},
我们能用 mapMutation 也能简写 借助mapMutation 生成结构类似的方法 方法中调用 commit 来练习 mutations
...mapMutations({increment:'JIA',decrement:'JIAN'}),
使用传参来接收数据 要不默认接受的数据是 对象 target 对象加一个数字 得出的结果不正常
这是对象方式的写法 数组的写法和前面的类似,
还有一个...mapActions({}) 和上面的 mapMutation 同理
...mapActions(['incrementOdd','incrementWait'])
六、多组件共享数据案例
1.Count.vue
<template>
<div>
<h1>当前求和为{{ sum }}</h1>
<h1>当前求和放大十倍为{{ bigSum }}</h1>
<h3>我在{{ school }}学习{{ subject }}</h3>
<h3>下方组件的总人数是:{{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="JIA(n)">+</button>
<button @click="JIAN(n)">-</button>
<button @click="jiaOdd(n)">当前为计奇数再加</button>
<button @click="jiaWait(n)">等一等再加</button>
</div>
</template>
<script>
import { mapState, mapMutations, mapGetters, mapActions } from "vuex";
export default {
name: "Count",
data() {
return {
n: 1,
};
},
methods: {
...mapMutations(["JIA", "JIAN"]),
...mapActions(["jiaOdd", "jiaWait"]),
},
mounted() {
console.log("Count", this);
},
computed: {
...mapState(["sum", "school", "subject",'personList']),
...mapGetters(["bigSum"]),
},
};
</script>
<style>
button {
margin-left: 5px;
}
</style>
2.Person.vue
<template>
<div>
<h1>人员列表</h1>
<h3>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";
// import {mapState} from 'vuex'
export default {
name: "Person",
data() {
return {
name: '',
};
},
computed: {
personList() {
return this.$store.state.personList;
},
sum() {
return this.$store.state.sum;
},
// ...mapState(['personList'])
},
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit("ADD_PERSON", personObj);
console.log(personObj);
this.name = "";
},
},
};
</script>
3.index.js
import Vuex from 'vuex'
import Vue from 'vue'
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)
},
}
const mutations = {
JIA(state, value) {
state.sum += value
},
JIAN(state, value) {
state.sum -= value
},
ADD_PERSON(state, value) {
console.log('mtuations 中的JIAN被调用了')
state.personList.unshift(value)
}
}
const state = {
sum: 0,
school: '学校',
subject: '前端',
personList: [
{ id: '001', name: '张三' }
]
}
const getters = {
bigSum(state) {
return state.sum * 10
}
}
Vue.use(Vuex)
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
4.app.vue
<template>
<div>
<Count/>
<hr>
<Person/>
</div>
</template>
<script>
import Count from "./components/Count";
import Person from "./components/Person"
export default {
name: "app",
components: { Count ,Person},
};
</script>
5.main.js
import Vue from 'vue'
import App from './App.vue'
import vueResource from 'vue-resource'
import store from './store/index'
Vue.config.productionTip = false
Vue.use(vueResource)
new Vue({
el: '#app',
render: h => h(App),
store,
beforeCreate() {
Vue.prototype.$bus = this
}
})
七、Vuex 模块化编码 命名空间
(一)目的
让代码更好维护,让多种数据分类更加明确
(二)使用步骤
1.修改 store.js 文件
2.开启命名空间组件中读取 state 数据
方式一 自己读取
this.$store.state.personAbout.list
方式二 借助 mapstate 读取
...mapState('countAbout',['sum','school','subject'])
3.开启命名空间组件中读取 getters 数据
方式一 自己读取
this.$store.getters.personAbout.list
方式二 借助 mapGetters 读取
...mapGetters('countAbout',['sum','school','subject'])
4.开启命名空间组件中调用 dispatch 函数
方式一 自己调用 dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
方式二 借助 mapActions 读取
...mapActions('countAbout',{incrementOdd:"jiaOdd",incrementWait:"jiaWait"})
5.开启命名空间组件中调用 commit 函数
方式一 自己调用 commit
this.$store.dispatch('personAbout/addPersonWang',person)
方式二 借助 mapMutations 读取
...mapMutations('countAbout',{increment:"JIA",decrement:"JIAN"})
我们要引用的时候 就 ...mapState('countAbout',["sum", "school","subject"]), 就能简化引用的方式,很方便 使用 countAbout 对象中的方法 但是我们得在 对象中加一个属性
就是 nameplace属性 这样分类名才能被认识 为 true 时才能正确被识别
(三)案例代码
1.Count.vue
<template>
<div>
<h1>当前求和为{{ sum }}</h1>
<h1>当前求和放大十倍为{{ bigSum }}</h1>
<h3>我在{{ school }}学习{{ subject }}</h3>
<h3>下方组件的总人数是:{{ 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="JIA(n)">+</button>
<button @click="JIAN(n)">-</button>
<button @click="jiaOdd(n)">当前为计奇数再加</button>
<button @click="jiaWait(n)">等一等再加</button>
</div>
</template>
<script>
import { mapState, mapMutations, mapGetters, mapActions } from "vuex";
export default {
name: "Count",
data() {
return {
n: 1,
};
},
methods: {
...mapMutations('countAbout',["JIA", "JIAN"]),
...mapActions(['countAbout',"jiaOdd", "jiaWait"]),
},
mounted() {
console.log("Count", this);
},
computed: {
...mapState("countAbout", ["sum", "school", "subject"]),
...mapState("personAbout", ["personList"]),
...mapGetters('countAbout',["bigSum"]),
},
};
</script>
<style>
button {
margin-left: 5px;
}
</style>
2.Person.vue
<template>
<div>
<h1>人员列表</h1>
<h3>count 求和为:{{ sum }}</h3>
<h3>列表中第一个名字是:{{ firstPersonName }}</h3>
<input type="text" placeholder="请输入名字" v-model="name" />
<button @click="add">添加</button>
<button @click="addWang">添加王姓的人</button>
<ul>
<li v-for="p in personList" :key="p.id">{{ p.name }}</li>
</ul>
</div>
</template>
<script>
import { nanoid } from "nanoid";
// import {mapState} from 'vuex'
export default {
name: "Person",
data() {
return {
name: "",
};
},
computed: {
personList() {
return this.$store.state.personAbout.personList;
},
sum() {
return this.$store.state.countAbout.sum;
},
firstPersonName() {
return this.$store.getters["personAbout/firstPersonName"];
},
},
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit("personAbout/ADD_PERSON", personObj);
this.name = "";
},
addWang() {
const personObj = { id: nanoid(), name: this.name };
this.$store.dispatch("personAbout/addPersonWang", personObj);
this.name = "";
},
},
};
</script>
3.index.js
import Vuex from 'vuex'
import Vue from 'vue'
import axios from 'axios'
const countOptions = {
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
}
},
}
const personOptions = {
namespaced: true,
actions: {
addPersonWang(context, value) {
if (value.name.indexOf('王') === 0) {
context.commit('ADD_PERSON', value)
}
},
addPersonServer(context, value) {
axios.get('')
}
},
mutations: {
ADD_PERSON(state, value) {
console.log('mtuations 中的JIAN被调用了')
state.personList.unshift(value)
}
},
state: {
personList: [
{ id: '001', name: '张三' }
]
},
getters: {
firstPersonName(state) {
return state.personList[0].name
}
},
}
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
countAbout: countOptions,
personAbout: personOptions
}
})
4.App.js
<template>
<div>
<Count />
<hr />
<Person />
</div>
</template>
<script>
import Count from "./components/Count";
import Person from "./components/Person";
export default {
name: "app",
components: { Count, Person },
};
</script>