Vue2

一、数据绑定

1、v-bind  可以简写为:

单向数据绑定

后面跟的是js表达式

2、v-model

双向数据绑定

普通表单直接用v-model

单选框用v-model   value

复选框用v-model   value   与model绑定的数据必须是数组格式

下拉框用v-model value

文本框直接用v-model

v-model也可以用修饰符,用来控制输入,如lazy,trim,number

 

二、el和data的两种写法

1、el有2种写法

new Vue时候配置el属性

先创建Vue实例,随后再通过vm.$mount('#root')指定el的值

2、data的两种写法

对象式

函数式

 

三、Object.defineProperty

 

四、数据代理

基本原理:

  通过Object.defineProperty()把data对象中所有属性添加到vm上

  为每一个添加到vm上的属性,都指定一个getter/setter

  在getter/setter内部去操作(读/写)data中对应的属性

 

五、事件处理

1、v-on 可以简写为@

2、事件修饰符

prevent:阻止默认事件

stop:阻止事件冒泡

once:事件只触发一次

capture:使用事件的捕获模式

self:只有event.target是当前操作的元素时才触发事件

passive:事件的默认行为立即执行,无需等待事件回调执行完毕

scroll:滚动条一滚动就会触发的事件

wheel:鼠标滚轮事件

 

六、键盘事件

vue中键盘事件的绑定 一般用keyUp(keydown)

Vue中常用的按键别名:

  回车 => enter

  删除 => delete

  退出 => esc

  空格 => space

  换行 => tab

  上 => up/下 => down/左 => left/右 => right

系统修饰键(用法特殊):ctrl、alt、shift、meta

  配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发

  配合keydown使用:正常触发事件

也可以使用keyCode去指定具体的按键(不推荐)

Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名

 

七、计算属性

定义:将定义好的属性拿来计算

原理:底层借助了Objcet.defineproperty方法提供的getter和setter

 1 computed: {
 2      fullName: {
 3            get(){
 4 
 5             },
 6            set(value){
 7                    
 8            }
 9      }
10 }

get函数什么时候执行?

  初次读取时会执行一次

  当依赖的数据发生改变时会被再次调用

优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变

简写前提:计算属性只考虑读取不考虑修改

1 computed: {
2 }

 

八、监视属性

定义:将定义好的属性拿来计算

当被监视的属性变化时, 回调函数自动调用, 进行相关操作

监视的两种写法:

  new Vue时传入watch配置

  通过vm.$watch监视

深度监视:配置deep:true可以监测对象内部值改变(多层)

1 watch:{
2         //简写的前提watch的属性不需要immediate和deep属性的时候
3         //immediate:true;当这个属性为true时,页面刚渲染就运行handler函数
4         //deep:true;深度监视
5         isHot(newValue, preValue){
6                console.log(newValue,preValue);
7         }
8 }        

computed和watch之间的区别:

  computed能完成的功能,watch都可以完成

  watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

两个重要的小原则:

  所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。

  所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,

 

九、绑定样式

1、绑定class对象   :class

:class='xxx';xxx可以是字符串、对象、数组

  字符串写法,适用于样式的类名不确定,需要动态指定

  数组写法,适用于要绑定的样式个数不确定,名字也不确定,需要动态指定

  对象写法,适用于要绑定的样式个数确定,名字也确定,需要动态决定用不用

2、绑定style对象   :style

:style='xxx';xxx是样式对象

  对象写法

  数组写法

 

十、条件渲染

1、v-show

真显示,假隐藏

2、v-if /v-else-if /v-else

为假不做渲染,如果切换频率较高,建议用v-show;在用v-if和v-else-if时,代码中间不能被打断

 

十一、列表渲染

1、v-for

在react中必须有:key;v-for可以遍历数组、对象、字符串、指定字数,例如v-for="(number, index) in 6" :key="index"

2、虚拟DOM对比算法

key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后进行新虚拟DOM和旧虚拟DOM的差异比较,比较规则如下:

  1、旧虚拟DOM中找到了与新虚拟DOM相同的key,若内容没变则直接使用之前的真实DOM;若内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

  2、未找到与新虚拟DOM相同的key,则直接创建新的真实DOM,随后渲染到页面

用index作为key,如果破坏原有数据的结构顺序,则有可能造成数据错乱

3、列表过滤

filter不改变源数据

4、列表排序

sort改变源数据

 

十二、Vue监测数据的原理

1、vue.set

1 vue.set(vm.student,'sex','男')
2 
3 vm.$set(vm.student,'sex','男')

只能给data里面的某个属性追加属性,不能给data追加属性

2、对数组进行监测

push:数组最后位置添加元素

pop:删除数组最后一个元素

shift:删除数组第一个元素

unshift:在数组第一个元素前添加元素

splice:指定位置添加、删除、修改元素

sort:对数组进行排序
 
reverse:对数组进行反转

3、总结

vue会监视data中的所有层次的数据

通过setter实现监视,只要对data中的数据进行修改,则会调用该属性的setter方法,并重新对模板进行解析;在Vue实例化时就要传入要监测的数据

对数组的索引操作不对进行模板重新解析,监测数组是通过包裹数组更新元素的实现方法

 

十三、过滤器

过滤器的本质就是函数,可以对属性进行加工,不改变源数据

1 在页面中用
2 {{time | timeFormater}}
1 在Vue对象中用
2 filters:{
3     timeFormater(value) {
4          return xxx   
5     }
6 }

多个过滤器可以串联,链式编程

这里用的过滤器都是局部过滤器,只能在本vue实例中使用,想要全局使用需注册

1 Vue.filter('timeFormater',function(value){
2         return xxx
3 })

支持v-bind,不支持v-model

 

十四、内置指令

1、v-text

对其绑定的数据进行文本渲染,不常用,多用插值表达方式

2、v-html

3、v-cloak

配合样式使用,解决当网速过慢时页面展示出未经解析的模板的问题

4、v-once

只初始化渲染一次就视为静态资源

5、v-pre

可以跳过所在节点的编译过程,页面不会去解析渲染,可以利用它跳过那些没有指令语法、没有插值语法的节点,加快了编译

 

十五、自定义指令

用directives进行配置

指令在与元素成功绑定时会被调用,指令所在的模板被重新解析时会被调用

指令的两个参数:Dom元素element,绑定的数据binding

指令里的this都是window

自定义指令是局部指令,全局注册跟过滤器一样

指令定义时不加v-,但使用时要加

指令名如果是多个单词,要用-连接命名,不要用小驼峰

1、对象式

bind:指令与元素成功绑定时调用

inserted:指令所在元素被插入页面时调用

update:指令所在的模板被重新解析时调用

2、函数式

相当于只用了bind和update

 

十六、生命周期

声明周期中的this指向的是vm 或 组件实例对象

1、beforeCreate

此时还没有进行数据监测和数据代理,无法通过vm获得到data和methods

2、created

数据监测和数据代理完毕,可以通过vm获得到data中的数据和methods中的方法

3、beforeMount

挂载之前,页面呈现的是未经vue编译的dom结构,所有对Dom的操作,最终都不奏效

4、mounted

vue完成初始化模板解析,并把真实Dom元素放入页面后(挂载完毕)调用mounted

至此初始化过程结束,一般在此进行:开启定时器、发送网络请求、订阅消息、绑定自定义事件等初始化操作

5、beforeUpdate

此时数据是新的,但页面是旧的

6、updated

根据新数据,生成新的虚拟Dom,并与旧的虚拟Dom进行比较,最终完成页面更新

7、beforeDestory  

销毁实例vm,清理它与其他实例的连接,解绑全部指令及自定义事件监听器,但真实Dom还存在,此时vm中的所有data、methods、指令等都处于可用状态

在此阶段进行的操作都不触发页面更新

8、destoryed

销毁完毕

 

十七、组件

1、定义

实现应用中局部功能代码和资源的集合

组件定义时,不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm进行分配

组件使用方式:

  1、创建组件

  2、注册组件

  3、使用组件

组件的分类:

  1、非单文件组件

  2、单文件组件

2、非单文件组件

<div id="root">
    <h1>
        {{ msg }}
    </h1>
    <hello></hello>
    <!--使用组件-->
    <school></school>
    <hr/>
    <student></student>
    <hr/>
</div>
<div id="root2">
   <h2>root2容器</h2>
    <hello></hello>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false;

  
        //创建school组件
    const school = Vue.extend({
            template: `
              <div>
              <h2>学校名称:{{ schoolName }}</h2>
              <h2>学校地址:{{ address }}</h2>
              <button @click="showName">点我提示学校名</button>
              </div>
            `,
            //组件定义不要写el配置项,因为最终所有的组件都要被vm所管理,由vm决定服务于哪个容器
            //这里data必须写成函数形式 避免多次使用组件导致共用data对象导致一个问题
            data() {
                //注意这里不要写箭头函数
                return {
                    schoolName: '武汉科技大学',
                    address: '武汉',
                }
            },
            methods:{
                showName(){
                    alert(this.schoolName)
                }
            }
        })
    //创建school组件
    const student = Vue.extend({
        template: `
            <div>
              <h2>学生名字:{{ studentName }}</h2>
              <h2>学生年龄:{{ age }}</h2>
            </div>
        `,
        data() {
            return {
                studentName: 'Jone',
                age: 18
            }
        }
    });


    const hello = Vue.extend({
        template:`
          <div>
            <h2>你好世界,{{ name }}</h2>
          </div>
        `,
        data(){
            return {
                name: 'panyue'
            }
        }
    });

    //hello组件
    Vue.component('hello', hello); //全局注册hello 就代表所有的vm都可以用hello组件了

    // 创建vm
    new Vue({
        el: "#root",
        //配置组件(局部注册)
        data:{
            msg: 'hello world'
        },
        components: {
            school,
            student
        },
    })

    new Vue({
       el: '#root2',
    });

</script>

 需要vue脚手架的情况:

  1、vue注册组件时组件命名用大驼峰命名规范

  2、多个组件标签在使用时自闭合

3、VueComponent

组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的

我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent

 

关于this指向:

  组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【VueComponent实例对象】

  new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是【Vue实例对象】

vm与vc属性配置并不是一模一样,尽管vc底层复用了很多vm的逻辑;因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等,仅有的例外是像 el 这样根实例特有的选项,并且vc的data只能用函数式表达

4、一个重要的内置关系

VueComponent.prototype.__proto__ === Vue.prototype

 

可以理解为vc的原型对象的原型对象继承自vm的原型对象

为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法

5、单文件组件

 1 <template>
 2     <!--  组件的交互-->
 3 </template>
 4 
 5 <script>
 6   //组件交互的代码
 7   //export default school分别暴露
 8   export default { 9   };
10   //统一暴露
11   // export { school };
12   // export default school //默认暴露
13 </script>
14 
15 <style>
16     /* 组件的样式 */
17 </style>

 

十八、脚手架

1、目录结构

├── 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:包版本控制文件

2、render函数

vue.js与vue.runtime.xxx.js的区别:

  vue.js是完整版的Vue,包含:核心功能+模板解析器

  vue.runtime.xxx.js是运行版的Vue,只包含核心功能;没有模板解析器

因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容

 

1 new Vue({
2   // render: h => h(App),
3   // el:'#app',
4   render: h => h(App),
5   // vue 传递帮你调render函数并传递了一个名为createElement的函数,这里的第一个参数代表h1元素,第二个参数是h1的内容
6   // render:(createElement) => createElement('h1',"你好")
7   // template: '<h1>你好</h1>'
8 }).$mount('#app')

组件的template有专门的解析器解析,不需要render函数

3、vue.config.js

使用output.js可以查看到vue脚手架的默认配置

vue.config.js 是一个可选的配置文件,可以调节脚手架

1 module.exports = {
2     pages: {
3         index: {
4             // page 的入口
5             entry: 'src/index/main.js',
6     },
7     lintOnSave: false //关闭语法检查
8 }

4、ref属性

被用来给元素或组件注册引用信息,应用在html标签上可以获取真实的Dom元素,相当于html中的id属性

1 id:
2     document.getElementById(xx)
3 
4 ref:
5     this.$refs.xx

对于组件来说,ref拿的是组件实例对象vc,id拿的是组件根目录的id

5、props配置

 1 props: ['name', 'sex', 'age'] //简单声明接收
 2 
 3 //限制props中属性的类型 类型错误了会提示错误信息
 4 props: {
 5     name: String,
 6     sex: String,
 7     age: Number
 8 }
 9 
10 //接收时不仅限制类型还加上默认值的指定并加上必要性的限制
11 props:{
12     name:{
13         type: String, //类型
14         required: true //必要的
15     },
16     age:{
17         type: Number,
18         default: 99 //默认值
19     },
20     sex:{
21         type: String,
22         required: true
23     }
24 }

props中的数据是只读的,如果进行了修改vue会发出警告;如果业务需求确实要改,那么会复制props的内容到data中一份,然后修改data中的数据

6、mixin混入

多个组件共用的东西都可以提取出一个混入对象

可以局部混入,也可以全局混入

1 import { mixin, shareData } from "@/mixin";
2 
3 //局部混入
4 mixins:[ mixin, shareData ]
5 
6 //全局混入
7 Vue.mixin(mixin);
8 Vue.mixin(shareData);

7、vue插件

包含install方法的一个对象,install的第一个参数是vue,第二个参数是插件使用者传递的数据

1 //引入插件
2 import plugins from './plugins';
3 
4 //vue应用插件
5 Vue.use(plugins);

8、scoped样式

 

十九、组件的事件交互

1、组件化编码流程

流程:

  实现静态组件,组件要按照功能点拆分

  实现动态数据,考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:一个组件在用,放在组件自身;一些组件在用,放在他们共同的父组件上(状态提升)

  实现交互:从绑定事件开始

props适用于:

  父组件==>子组件:子组件直接用props接收

  子组件==>父组件:要求父组件先给一个函数,子组件调用函数,传参给父组件

2、浏览器的本地存储localStorage/sessionStorage

 1 //保存一个数据
 2 localStorage.setItem('键', '值');
 3 
 4 //读取一个数据
 5 localStorage.getItem('键');
 6 
 7 //删除一个数据
 8 localStorage.removeItem('键');
 9 
10 //清空所有数据
11 localStorage.clear();

sessionStorage在页面关闭后清空,localStorage需要手动清空

3、组件的自定义事件

是一种组件间通信的方式,适用于子组件给父组件传数据,要在父组件中给子组件绑定自定义事件

(1)绑定事件

 1 //通过父组件给子组件绑定一个自定义事件实现子给父传递数据 
 2 
 3 //回调函数
 4 getStudentName(name, ...params){
 5      console.log(`app收到了学生名, ${name}`);
 6      console.log(`剩余参数,${params}`);
 7 }
 8 
 9 //第一种写法使用@或v-on
10 <Student @java="getStudentName"/>
11 
12 子组件中用this.$emit.('自定义方法名',相关参数)触发自定义事件
13 
14 //第二种写法使用ref绑定事件
15 <Student ref="student"/>
16 this.$refs.student.$on('java', this.getName);
17 
18 //只使用一次
19 <Student @java.once="getStudentName"/>
20 this.$refs.student.$once('java', this.getName);

绑定自定义事件时,要么配置在methods中,要么用箭头函数

(2)解绑事件

1 //解绑多个自定义事件
2 this.$off(['自定义事件名'])
3 
4 //解绑所有自定义事件
5 this.$off()
6 
7 //销毁当前的组件实例,销毁后实例及子组件所有的自定义事件全部销毁
8 this.$destroy()

(3)原生Dom事件

1 <Student @click.native="getStudentName"/>

4、全局事件总线 

可以实现任意组件间的通信

 1 //首先vm中定义全局事件总线,在main.js中
 2 new Vue({
 3     el:'#app',
 4     render: h => h(App),
 5     beforeCreate() {
 6         //此时这个this就是vm,只不过这个时候还并没有去解析模版
 7         Vue.prototype.$bus = this; //安装全局事件总线
 8     }
 9 });
10 
11 //接收数据方要用$on绑定组件
12 //绑定组件
13 mounted() {
14     this.$bus.$on('hello', data)
15 },
16 //销毁解绑
17 beforeDestroy() {
18     this.$bus.$off('hello'); 
19 }
20 
21 //发送数据方要用$emit发送数据
22 sendStudentName(){
23     this.$bus.$emit('hello', this.name);
24 }

5、消息订阅与发布

 1 //引入第三方库pubsub-js
 2 import pubsub from 'pubsub-js'
 3 
 4 //接收数据方要用subscribe订阅消息
 5 //绑定组件
 6 mounted() {
 7     this.pudId = pubsub.subscribe('hello', (msgName,data)=>{如果用function注意这里的this指向的是null})
 8 },
 9 //销毁前取消订阅
10 beforeDestroy() {
11     pubsub.unsubscribe(this.pudId); 
12 }
13 
14 //发送数据方要用publish广播数据
15 sendStudentName(){
16    pubsub.publish('hello', this.name);
17 }

 

二十、$nextTick

 1 //编辑
 2 handleEdit(todo){
 3     // todo.isEdit = true; //注意这里添加的数据并不是响应式的 一定清楚
 4     if(Object.prototype.hasOwnProperty.call(todo, 'isEdit')){
 5         todo.isEdit = true;
 6     }else{
 7     this.$set(todo, 'isEdit', true); //保证初次加入的时候存在响应式的数据
 8     }
 9  
10      //自动获取焦点
11      //this.$refs.inputTitle.focus(); //此时你这行代码执行了,但是注意vue并没有重新解析模版(input并没有出现在页面上,dom节点并没有被更新),它一定要等这个回调函数执行完之后才会去重新渲染模版
12      //使用nextTick来解决
13     this.$nextTick(() => {
14          //这里的回调函数注意是在dom节点被更新之后才会运行的
15          this.$refs.inputTitle.focus();
16     })
17     console.log(todo);
18 }

语法:this.$nextTick(回调函数)

作用:在下一次Dom更新结束后执行其指定的回调函数

什么时候用:当改变数据后,要基于更新后的新Dom进行某些操作时,要在nextTick所指定的回调函数中执行

 

二一、过度与动画

1、动画简单用例

 1 <div>
 2     <!--如果不用name属性,style命名要用v;appear表示刚进入页面时就呈现动画效果-->
 3     <transition name="hello" appear>
 4         <h1 v-show="isShow">你好啊!</h1>
 5     </transition>
 6 </div>
 7 
 8 <script>
 9 export default {
10   name: "Test",
11   data(){
12     return {
13       isShow: true
14     }
15   }
16 }
17 </script>
18 
19 <style scoped>
20   h1{
21     background: orange;
22   }
23   .hello-enter-active{
24     animation: anim linear 0.5s;
25   }
26   .hello-leave-active{
27     animation: anim  linear 0.5s reverse;
28   }
29   @keyframes anim {
30     from {
31       transform: translateX(-100%);
32     }
33     to{
34       transform: translateX(0px);
35     }
36   }
37 </style>

2、过度简单用例

 1 <style scoped>
 2   h1{
 3     background: orange;
 4   }
 5   /*进入的起点,离开的终点*/
 6   .hello-enter,
 7   .hello-leave-to{
 8     transform: translateX(-100%);
 9   }
10   /*进入的过程,离开的过程*/
11   .hello-enter-active,
12   .hello-leave-active{
13     transition: linear .5s;
14   }
15   /*进入的终点,离开的起点*/
16   .hello-enter-to,
17   .hello-leave{
18     transform: translateX(0);
19   }
20 </style>

3、第三方库animate.css

 1 安装:
 2 npm install animate.css --save
 3 yarn add animate.css
 4 
 5 导入文件:
 6 import 'animate.css';
 7 
 8 使用:
 9 <template>
10   <div>
11     <transition-group
12         appear
13         name="animate__animated animate__bounce"
14         enter-active-class="animate__swing"
15         leave-active-class="animate__backOutUp"
16     >
17       <h1 v-show="isShow" key="1">你好</h1>
18       <h1 v-show="isShow" key="2">哈哈</h1>
19     </transition-group>
20   </div>
21 </template>

 

二二、Ajax跨域问题

使用nginx或vue-cli开启代理服务器

 1 方式一:
 2 module.exports = {
 3   devServer: {
 4     proxy: 'http://localhost:5000'
 5   }
 6 }
 7 
 8 方式二:
 9 module.exports = {
10   devServer: {
11     proxy: {
12       '/api': {//加上前缀走服务器,不加前缀走代理
13         target: '<url>',//代理目标的基础路径
14         ws: true,//用于支持websocket
15         changeOrigin: true//用于控制请求头中的host值;react默认为false
16       },
17       '/foo': {
18         target: '<other_url>'
19       }
20     }
21   }
22 }

方式一的优点是配置简单,缺点是不能配置多个代理,不能灵活控制请求是否走代理;方式二相反

 

二三、插槽

让父组件可以向子组件指定位置插入html结构

1、默认插槽

1 <slot></slot>

2、具名插槽

1 <slot name="center"></slot>
2 
3 <ul slot="center"></ul>
4 
5 <template v-slot:center></template>

3、作用域插槽

 1 子组件:
 2 <!--插槽,等着组件的使用者进行填充-->
 3 <slot :games="games"></slot>
 4 
 5 <script>
 6 export default {
 7   data(){
 8     return {
 9       games:['红色警戒','穿越火线','劲舞团','超级玛丽'],
10     }
11   }
12 }
13 </script>
14 
15 
16 父组件:
17 <template scope="{games}">
18     <!--这里data为插槽给你传递的对象包含你所需要的数据-->
19     <ul>
20     <li  v-for="(g , index) in games" :key="index">{{ g }}</li>
21     </ul>
22 </template>

 

二四、Vuex

是什么:在Vue中实现集中式数据管理的一个插件

1、使用Vuex

 1 安装vuex:
 2 vue2安装vuex3,vue3安装vuex4
 3 npm install vuex@3
 4 
 5 引入并使用:
 6 import Vuex from 'vuex'
 7 Vue.use(Vuex)
 8 //创建并暴露Store对象
 9 import store from './store'
10 new Vue({
11     store,
12 })

2、常用API

1、组件:
this.$store.dispatch(a,2)

2、store:
actions = {
    a(context,value){
        context.commit(A,value)
    }
}

3、store:
mutations = {
    A(state,value){
        state.sum += value
    }
}

4、组件:
{{ this.$store.state.sum }}

也可以由步骤1直接运行到步骤3

3、store.getters

用于将state中的数据进行加工

4、mapState、mapGetters

 1 computed:{
 2    //方式一
 3   Sum(){
 4      return this.$store.state.sum
 5   }
 6    //方式二,mapState对象写法
 7    ...mapState({Sum:'sum'})
 8    //方式三,mapState数组写法
 9    ...mapState(['sum'])
10 }  

mapState方法用于帮助我们映射state中的数据为计算属性;mapGetters方法用于帮助我们映射getters中的数据为计算属性

5、mapActions、mapMutations

 1 methods:{
 2    //方式一
 3   getSum(){
 4     this.$store.commit(getSum,1)
 5   }
 6    //用以下方式要将参数传进函数,即{{getSum(1)}},因为默认的构造方法是getSum(value)
 7    //方式二,mapMutations对象写法
 8    ...mapMutations({getSum:'getSum'})
 9    //方式三,mapMutations数组写法
10    ...mapState(['getSum'])
11 }

mapActions方法用于帮助我们生成与actions对话的方法,即包含$store.dispatch(xxx)的函数;mapMutations方法用于帮助我们生成与mutations对话的方法,即包含$store.commit(xxx)的函数

6、vue模块化+namespaced

目的:让代码更好维护,让多种数据分类更加明确

修改store.js

 1 const countAbout = {
 2   namespaced:true,//开启命名空间
 3   state:{x:1},
 4   mutations: { ... },
 5   actions: { ... },
 6   getters: {
 7     bigSum(state){
 8        return state.sum * 10
 9     }
10   }
11 }
12 
13 const personAbout = {
14   namespaced:true,//开启命名空间
15   state:{ ... },
16   mutations: { ... },
17   actions: { ... }
18 }
19 
20 const store = new Vuex.Store({
21   modules: {
22     countAbout,
23     personAbout
24   }
25 })

开启命名空间后,组件中读取state数据:

1 //方式一:自己直接读取
2 this.$store.state.personAbout.list
3 //方式二:借助mapState读取:
4 ...mapState('countAbout',['sum','school','subject']),

开启命名空间后,组件中读取getters数据:

1 //方式一:自己直接读取
2 this.$store.getters['personAbout/firstPersonName']
3 //方式二:借助mapGetters读取:
4 ...mapGetters('countAbout',['bigSum'])

开启命名空间后,组件中调用dispatch:

1 //方式一:自己直接dispatch
2 this.$store.dispatch('personAbout/addPersonWang',person)
3 //方式二:借助mapActions:
4 ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

开启命名空间后,组件中调用commit:

1 //方式一:自己直接commit
2 this.$store.commit('personAbout/ADD_PERSON',person)
3 //方式二:借助mapMutations:
4 ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

 

二五、路由

理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。

前端路由:key是路径,value是组件

后端路由:key是路径,value是函数

基本使用:

  安装vue-router,命令:npm i vue-router

  应用插件:Vue.use(VueRouter)

  编写router配置项

 1 //引入VueRouter
 2 import VueRouter from 'vue-router'
 3 //引入Luyou 组件
 4 import About from '../components/About'
 5 import Home from '../components/Home'
 6 
 7 //创建router实例对象,去管理一组一组的路由规则
 8 const router = new VueRouter({
 9  routes:[
10    {
11    path:'/about',
12    component:About
13    },
14    {
15    path:'/home',
16    component:Home
17    }
18  ]
19 })
20 
21 //暴露router
22 export default router

实现切换(active-class可配置高亮样式):

1 <router-link active-class="active" to="/about">About</router-link>

指定展示位置:

1 <router-view></router-view>

 

二六、嵌套路由

 1 routes:[
 2   {
 3   path:'/about',
 4   component:About,
 5   },
 6   {
 7   path:'/home',
 8   component:Home,
 9   children:[ //通过children配置子级路由
10     {
11     path:'news', //此处一定不要写:/news
12     component:News
13     },
14     {
15     path:'message',//此处一定不要写:/message
16     component:Message
17     }
18     ]
19   }
20 ]

 

二七、路由Query传参

传递参数:

 1 <!-- 跳转并携带query参数,to的字符串写法 -->
 2 <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">跳转</router-link>
 3                 
 4 <!-- 跳转并携带query参数,to的对象写法 -->
 5 <router-link 
 6     :to="{
 7         path:'/home/message/detail',
 8         query:{
 9            id:m.id,
10            title:m.title
11         }
12     }"
13 >跳转</router-link>

接收参数:

1 $route.query.id
2 $route.query.title

 

二八、路由命名

作用:可以简化路由的跳转

使用:

  给路由命名:

 1 {
 2  path:'/demo',
 3  component:Demo,
 4  children:[
 5   {
 6    path:'test',
 7    component:Test,
 8    children:[
 9      {
10      name:'hello' //给路由命名
11      path:'welcome',
12      component:Hello,
13      }
14     ]
15    }
16  ]
17 }

  简化跳转:

 1 <!--简化前,需要写完整的路径 -->
 2 <router-link to="/demo/test/welcome">跳转</router-link>
 3 
 4 <!--简化后,直接通过名字跳转 -->
 5 <router-link :to="{name:'hello'}">跳转</router-link>
 6 
 7 <!--简化写法配合传递参数 -->
 8 <router-link 
 9     :to="{
10         name:'hello',
11         query:{12         }
13     }"
14 >跳转</router-link>

 

二九、路由Params传参

配置路由,声明接收params参数:

 1 {
 2  path:'/home',
 3  component:Home,
 4  children:[
 5    {
 6    path:'news',
 7    component:News
 8    },
 9    {
10    component:Message,
11    children:[
12      {
13        name:'xiangqing',
14        path:'detail/:id/:title', //使用占位符声明接收params参数
15        component:Detail
16        }
17    ]
18    }
19 ]
20 }

传递参数:

 1 <!-- 跳转并携带params参数,to的字符串写法 -->
 2 <router-link :to="/home/message/detail/${m.id}/${m.title}">跳转</router-link>
 3                 
 4 <!-- 跳转并携带params参数,to的对象写法 -->
 5 <router-link 
 6     :to="{
 7         name:'xiangqing',
 8         params:{
 9            id:m.id,
10            title:m.title
11         }
12     }"
13 >跳转</router-link>

特别注意:

路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

 

二九、路由的props配置

作用:让路由组件更方便的收到参数

 1 {
 2  name:'xiangqing',
 3  path:'detail/:id',
 4  component:Detail,
 5 
 6  //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
 7  // props:{a:900}
 8 
 9  //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
10  // props:true
11  
12  //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
13  props(route){
14    return {
15      id:route.query.id,
16       title:route.query.title
17       }
18    }
19 }

 

三十、路由导航(前进/后退)

1、replace属性

作用:控制路由跳转时操作浏览器历史记录的模式

浏览器的历史记录有两种写入方式:分别为pushreplacepush是追加历史记录,replace是替换当前记录。路由跳转时候默认为push

如何开启replace模式:<router-link replace .......>News</router-link>

2、路由实现前进后退

 1 //$router的两个API
 2 this.$router.push({
 3  name:'xiangqing',
 4   params:{
 5    id:xxx,
 6    title:xxx
 7         }
 8 })
 9 
10 this.$router.replace({
11  name:'xiangqing',
12   params:{
13    id:xxx,
14    title:xxx
15         }
16 })
17 this.$router.forward() //前进
18 this.$router.back() //后退
19 this.$router.go() //可前进也可后退

3、缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁

1 <!--如果要缓存多个路由组件就改写为:include="['News', 'Message']"-->
2 <keep-alive include="组件名"> 
3     <router-view></router-view>
4 </keep-alive>

 

三一、两个新的生命周期钩子

作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态

1、actived

路由组件被激活时触发

2、deactivated

路由组件失活时触发

 

三二、路由守卫

作用:对路由进行权限控制

分类:全局守卫、独享守卫、组件内守卫

全局守卫:

 1 //全局前置守卫:初始化时执行、每次路由切换前执行
 2 router.beforeEach((to,from,next)=>{
 3  console.log('beforeEach',to,from)
 4  if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
 5   if(localStorage.getItem('name') === 'zhangsan'){ //权限控制的具体规则
 6    next() //放行
 7    }else{
 8    alert('暂无权限查看')
 9    // next({name:'guanyu'})
10    }
11  }else{
12   next() //放行
13  }
14 })
15 
16 //全局后置守卫:初始化时执行、每次路由切换后执行
17 router.afterEach((to,from)=>{
18  console.log('afterEach',to,from)
19  if(to.meta.title){ 
20   document.title = to.meta.title //修改网页的title
21  }else{
22   document.title = 'vue_test'
23  }
24 })

独享守卫:

 1 beforeEnter(to,from,next){
 2   console.log('beforeEnter',to,from)
 3   if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
 4     if(localStorage.getItem('name') === 'zhangsan'){
 5       next()
 6      }else{
 7        alert('暂无权限查看')
 8        // next({name:'guanyu'})
 9       }
10     }else{
11      next()
12     }
13   }

组件内守卫:

1 //进入守卫:通过路由规则,进入该组件时被调用
2 beforeRouteEnter (to, from, next) {
3 },
4 //离开守卫:通过路由规则,离开该组件时被调用
5 beforeRouteLeave (to, from, next) {
6 }

 

三三、路由器的两种工作模式

hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器

hash模式:

  地址中永远带着#号,不美观 

  若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法

  兼容性较好

history模式:

  地址干净,美观 

  兼容性和hash模式相比略差

  应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题

1 const router = new VueRouter({
2     //默认开启hash模式
3     mode: 'history',
4 });

 

posted @ 2022-02-18 17:12  奈非天c  阅读(187)  评论(0)    收藏  举报