记录vue的一些基本使用。
脚手架文件
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件
1,数据绑定
<!-- 普通写法 -->
<!-- 单向数据绑定:<input type="text" v-bind:value="name"><br/>
<!--双向数据绑定:<input type="text" v-model:value="name"><br/> -->
<!-- 简写 -->
单向数据绑定:<input type="text" :value="name"><br/>
双向数据绑定:<input type="text" v-model="name"><br/>
data() {
return {
name:'张三同学'
};
},
2,MVVM模型
1 M:模型(Model) :data中的数据
2. V:视图(View) :模板代码
3. VM:视图模型(ViewModel):Vue实例
观察发现:
1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
3,vue中的事件
事件的基本使用:
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或组件
事件修饰符
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
键盘事件
enter,delete ,esc,space,tab,up,down,left,right
4,计算属性
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
//vue.js中的代码段
data() {
return {
firstName:'张',
lastName:'三',
};
},
computed:{
fullName(){
console.log('haha')
return this.firstName + '-' + this.lastName
}
}
5,监视属性
姓:<input type="text" v-model="firstName"> <br/><br/>
名:<input type="text" v-model="lastName"> <br/><br/>
全名:<span>{{fullName}}</span> <br/><br/>
//代码段
data() {
return {
firstName:'张',
lastName:'三',
fullName:'张+三'
};
},
watch:{
firstName(val){
setTimeout(()=>{
console.log(this)
this.fullName = val + '-' + this.lastName
},1000);
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
5,样式绑定
<!-- 样式绑定 -->
<div :class="style1">字符串写法,绑定class样式1{{name1}}</div>
<div :class="arrayStyle">数组写法{{name2}}</div>
<div :class="OjbectClass">对象写法,可以动态地决定样式的显示和隐藏{{name3}}</div>
<div :style="styleObj">style对象写法{{name4}}</div>
<div :style="styleArray">style数组写法{{name5}}</div>
//js部分
data() {
return {
name1:'张三',
name2:'李四',
name3:'王五',
name4:'赵六',
name5:'田七',
// 字符串写法
style1:'class1',
// 数组写法
arrayStyle:['array1','array2','array3'],
// 对象写法
OjbectClass:{
obj1:true,
obj2:false
},
// 对象objStyle写法 骆峰式写法
styleObj:{
fontSize:'16px',
color:'blue',
border:'1px solid pink'
},
//对象数据写法
styleArray:[
{
fontSize:'16px',
color:'red',
},
{
border:'1px solid red'
}
]
};
},
//style部分
<style>
/* 字符串写法 */
.class1{
font-size: 16px;
font-family: 'Courier New', Courier, monospace;
color: red;
}
/* 数组写法 */
.array1{
font-size: 12px;
color: palegreen;
}
.array2{
font-family: 'Courier New', Courier, monospace;
}
.array3{
width: 200px;
height: 30px;
line-height: 30px;
border: 1px solid red;
}
/* 对象写法 */
.obj1{
width: 200px;
height: 30px;
border: 1px solid blue;
}
.obj2{
font-size: 16px;
color: black;
}
</style>
6,列表渲染,条件渲染,表单,过滤器
v-if,v-show,v-for,v-model,filter
7,常用指令
v-text,v-html,v-cloak,v-once,v-pre
8,自定义指令(全局和局部)
9,生命周期(看官方文档)
10,ref属性
1. 被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
1. 打标识:```<h1 ref="xxx">.....</h1>``` 或 ```<School ref="xxx"></School>```
2. 获取:```this.$refs.xxx```
11,props配置项
1. 功能:让组件接收外部传过来的数据(常用于父组件向子组件传值)
2. 传递数据:```<Demo name="xxx"/>```
3. 接收数据:
1. 第一种方式(只接收):```props:['name'] ```
2. 第二种方式(限制类型):```props:{name:String}```
3. 第三种方式(限制类型、限制必要性、指定默认值):
```js
props:{
name:{
type:String, //类型
required:true, //必要性
default:'老王' //默认值
}
}
使用方式一:父组件向子组件传值
父组件
<template>
<div>
<datalistaa :options="data1"/>
<datalistaa :options="data2"/>
</div>
</template>
<script>
import datalistaa from './datalistaa.vue'
export default{
name:'mains',
components: {
datalistaa
},
data(){
return{
data1:[
{id:'001',label:'张三'},
{id:'002',label:'李四'},
{id:'003',label:'王五'},
],
data2:[
{id:'001',label:'张三1'},
{id:'002',label:'李四2'},
{id:'003',label:'王五3'},
]
}
}
}
</script>
子组件
<template>
<div class="dropdown">
<button @click="showList = !showList">{{ buttonText }}</button>
<ul v-if="showList">
<li v-for="option in options" :key="option.value" @click="selectOption(option)">{{ option.label }}</li>
</ul>
</div>
</template>
<script>
export default {
props: {
options: {
type: Array,
required: true
},
options1: {
type: Array,
required: true
},
buttonText: {
type: String,
default: 'down menu'
}
},
data() {
return {
showList: false
}
},
methods: {
selectOption(option) {
this.$emit('select', option.value);
this.showList = false;
}
}
}
</script>
使用方式二:兄弟组件之间传值
父组件
<!--父组件里面分另有两个对应的child1和child2两个子组件-->
<template>
<div>
<div style="border:1px solid red;width:800px;height:200px">
<span>这是父组件</span>
<br/>
</div>
<child1 ref="child1" :childOne="childOne" @newClick="btnC"></child1>
<a-divider />
<child2 :childTwo="childTwo"></child2>
</div>
</template>
<script>
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
name:"WorkPlace",
components:{child1,child2},
data () {
return {
//所对应的值
childOne:"",
childTwo:""
}
},
methods:{
btnC(val){
this.childOne=val//兄弟组件1
this.childTwo=val//兄弟组件2
}
}
}
</script>
子组件child1
<template>
<div>
<h1>兄弟组件一</h1>
<h2>{{childOne}}</h2>
<a-button @click="btn">兄弟组件之间通信</a-button>
</div>
</template>
<script>
export default {
name:"child2",
props:{
childOne:{
type:String
}
},
methods:{
btn(){
//将这里的100传到兄弟组件2中,这里使用的是自定义事件
let ages="100"
this.$emit('newClick',ages)
}
}
}
</script>
子组件child2
<template>
<div>
<h1>兄弟组件二{{childTwo}}</h1>
</div>
</template>
<script>
export default {
name:"child2",
props:{
childTwo:{
type:String
}
}
}
</script>
当点击组件child1中的事件之间,组件1和组件2中的数据同步更新为100
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
12,mixin(混入)
1. 功能:可以把多个组件共用的配置提取成一个混入对象
2. 使用方式:
第一步定义混合:
```
{
data(){....},
methods:{....}
....
}
```
第二步使用混入:
全局混入:```Vue.mixin(xxx)```
局部混入:```mixins:['xxx'] ```
就是把所有公用的部分单独抽取出来,如data、components、created、methods 、computed、watch等。假如有这样的一个需求,两个组件里面分别有姓名和年纪信息,并且点击姓名弹出姓名,正常情况下需要写两个事件分别弹出姓名。但是我们如果使用混入就要简单的多了。
第一步先在src下新建一个mixin.js文件,在这个文件下面写入代码
export const mixi={
methods:{
btn(){
alert(this.name)
}
}
}
接着在两个需要用到的组件中分别引入并使用
组件1代码
<template>
<div>
<div>姓名是{{name}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
import {mixi} from '../mixin'
export default{
name:'',
data(){
return{
name:'李四'
}
},
mixins: [mixi]
}
</script>
组件2代码
<template>
<div>
<div>姓名是{{name}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
import {mixi} from '../mixin'
export default{
name:'',
data(){
return{
name:'张三'
}
},
mixins: [mixi]
}
</script>
13,插件
包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据
假如有两个组件里面有各自需要实现的功能,一个功能能对字符串进行截取,另一个是点击按钮弹出各自的提示,正常情况下是需要写两个事件和两个字符分割的操作,如果使用插件就简单得多。
1,使用的第一步在src目录下新建一个plugins.js文件,接着在js文件下添加对应的代码
export default{
install(Vue){
//这里对字符串进行截取
Vue.filter('strSlice',function(value){
return value.slice(0,4)
});
//添加一个原型方法
Vue.prototype.fun=()=>{
alert("vue.js")
}
//...还可以添加其它的
}
}
2,全局引用
import Vue from 'vue'
import App from './App'
import router from './router'
//引入store
import store from './store/index'
import plugins from './plugins'//引入插件
Vue.use(plugins)//使用插件
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store:store,
components: { App },
template: '<App/>'
})
3,在对应的组件中使用
组件1
<template>
<div>
<!-- 点击按钮弹出vue.js 字符串被截取 -->
<div>{{name|strSlice}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
export default{
name:'',
data(){
return{
name:'长风破浪会有时'
}
},
methods: {
btn(){
this.fun()
}
}
}
</script>
组件2
<template>
<div>
<!--点击按钮弹出vue.js 字符串被截取-->
<div>{{name|strSlice}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
export default{
name:'',
data(){
return{
name:'直挂云帆济沧海'
}
},
methods: {
btn(){
this.fun()
}
}
}
</script>
14组件自定义事件
1,创建一个自定义事件(可用于子组件向父组件传值)
首先在父组件在添加自定义事件,这里的父组件是App.vue
<plusins1 v-on:customBtn="btn1"/>
//这里的btn1需要和methods中的btn1保持一至
methods: {
btn1(){
alert("自定义事件")
}
}
调用自定义事件,这里是子组件
<template>
<div>
<div>{{name}}</div>
//这里点击按钮会看到对应的提示
<button @click="btn">按钮1</button>
</div>
</template>
<script>
export default{
name:'',
data(){
return{
name:'长风破浪会有时'
}
},
methods: {
btn(){
//触发自定义事件使用$emit 另外这里的customBtn需要和父组件里面的一样
this.$emit('customBtn')
}
}
}
</script>
2,自定义事件传参
首先在组件顶部添加一个div,div里面有names,names在data中,并且值为空
<div>{{names}}</div>
<plusins1 v-on:customBtn="btn1"/>
data() {
return {
names:''
};
},
mounted () {
console.log(this)
},
methods: {
//这里给btn1添加了一个参数
btn1(val){
this.names=val
}
}
在子组件中的处理
<template>
<div>
<div>{{name}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
export default{
name:'',
data(){
return{
name:'长风破浪会有时'
}
},
methods: {
btn(){
//触发自定义事件使用$emit 另外这里的customBtn需要和父组件里面的一样
//当点击之后父组件中的names值会等于这个里面的name
this.$emit('customBtn',this.name)
}
}
}
</script>
注意点
1. 一种组件间通信的方式,适用于:子组件 ===> 父组件
2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件事件的回调在A中
3. 绑定自定义事件:
1. 第一种方式,在父组件中:```<Demo @customBtn="test"/>``` 或 ```<Demo v-on:customBtn="test"/>```
2. 第二种方式通过ref,在父组件中:
```js
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('customBtn',this.test)
}
```
3. 若想让自定义事件只能触发一次,可以使用```once```修饰符,或```$once```方法。
4. 触发自定义事件:```this.$emit('atguigu',数据)```
5. 解绑自定义事件this.$off('customBtn') //解绑一个自定义事件
// this.$off(['customBtn','customBtn1']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
6. 组件上也可以绑定原生DOM事件,需要使用```native```修饰符。
7. 注意:通过```this.$refs.xxx.$on(' ',回调)```绑定自定义事件时,回调<span style="color:red">要么配置在methods中</span>,<span style="color:red">要么用箭头函数</span>,否则this指向会出问题!
15.全局事件总线
首先在main.js中添加全局事件事件总线
new Vue({
el: '#app',
router,
store:store,
components: { App },
template: '<App/>',
//添加全局事件总线
beforeCreate(){
Vue.prototype.$bus=this
}
})
接下来创建两个组件,现在需要做的是需要把组件A中的数据传递到组件B中
A组件
<template>
<div>
<div>{{name}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
export default{
name:'',
data(){
return{
name:'天生我材必有用'
}
},
methods: {
btn(){
//定义使用$bus.$emit
this.$bus.$emit('clickline',this.name)
}
},
beforeDestroy () {
//对全局事件总线进行解绑
this.$bus.$off('clickline')
}
}
</script>
B组件
总结
1,一种组件间通信的方式,适用于任意组件间通信。
2,A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
16,消息订阅与发布
1,安装npm i pubsub-js(消息订阅与发布的组件不止这一种,也有其它的插件,区别就是语法上面)
2 ,引入 import pubsub from 'pubsub-js'(在需要用到的组件中使用)
现在有两个组件,想将组件A中的数据传到组件B
组件A
<template>
<div>
<div>{{name}}</div>
<button @click="btn">按钮1</button>
</div>
</template>
<script>
//引入pubsub.js
import pubsub from 'pubsub-js'
export default{
name:'',
data(){
return{
name:'人生得意须尽欢'
}
},
methods: {
btn(){
//这里使用pubsub.publish
pubsub.publish('subClick',this.name)
}
}
}
</script>
组件B 一共有3种写法
<template>
<div>
<div>{{name}}</div>
</div>
</template>
<script>
//引入pubsub.js
import pubsub from 'pubsub-js'
export default{
name:'inst1',
data(){
return{
name:''
}
},
mounted () {
//这里的两个参数,第一个是事件名,第二个才是对应值
//第一种写法
var that = this
// pubsub.subscribe('subClick',function(msg,data){
// console.log(data)
// that.name=data
// })
//第二种写法,用回调
//pubsub.subscribe('subClick',that.funs)
//第三种写法
this.pubId = pubsub.subscribe('subClick',(msg,data)=>{
that.name=data
})
},
methods: {
funs(mss,data){
this.name=data
}
},
//进行取消
beforeDestroy () {
pubsub.unsubscribe(this.pubId)
}
}
</script>
总结:
1,消息订阅与发布只发生在需要用到的组件之间;
2,那个组件想要接收数据,就在那个组件订阅消息,回调留在当前组件,发布由指定的组件进行。
17,$nextTich
1. 作用:在下一次 DOM 更新结束后执行其指定的回调。
2. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
18,插槽
注意:支持不同数据一次性传递到子组件的方法
父组件中有这样的数据
//把data中的color,cat,dog传递到子组件,只需要用一个titlelist,但需要用到data中各自的名称
<slot1 title="颜色" :titleList='color'/>
<slot1 title="猫" :titleList='cat'/>
<slot1 title="狗" :titleList='dog'/>
data() {
return {
names:'',
//要把这三个数据传递到子组件
color:['黄','白','黑'],
cat:['狸花猫','波斯猫','宠物猫'],
dog:['小狗','大狗','黑狗']
};
},
子组件只需要一次遍历即可
<template>
<div>
<h1>{{title}}</h1>
<ul>
<li v-for="(item,index) in titleList" :key="index">{{item}}</li>
</ul>
</div>
</template>
<script>
export default{
name:'inst1',
// 用于接收从父组件中传递过来的数据,并显示出来
props:['titleList','title']
}
</script>
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件。
分类:默认插槽、具名插槽、作用域插槽
1,默认插槽
父组件
<slot1 title="颜色">
<ul>
<li v-for="(item,index) in color" :key="index">{{item}}</li>
</ul>
</slot1>
<slot1 title="猫">
<img src="../src/assets/logo.png" alt="">
</slot1>
<slot1 title="狗">
<img src="../src/assets/logo.png" alt="">
</slot1>
data() {
return {
names:'',
//要把这三个数据传递到子组件
color:['黄','白','黑'],
cat:['狸花猫','波斯猫','宠物猫'],
dog:['小狗','大狗','黑狗']
};
},
子组件
<template>
<div>
<h1>{{title}}</h1>
<slot>默认插槽,没有内容的时候显示</slot>
</div>
</template>
<script>
export default{
name:'inst1',
}
</script>
2,具名插槽 作用就是把相对的内容填充到相应的插槽中,一个萝卜一个坑,对应的名字填充到对的slot中,默认插槽无法做到。
具体使用
<!-- 插槽 -->
<slot1 title="颜色">
<ul slot="center">
<li v-for="(item,index) in color" :key="index">{{item}}</li>
</ul>
<div slot="footer">
<ul>
<li>张三</li>
<li>李四</li>
<li>五五</li>
</ul>
</div>
</slot1>
<slot1 title="猫">
<img slot="center" src="../src/assets/logo.png" alt="">
<a slot="footer" href="#">哈哈</a>
</slot1>
<slot1 title="狗">
<img slot="center" src="../src/assets/logo.png" alt="">
<!-- 如果这里使用template 可以使用 v-solt:footer 如果不是template模块需要使用slot-->
<template v-slot:footer>
<a href="#">哈哈</a>
</template>
</slot1>
对应数据
data() {
return {
names:'',
//要把这三个数据传递到子组件
color:['黄','白','黑'],
cat:['狸花猫','波斯猫','宠物猫'],
dog:['小狗','大狗','黑狗']
};
}
子组件
<template>
<div>
<h1>{{title}}</h1>
<slot name="center">默认插槽,没有内容的时候显示</slot>
<slot name="footer">默认插槽,没有内容的时候显示</slot>
</div>
</template>
<script>
export default{
name:'inst1',
}
</script>
3,作用域插槽
重点:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
具体使用父组件
<!-- 插槽 父组件中并无数据,数据是由子组件传过来的 -->
<slot1 title="颜色">
<!-- 这里需要使用template 并且接收需要使用scope从子组件传过来的数据 -->
<template scope="cats">
<ul>
<li v-for="(index,item) in cats.cat" :key="index">{{item}}</li>
</ul>
</template>
</slot1>
<slot1 title="猫">
<!-- 这里需要使用template 并且接收需要使用scope从子组件传过来的数据 -->
<template scope="cats">
<ol>
<li v-for="(index,item) in cats.cat" :key="index">{{item}}</li>
</ol>
</template>
</slot1>
<slot1 title="狗">
<!-- 这里需要使用template 并且接收需要使用scope从子组件传过来的数据 -->
<template scope="cats">
<h2 v-for="(index,item) in cats.cat" :key="index">{{item}}</h2>
</template>
</slot1>
data() {
return {
names:''
};
},
子组件
<template>
<div>
<h1>{{title}}</h1>
<!--cat为要传递给父组件的数据-->
<slot :cat="cat">默认插槽,没有内容的时候显示</slot>
</div>
</template>
<script>
export default{
name:'inst1',
data(){
return{
cat:['狸花猫','波斯猫','宠物猫'],
}
}
}
</script>
19,vuex
1,概念
在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
2,什么时候使用?
多个组件需要共享数据时
基本使用
1,第一步先安装vuex,目前是以vuex3的版本
2,在src下新建一个store文件,然后在这个文件下面新建一个store.js文件
3,在main.js中进行引入
首先实现组件A和组件B中的数据同时变化,在store.js文件中添加这样的代码
//引入vue和vuex
import Vue from "vue";
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//基本数据用来存储变更
state:{
//初始数据为0
num:0
},
//用于修改state中的数据,属于同步操作
mutations:{
//这里的名称addNum是要在A组件中调用的点击的
addNum(state){
state.num++
}
},
//用来处理异步操作
actions:{
},
//用于对store中的数据进行加工处理
getters:{
}
})
组件A
<template>
<div>
<!-- 可以直接$store.state.变量名 -->
<div>{{$store.state.num}}</div>
<button @click="addClick">点击按钮</button>
</div>
</template>
<script>
export default{
name:'person2',
methods: {
addClick(){
//这里需要用到commit,addNum名称需要和store.js中mutations的方法名一样
this.$store.commit('addNum')
}
}
}
</script>
组件B
<template>
<div>
<!-- 也可以加this.然后在$store -->
<div>{{this.$store.state.num}}</div>
</div>
</template>
<script>
export default{
name:'person3'
}
</script>
点击组件A中的按钮,组件A和组件B中的数字会同时发生变化
传递参数的写法store.js中的写法不变,在原来的mutations里的addNum里加了一个参数
mutations:{
//传递一个参数为n1
addNum(state,n1){
state.num+=n1
}
},
组件A里面的写法,组件B还是和原来的一样保持不变,点击按钮可以看到每点一次,数字加2
<template>
<div>
<!-- 可以直接$store.state.变量名 -->
<div>{{$store.state.num}}</div>
<button @click="addClick">点击按钮</button>
</div>
</template>
<script>
export default{
name:'person2',
methods: {
addClick(){
//这里需要用到commit,addNum名称需要和store.js中mutations的方法名一样
this.$store.commit('addNum',2)
}
}
}
</script>
异步操作,点击异步按钮之后等3秒会执行减减操作,组件B还是和之前一样
//引入vue和vuex
import Vue from "vue";
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//基本数据用来存储变更
state:{
num:0
},
//用于修改state中的数据,属于同步操作
mutations:{
//传递一个参数为n1
addNum(state,n1){
state.num+=n1
},
addjs(state){
state.num--
}
},
//用来处理异步操作
actions:{
//这个wati需要和点击事件中的一样
wait(count){
setTimeout(()=>{
console.log('这是个异步')
//这里需要用到commit并且要和mutations里面的addjs一至
count.commit('addjs')
},3000)
}
},
//用于对store中的数据进行加工处理
getters:{
}
})
组件A
<template>
<div>
<!-- 可以直接$store.state.变量名 -->
<div>{{$store.state.num}}</div>
<button @click="addClick">点击按钮</button>
<button @click="steps">异步操作</button>
</div>
</template>
<script>
export default{
name:'person2',
methods: {
addClick(){
//这里需要用到commit,addNum名称需要和store.js中mutations的方法名一样
this.$store.commit('addNum',2)
},
steps(){
//这里的wati需要和actions里面的名称一样,
//如果需要传参,也是和之前的一样
this.$store.dispatch('wait')
}
}
}
</script>
处理数据
//引入vue和vuex
import Vue from "vue";
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//基本数据用来存储变更
state:{
num:0
},
//用于修改state中的数据,属于同步操作
mutations:{
//传递一个参数为n1
addNum(state,n1){
state.num+=n1
},
addjs(state){
state.num--
}
},
//用来处理异步操作
actions:{
//这个wati需要和点击事件中的一样
wait(count){
setTimeout(()=>{
console.log('这是个异步')
//这里需要用到commit并且要和mutations里面的addjs一至
count.commit('addjs')
},3000)
}
},
//用于对store中的数据进行加工处理
getters:{
setNum(state){
return '当前num是'+state.num
}
}
})
组件A
<template>
<div>
<!-- 可以直接$store.state.变量名 -->
<div>{{$store.state.num}}</div>
<button @click="addClick">点击按钮</button>
<button @click="steps">异步操作</button>
<!-- 第一种获取getters的方法,先引入,在使用 -->
<div>{{setNum}}</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default{
name:'person2',
methods: {
addClick(){
//这里需要用到commit,addNum名称需要和store.js中mutations的方法名一样
this.$store.commit('addNum',2)
},
steps(){
//这里的wati需要和actions里面的名称一样
this.$store.dispatch('wait')
}
},
computed: {
...mapGetters(['setNum'])
}
}
</script>
组件B
<template>
<div>
<!-- 也可以加this.然后在$store -->
<div>{{this.$store.state.num}}</div>
<!-- 调用getter的第二种方式 -->
<div>{{$store.getters.setNum}}</div>
</div>
</template>
<script>
export default{
name:'person3'
}
</script>
使用vuex存储数据
//子组件1
<template>
<div>
<h1>兄弟组件一</h1>
<a-button @click="SaveDataVuex">vuex存取数据</a-button>
</div>
</template>
<script>
export default {
name:"child1",
data(){
return{
names:"咖宝"
}
},
methods:{
SaveDataVuex(){
//传值的格式
this.$store.commit('demoTest/SaveVuex',this.names)
}
}
}
</script>
//vuex
export default{
namespaced: true,
state:{
name:""
},
mutations:{
//这里的名称SaveVuex一样
SaveVuex(state,newValue){
state.name=newValue
console.log(newValue)
}
},
getters:{
}
}
//子组件2
<template>
<div>
<h1>兄弟组件二</h1>
<span>{{"哈哈"+name}}</span>
<a-button @click="obtaindata">传入一个数组</a-button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name:"child2",
data(){
return{
arr:this.$store.state.demoTest.datalist
}
},
computed:{
//这里使用的模块化
...mapState('demoTest',['name'])
},
methods:{
obtaindata(){
console.log(this.datalist)
}
}
}
</script>
//父组件
<template>
<div>
<child1></child1>
<child2></child2>
<span>{{"父组件"+name}}</span>
</div>
</template>
<script>
import { mapState } from 'vuex'
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
name:"WorkPlace",
components:{child1,child2},
computed:{
...mapState('demoTest',['name'])
},
}
</script>
//最终的结果就是点击组件1里面的事件,组件2和父组件同步更改
map4个方法
1,mapState方法:用于帮助我们映射```state```中的数据为计算属性
2,mapGetters方法:用于帮助我们映射```getters```中的数据为计算属性
3,mapActions方法: 用于帮助我们生成与```actions```对话的方法,即:包含```$store.dispatch(xxx)```的函数
4,mapMutations方法用于帮助我们生成与```mutations```对话的方法,即:包含```$store.commit(xxx)```的函数
20,路由的基本使用
1. 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
2. 前端路由:key是路径,value是组件。
使用步骤
1. 安装vue-router,命令:npm i vue-router
2. 应用插件:Vue.use(VueRouter)
3. 编写router配置项:
//引入路由
import Vue from 'vue'
import Router from 'vue-router'
import rout1 from '../pages/rout1.vue'
import rout2 from '../pages/rout2.vue'
//使用
Vue.use(Router)
//配置项
const router=new Router({
routes: [
{
path:'/rout1',
component:rout1
},
{
path:'/rout2',
component:rout2
}
]
})
export default router
接下来在pages里面创建两个组件,并完成一个query传参,params的用法和query相同
特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
<template>
<div>
<div>组件一{{$route.query.id}}</div>
<div>组件一{{$route.query.name}}</div>
</div>
</template>
<script>
export default{
name:'rout1'
}
</script>
<template>
<div>
<div>组件二{{$route.query.id}}</div>
<div>组件二{{$route.query.title}}</div>
</div>
</template>
<script>
export default{
name:'rout2'
}
</script>
接着在app里面通过query向这两个组件分别传递参数
<template>
<div id="app">
<div>
<!-- 传参的第一种写法 -->
<router-link
class="list-group-item"
active-class="active"
:to="{
path:'rout1',
query:{
id:666,
name:'张三'
}
}"
>rout1</router-link
>
<!-- 传参的第二种写法 -->
<router-link class="list-group-item" active-class="active" to="/rout2?id=888&title=李四"
>rout2</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
当然还可以传递其它的数据
<template>
<div id="app">
<div v-for="(item,index) in list" :key="index">
<!-- 传参data中的数据 -->
<router-link
class="list-group-item"
active-class="active"
:to="{
path:'rout1',
query:{
id:item.id,
name:item.name
}
}"
>rout1</router-link
>
<!-- 或者 -->
<router-link class="active" :to="`/rout2?id=${item.id}&name=${item.name}`">rout2</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
list: [
{ id: "001", name: "张三" },
{ id: "002", name: "李四" },
{ id: "003", name: "王五" },
],
};
},
};
</script>
路由props的配置,让路由组件更方便地接收到参数
//引入路由
import Vue from 'vue'
import Router from 'vue-router'
import rout1 from '../pages/rout1.vue'
import rout2 from '../pages/rout2.vue'
//使用
Vue.use(Router)
//配置项
const router=new Router({
routes: [
{
path:'/rout1',
component:rout1
},
{
path:'/rout2',
component:rout2,
//props配置
props($route){
return{
id:$route.query.id,
name:$route.query.name
}
}
}
]
})
export default router
通过props接收
<template>
<div>
<div>组件二{{id}}</div>
<div>组件二{{name}}</div>
</div>
</template>
<script>
export default{
name:'rout2',
props:['id','name']
}
</script>
<router-link>的replace属性
1. 作用:控制路由跳转时操作浏览器历史记录的模式
2. 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
3. 如何开启replace模式:<router-link replace>rout2</router-link>
编程式路由导航
1. 作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵活
2. 具体编码:
```js
//$router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
缓存路由组件
1. 作用:让不展示的路由组件保持挂载,不被销毁。
2. 具体编码:
<keep-alive include="home">
<router-view></router-view>
</keep-alive>
两个新的生命周期钩子
1. 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
2. 具体名字:
1. activated路由组件被激活时触发。
2. deactivated路由组件失活时触发。
路由守卫
1. 作用:对路由进行权限控制
2. 分类:全局守卫、独享守卫、组件内守卫
路由器的两种工作模式
1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
3. hash模式:
1. 地址中永远带着#号,不美观 。
2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
3. 兼容性较好。
4. history模式:
1. 地址干净,美观 。
2. 兼容性和hash模式相比略差。
3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
常用的一些方法
父组件调用子组件中的方法
方法一过ref直接调用子组件的方法
//父组件中
<template>
<div>
<Button @click="handleClick">点击调用子组件方法</Button>
<Child ref="child"/>
</div>
</template>
<script>
import Child from './child';
export default {
methods: {
handleClick() {
this.$refs.child.fun();
},
},
}
</script>
//子组件中
<template>
<div>我是子组件</div>
</template>
<script>
export default {
methods: {
fun() {
console.log('我是子组件');
},
},
};
</script>
方法二通过组件的$emit、$on方法
//父组件中
<template>
<div>
<Button @click="handleClick">点击调用子组件方法</Button>
<Child ref="child"/>
</div>
</template>
<script>
import Child from './child';
export default {
methods: {
handleClick() {
this.$refs.child.$emit("childfun") //子组件$on中的名字
},
},
}
</script>
//子组件中
<template>
<div>我是子组件</div>
</template>
<script>
export default {
mounted() {
this.$nextTick(function() {
this.$on('childfun', function() {
console.log('我是子组件方法');
});
});
},
};
</script>
子组件通过$emit方法调用父组件函数
父组件
<template>
<div>
<div style="border:1px solid red;width:800px;height:200px">
<span>这是父组件</span>
<br/>
</div>
<child1 @childClick="childClick"></child1>
</div>
</template>
<script>
import child1 from './child1.vue'
export default {
name:"WorkPlace",
components:{child1},
methods:{
childClick(val){
console.log("Received"+val)
}
}
}
</script>
子组件
<template>
<div>
<h1>兄弟组件一</h1>
<a-button @click="emitClick">调用子组件方法</a-button>
</div>
</template>
<script>
export default {
name:"child2",
methods:{
emitClick(){
this.$emit('childClick',"组件之间调用")
}
}
}
</script>
父组件调用子组件中的函数
父组件
<template>
<div>
<a-button @click="childFun">父组件调用子组件</a-button>
<child1 ref="Element"></child1>//这里需要ref
</div>
</template>
<script>
import child1 from './child1.vue'
export default {
name:"WorkPlace",
components:{child1},
methods:{
childFun(){
this.$refs.Element.BtnClick("vue","javascript")
}
}
}
</script>
子组件
<template>
<div>
<h1>兄弟组件一</h1>
</div>
</template>
<script>
export default {
name:"child2",
methods:{
BtnClick(num1,num2){
console.log(num1,num2)
}
}
}
</script>
兄弟组件之间方法的调用 (通过子组件1调用子组件2里面的方法)
//兄弟组件1
<template>
<div>
<h1>兄弟组件一</h1>
<a-button @click="callSiblingComponents">调用兄弟组件里面的事件</a-button>
</div>
</template>
<script>
export default {
name:"child1",
methods:{
callSiblingComponents(){
this.$emit("callSiblingComponentsClick")
}
}
}
</script>
//父组件
<template>
<div>
<child1 @callSiblingComponentsClick="callSiblingComponentsClick"></child1>
<child2 ref="SiblingCompents"></child2>
</div>
</template>
<script>
import child1 from './child1.vue'
import child2 from './child2.vue'
export default {
name:"WorkPlace",
components:{child1,child2},
methods:{
callSiblingComponentsClick(){
//要调用的事件
this.$refs.SiblingCompents.callSiblingClick()
}
}
}
</script>
//兄弟组件2
<template>
<div>
<h1>兄弟组件二</h1>
</div>
</template>
<script>
export default {
name:"child2",
methods:{
callSiblingClick(){
console.log("我已触发")
}
}
}
</script>
未完待续.....