vue常用知识点梳理

记录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>

未完待续.....

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值