vue part 10
vue-resource
在vue1.0时代讲的比较多,是vue.插件库,
import vueResource from 'vue-resource'
Vue.use(vueResource)
在vc和vm中会多出如下F12代码即,$http:()
他的用法和返回值和axios一模一样,但是不常维护了
插槽
默认插槽
App.vue的Category标签不起作用,因为在Category.vue的????究竟放在哪vue不知道;因此通过slot来表明位置
App.vue
<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
<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
//引入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
<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如下
<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
<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
<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版本。
npm i vuex@3
main.js
//引入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
//引入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
/**
* 该文件用于创建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
<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
<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官方有一个这种批量生成的库:
import {mapState} from 'vuex'
4个map的方法mapState mapGetters 与mapActions mapMutaions
前两个主要用于computed做简写,那后两个是methods的简写
113_尚硅谷Vue技术_mapActions与mapMutations_哔哩哔哩_bilibili最体现对vue理解的一集
多组件共享数据
placeholder 属性提供可描述输入字段预期值的提示信息(hint)。 该提示会在输入字段为空时显示,并会在字段获得焦点时消失。
只要在mapState中声明一下personList即可
Person.vue
<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修改如下
<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
/**
* 该文件用于创建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
});