【学习笔记】Vue2基础

Vue2

Vue-basic

简述

Vue是一套用于构建用户界面渐进式(自底向上逐层应用)JavaScript框架

特点

  • 采取组件化模式(提高代码复用率、利于代码维护)

  • 是一种声明式编码(无需之间操作DOM、提高开发效率)【区别于命令式编码】

  • 使用==虚拟DOM+==优秀的Diff算法(尽可能复用DOM节点)

初识

  • 下载并配置

    <script type="text/javascript" src="./js/vue.js"></script>
    

    下载vue.js并以<script>标签引入,Vue会注册成一个全局变量

  • 初始

    <body>
    	<div id="root">
            <h1>Hello,{{name}}</h1>
        </div>
    </body>
    <script type="text/javascript">
    	Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示。
    	// 创建Vue实例
    	new Vue({
    		// el 用于指定当前实例为哪个容器服务,值通常为css选择器字符串;
    		el: '#root',
    		// data中存储数据,数据供el所指定的容器使用;
    		data: {
    			name: 'Vue'
    		}
    	})
    </script>
    
    

    1.创建vue实例,并传入一个配置对象;

    2.root容器代码符合html规范,视为Vue模板;

    3.Vue实例和容器是一一对应的;

    4.只有一个Vue实例,并且会配合着组件使用

    5.{{xxx}} xxx代表的是js表达式,且会自动读取到data所有属性;

    6.data数据发送改变,页面中数据会自动更新;

    • el的两种写法
    <!-- 方式1 -->
    <div id="root">
    	<h1>你好,{{name}}</h1>
    </div>
    <script>
    	new Vue({
        	el: '#root',      
    		data: {
    			name: '尚硅谷'
    		}
    	})
    </script>
    
    <!-- 方式2 -->
    <div id="root">
    	<h1>你好,{{name}}</h1>
    </div>
    <script>
    	const vm = new Vue({
            data: {
                name: '尚硅谷'
            }
    	})
        v.$mount('#root')
    </script>
    
    1. new Vue时配置el属性
    2. 先创建Vue实例,再通过v.$mount('#root')指定el值
    • data的两种写法
    <!-- 方式1:对象式 -->
    <div id="root">
    	<h1>你好,{{name}}</h1>
    </div>
    <script>
    	new Vue({
        	el: '#root',      
    		data: {
    			name: '尚硅谷'
    		}
    	})
    </script>
    
    <!-- 方式2:函数式 -->
    <div id="root">
    	<h1>你好,{{name}}</h1>
    </div>
    <script>
    	new Vue({
        	el: '#root',      
    		data: function() {
                return{
                    name:'尚硅谷'
                }
            }
    	})
    </script>
    

    1.对象式

    2.函数式,组件时必用

重要原则:Vue管理的函数不能使用箭头函数,因会使之成为Window实例,而非Vue实例。

  • 模板语法

    • 插值语法

      用于解析标签体内容

      {{xxx}}
      

      xxx是js表达式,且可以直接读取data中所有属性

    • 指令语法

      解析标签属性、解析标签体内容、绑定事件

      v-bind:href = 'xxx'
      :href='xxx'
      

      xxx是js表达式

      有很多指令,形式均为v-????

数据绑定

  • 单向数据绑定

    v-bind:href = 'xxx'
    <!-- 缩写 -->
    :href = 'xxx'
    

    数据只能从data流向页面

  • 双向数据绑定

    v-mode:value = 'xxx'
    <!-- 缩写 -->
    v-model = 'xxx'
    

    数据不仅能从data流向页面,还能从页面流向data

    v-model只能应用在表单类元素(输入类元素)上,例如input、select等;

    v-model:value可简写为v-model,而v-model一般默认收集value值

MVVM模型

在这里插入图片描述

  • 模型(Model):对应data中的数据

  • 视图(View):模板

  • 视图模型(ViewModel):Vue实例对象

    data中所有属性都会出现在vm上,而vm上所有属性及Vue原型上所有属性都能被直接使用。

数据代理

  • 通过一个对象代理对另一个对象中属性的操作(读/写)

  • JavaScript中数据代理

    <script>
    	let obj1 = {
    		x: 100
    	}
    	let obj2 = {
    		y: 100
    	}
    	Object.defineProperty(obj2, 'x', {
    		get() {
    			return obj1.x
    		},
    		set(value) {
    			obj1.x = value
    		}
    	})
    </script>
    
  • Vue中数据代理

    • 通过vm对象代理data对象中属性的操作(读/写)
    • 更为方便地操作data中的数据
    • 原理:通过Object.defineProperty()把data对象中所有属性添加到vm上,为每个添加到vm上的属性,都指定一个getter/setter内部去操作(读/写)data中的数据。

    图示:
    在这里插入图片描述

    1. 加工了data
    2. vm._data = data

事件处理

事件基本使用
  • 使用v-on:xxx@xxx绑定事件,其中xxx式事件名
  • 事件回调需要配置再methods对象中最终会放在vm上
  • methods中配置的函数不使用箭头函数,否则导致this的对象不是vm,而是window
  • methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
  • @click='demo'@click='demo($event)'效果一致,后者可传参
事件修饰符
  • prevent:阻止默认事件
  • stop:阻止事件冒泡
  • once:事件只触发一次
  • capture:使用事件的捕获模式
  • self:只有event.target是当前操作元素时才能触发事件
  • passive:事件默认行为立即执行,无须等待事件回调执行完毕

修饰符可以连续写

键盘事件
  • Vue中将常用按键起了别名

    • 回车 --> enter 删除–>delete(捕获“删除“和”退格“键) 退出–>esc 空格–>space 换行–>tab(配合keydown使用)
    • 上–>up 下–>down 左–>left 右–>right
  • Vue中未提供别名的按键,使用按键原始key值绑定,

  • 系统修饰按键,例如ctrlaltshiftmeta/window/command

    • 配合keyup使用:按下修饰键的同时,需要再按下其他键,随后在释放其他键,事件才能被触发
    • 配合keydown使用:正常触发事件
  • 定制按键别名Vue.config.keyCodes.自定义键名 = 键码

计算属性与监视属性

计算属性
  • 定义:需要的属性不存在,而通过已有属性计算得来

  • 原理:底层借助Object.defineproperty()方法提供getter和setter

  • get()函数的执行

    • 初次读取时执行一次
    • 当依赖数据发生变化时再次被调用
  • 应用

    new Vue({
    	el: '#root',
    	data: {
    		firstName: '张',
    		lastName: '三'
    	},
    	computed: {
    		fullName: {
    			// 读取fullName时,get就会被调用,且返回值会作为fullName的值
    			// 初次读取fullName时,或者所依赖的数据发生变化时,get被调用
    			get() {
    				return this.firstName + '-' + this.lastName
    			},
    			set(value) {
    				const arr = value.split('-')
    				this.firstName = arr[0]
    				this.lastName = arr[1]
    			}
    		}
            // 简写(不考虑修改时使用,即不配置set()时)
            fullName(){
        		return this.firstName + '-' + this.lastName
    		}
    	}
    })
    
  • 优势

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

  • 备注

    计算属性最终会出现在vm对象上,直接读取使用

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

监视属性
  • 普通监视

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

    • 监视的属性必须存在,才能进行监视

    • 语法

      • new Vue时传入watch配置
      const vm = new Vue({
      	el: '#root',
          data: {
      		isHot: true
          },
      	watch: {
      		isHot: {
      			immediate: true,
      			handler(newValue, oldValue) {
      			console.log('isHot被修改了', newValue, oldValue);
      			}
      		}
      	},
      })
      
      • 通过vm.$watch监视
      const vm = new Vue({
      	el: '#root',
          data: {
      		isHot: true
          },
      })
      vm.$watch('isHot', {
          immediate: true,
          handler(newValue, oldValue) {
              console.log('isHot被修改了', newValue, oldValue);
          }
      })
      
  • 深度监视

    • Vue中的watch默认不监测对象内部值的改变(一层)

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

      Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以

      使用watch时根据数据的具体结构,决定是否采用深度监测

计算对比与监视属性对比
  • computed能完成的功能,watch都可以完成;

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

    所有被Vue管理的函数,最好写成普通函数,此时this会指向vm或组件实例对象;

    所有不被Vue所管理的的函数(如定时器回调函数、ajax回调函数、Promise回调函数等),最好写成箭头函数,此时可使this的指向vm或组件实例对象。

绑定样式

绑定class
  1. 字符串写法

    适用于样式类名不确定,需要动态指定

    <body>
        <div class="basic" :class="classStr" @click="changeMood">{{name}}</div>
    </body>
    <script>
        new Vue({
            el: '#root',
             data: {
                name: 'Vue',
                classStr: 'normal',
             },
        	methods: {
            	changeMood() {
                	const arr = ['happy', 'sad', 'normal']
                	const index = Math.floor(Math.random() * 3)
                	this.mood = arr[index]
            		}
        		},
        	}
        })
    </script>
    
  2. 数组写法

    适用于绑定的样式个数不确定、名字不确定

    <body>
        <div class="basic" :class="classArr">{{name}}</div>
    </body>
    <script>
        new Vue({
            el: '#root',
            data: {
                name: 'Vue',
                 classArr: ['wwk1', 'wwk2', 'wwk3'],
             },
        })
    </script>
    
  3. 对象写法

    适用于绑定的样式个数确定、名字确定,但要动态用不用

    <body>
        <div class="basic" :class="classArr">{{name}}</div>
    </body>
    <script>
        new Vue({
            el: '#root',
            data: {
                name: 'Vue',
                 classObj: {
                    wwk1: false,
                    wwk2: true,
                },
             },
        })
    </script>
    
绑定style
  1. 数组写法

    <body>
        <div class="basic" :style="styleArr">{{name}}</div>
    </body>
    <script>
        new Vue({
            el: '#root',
            data: {
                name: 'Vue',
                styleArr: [{
                    fontSize: '40px',
                    color: 'red',
                }, 
                {
                    backgroundColor: 'orange'
                }, ]
             },
        })
    </script>
    
  2. 对象写法

    <body>
        <div class="basic" :style="styleObj">{{name}}</div>
    </body>
    <script>
        new Vue({
            el: '#root',
            data: {
                name: 'Vue',
                styleObj: {
                    fontSize: '40px',
                    color: 'red',
                    backgroundColor: 'orange'
                },
             },
        })
    </script>
    

条件渲染

  • v-if

    • 写法

      v-if = "expression"
      v-else-if = "expression"
      v-else = "expression"
      
    • 适用

      切换频率较低的场景

    • 特点

      不展示DOM元素,直接被移除

    • 注意点

      v-if可以和v-else-if及v-else一起使用,但要求其结构不能被打断;使用v-if时,元素可能无法获取到;

  • v-show

    • 写法

      v-show = "expression"
      
    • 适用

      切换频率较高的场景

    • 特点

      不展示DOM元素,未被移除,仅仅使用样式display=none隐藏掉了

    • 注意点

      使用v-show时,元素一定能被获取到

列表渲染

  • v-for指令

    • 用于展示列表数据

    • 语法

      v-for="(item,index) in xxx" :key="yyy"
      
    • 可遍历

      数组、对象、字符串(使用较少)、指定次数(使用较少)

  • key的内部原理

    • 虚拟DOM中key的作用

      key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据“新数据”生成“新的虚拟DOM”,随后Vue进行“新虚拟DOM”与“旧虚拟DOM”的差异比较

    • 对比规则

      1. “旧虚拟DOM”中找到与“新虚拟DOM”相同的key:
        • 若虚拟DOM中内容没变,直接使用之前的真实DOM;
        • 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
      2. “旧虚拟DOM”中未找到与“新虚拟DOM”相同的key:
        • 创建新的真实DOM,随后渲染到页面
    • 用index作为key可能引发的问题

      1. 若对数据进行逆序添加、逆序删除等破坏顺序操作,会产生不必要的真实DOM更新,导致界面效果不出现问题,但会降低效率
      2. 若结构中还包含输入类的DOM,会产生错误DOM更新,导致界面出现问题
    • 如何选择

      • 最好使用每条数据的唯一标识作为key,如id、手机号、身份证号、学号等唯一值
      • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作而仅用于渲染列表用于展示,使用index作为key是没问题的
  • 列表过滤

  • 列表排序

监视数据

  • 原理

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

  • 分类

    • 监视对象中数据

      通过setter实现监视,且要在new Vue时就传入要监视的数据

      1. 对象中后追加的属性,Vue默认不做响应式处理

      2. 需给后追加的属性做响应式,需使用API:

        Vue.set(target,propertyName/index,value)
        vm.$set(target,propertyName/index,value)
        
    • 监测数组中数据

      通过包裹数组更新元素的方法实现,本质做两件事:其一,调用原生对应的方法队数组进行更新;其二,重新解析模板,进而更新页面;

      在Vue修改某个元素会用到到以下方法:

      // 一些API
      push()
      pop()
      shift()
      unshift()
      splice()
      sort()
      reverse()
      // 直接更改
      Vue.set()
      vm.$set()
      
  • 示例

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script type="text/javascript" src="./js/vue.js"></script>
    </head>
    
    <body>
    
        <div id="root">
            <h1>学生信息</h1>
            <button @click="student.age++">年龄加一岁</button>
            <button @click="addSex">添加性别属性(默认值为男)</button>
            <button @click="student.sex='未知'">修改性别</button>
            <button @click="addFriend">在列表首位添加一条朋友信息</button>
            <button @click="updateFirstFriendName">修改第一个朋友为张三</button>
            <button @click="addHobby">添加一个爱好</button>
            <button @click="updateHobby">修改第一个爱好</button>
            <h2>学生姓名:{{student.name}}</h2>
            <h2 v-if="student.sex">学生性别:{{student.sex}}</h2>
            <h2>学生年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
            <h2>爱好</h2>
            <ul>
                <li v-for="(h,index) in student.hobbies" :key="index">
                    {{h}}
                </li>
            </ul>
            <h2>朋友们</h2>
            <ul>
                <li v-for="(f,index) in student.friends" :key="index">
                    {{f.name}}--{{f.age}}
                </li>
            </ul>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false; // 阻止vue在启动时生成生产提示。
        // 创建Vue实例
        new Vue({
            // el 用于指定当前实例为哪个容器服务,值通常为css选择器字符串;
            el: '#root',
            // data中存储数据,数据供el所指定的容器使用;
            data: {
                student: {
                    name: "tom",
                    age: {
                        rAge: 21,
                        sAge: 18,
                    },
                    hobbies: ['抽烟', '喝酒', '烫头', '听相声'],
                    friends: [{
                        name: 'jerry',
                        age: 20
                    }, {
                        name: 'tony',
                        age: 21
                    }]
                }
            },
            methods: {
                addSex() {
                    // Vue.set(this.student, "sex", '男')
                    this.$set(this.student, "sex", '男')
                },
                addFriend() {
                    this.student.friends.unshift({
                        name: "jack",
                        age: 22
                    })
                },
                updateFirstFriendName() {
                    this.student.friends[0].name = "Kevin"
                },
                addHobby() {
                    this.student.hobbies.push("学习")
                },
                updateHobby() {
                    // this.student.hobbies.splice(0, 1, "开车")
                    // this.set(this.student.hobbies, 0, '开车')
                    this.$set(this.student.hobbies, 0, '开车')
                }
            },
        })
    </script>
    
    </html>
    
  • Vue.set()vm.$set()不能给vm和vm中的根数据对象添加数据

收集表单数据

  1. <input type="text" />,则v-model收集的是value值,用户输入的就是value值

  2. <input type="radio" />,则v-model收集的是value值,且要给标签配置value值

  3. <input type="checkbox" />

    没有配置input中的value属性,则收集的是checked(勾选为true,未勾选为false);

    而配置了input中的value属性:

    ​ v-model的初始值是非数组,则收集的是checked(勾选为true,未勾选为false);

    ​ v-model的初始值是数组,则收集的是value组成的数组;

注:v-model有三个修饰符

  1. lazy失去焦点再收集数据
  2. number输入字符串转成有效数字
  3. trim输入首尾空格过滤

过滤器

  • 定义

    对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑处理)

  • 语法

    • 注册过滤器

      // 全局过滤器
      Vue.filter(name,callback)
      // 局部过滤器
      new Vue({
          filter:{
              
          }
      })
      
    • 使用过滤器

      {{ xxx | 过滤器名}}
      v-bind:属性 = "xxx | 过滤器名"
      
  • 过滤器也可以接收额外参数、多个过滤器也可以串联

    并不改变原本数据,而是产生新的对应数据

内置指令

v-bind:xxx 单向绑定解析表达式,可简写为 :xxx

v-model: 双向数据绑定

v-for: 遍历数组/对象/字符串

v-on: 绑定事件监听,可简写为 @

v-if: 条件渲染(动态控制节点是否存在)

v-else: 条件渲染(动态控制节点是否存在)

v-show: 条件渲染(动态控制节点是否展示)

v-text:xxx 向所在的节点中渲染文本内容(与插值语法{{xxx}}类似,但区别在于v-text会替换掉节点中的内容,而插值语法则不会)

v-html:xxx 向指定节点中渲染包含html结构的内容(与v-text类似,但区别在于v-html会识别html结构并解析),[安全性问题:网站上动态渲染任意HTML危险,容易被XSS攻击;一定要在可信内容上使用v-html;永远不要用在用户提交的内容上!]

v-cloak 一特殊属性,Vue示例创建完毕并接管容器会自动删掉v-cloak属性;使用css配合v-cloak可以解决网络慢时页面展示出{{xxx}}的问题

v-once 所在节点在初次动态渲染后就被视为静态内容,之后数据的改变不会引起v-once所在结构的更新,可以用于优化性能

v-pre 跳过所在节点的编译过程;可用其跳过"没有使用指令的语句、没有使用插值语法的节点",会加快编译

自定义指令

  • 语法

    • 局部指令

      配置对象

      new Vue({
      	directives:{指令名:配置对象}
      })
      

      配置对象中常用的三个回调

      1. bind 指令与元素成功绑定时调用
      2. inserted 指令所在元素被插入页面时调用
      3. update 指令所在模板结构被重新解析时调用

      函数

      new Vue({
      	directives:{指令名:回调函数}
      })
      
    • 全局指令

      配置对象

      Vue.directive(指令名,配置对象)
      

      回调函数

      Vue.directive(指令名,回调函数)
      
  • 指令定义时不加v-,但使用时需要加v-

    指令名如果是多个单词,要使用kebab-case命名方式,而不是camelCase命名方式

生命周期

  • 内容

    又名生命周期回调函数、生命周期函数、生命周期钩子;是Vue在关键时刻帮助调用一些特殊名称的函数;生命周期函数的名字不可改变,但函数的具体内容可根据需求编写;其中this指向的是vm或组件实例对象

  • 流程图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8SfvnHpi-1670124487775)(F:\前端\Vue\资料(含课件)\02_原理图\生命周期.png)]

  • 过程

    1. 将要创建 = = => 调用beforeCreate函数

    2. 创建完毕 = = => 调用created函数

    3. 将要挂载 = ==> 调用beforeMount函数

    4. 挂载完毕 = = => 调用mounted函数(常用:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等[初始化操作])

    5. 将要更新 = = => 调用beforeUpdate函数

    6. 更新完毕 = = => 调用updated函数

    7. 将要销毁 = = => 调用beforeDestroy函数(清除定时器、解绑自定义事件、取消订阅消息等[收尾工作])

    8. 销毁完毕 = = => 调用destroyed函数

      销毁后借助Vue开发者工具无法看到任何信息;销毁后自定义事件会失效,但原生DOM事件依旧有效;一般不会在beforeDestroy操作数据(因操作数据后不会再触发更新流程)。

Vue-component

模块和组件、模块化和组件化

  • 模块

    向外提供特定功能的JavaScript程序,一般为一个js文件;便于复用js、简化js的编写、提高js运行效率

  • 组件

    实现应用中局部/特定功能代码(包括HTML、CSS和JavaScript)和资源(MP3、MP4等)的集合;便于复用编码、简化项目编码、提高运行效率

  • 模块化

    应用中的js都以模块编写,该应用即为一个模块化的应用。

  • 组件化

    应用中的功能都是多组件的方式来编写的,该应用即为一个组件化应用。

非单文件组件

  • 定义

    一个文件中包含有n个组件

  • 使用

    1. 定义组件(创建组件)

      Vue.extend(options)
      

      optionsnew Vue(options)传入的options几乎一样,区别在于:

      1. el不需要写–最终所有组件都要经过一个vm的管理,由vm中的el决定服务于哪个容器
      2. data必须写成函数形式–避免组件被复用,数据存在引用关系
    2. 注册组件

      // 局部注册
      new Vue({
      	components:{
      	
      	}
      })
      // 全局注册
      Vue.component("组件名",组件)
      
    3. 使用组件(写组件标签)

      <组件名></组件名>
      
  • 注意点

    • 组件名

      1. 一个单词组成

        首字母小写school或首字母大写School

      2. 多个单词组成

        kebab-case命名 my-school或CamelCase命名MySchool(需要Vue脚手架支持)

        组件名尽可能回避HTML中已有的元素名称;可以使用那么配置项指定主键再开发者工具中呈现的名字;

    • 组件标签

      <school></school><school/>

      不用使用脚手架时,<school/>会导致后续组件不能渲染。

    • 简写方式

      const school = Vue.extend(options)
      // 简写为
      const school = options
      
    • VueComponent

      1. 组件本质是一个名为VueComponent的构造函数,是Vue.extend生成的
      2. 只需要写组件标签<school></school>或<school>,Vue解析是会创建school组件的实例对象,即自动执行new VueComponent(options)
      3. 每次调用Vue.extend,返回的都是一个全新的VueComponent
      4. this的指向问题:组件配置中,data函数、methods中的函数、watch中的函数、computed中的函数,其this均是VueComponent实例对象(简称vc)new Vue()配置中,data函数、methods中的函数、watch中的函数、computed中的函数,其this均是Vue实例对象(简称vm)
    • 内置关系

      VueComponent.prototype.__proto__ === Vue.prototype
      在这里插入图片描述

      目的:让组件实例对象(vc)可以访问到Vue原型上的属性和方法

单文件组件

一个文件中只包含一个组件

<template>
    <!-- 组件的结构 -->
    <div></div>
</template>


<script>
    // 组件交互相关的代码(数据、方法)
</script>

<style>
    /* 组件的样式 */
</style>

Vue-cli

准备工作

  • 全局安装

    npm install -g @vue/cli
    

    仅执行第一次即可

  • 创建项目

    vue create xxx
    

    切换到需要创建项目的目录下,创建项目

  • 启动项目

    npm run serve
    

文件结构分析

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

ref属性

  • 被用来给元素或子组件注册引用信息(HTML中ID的替代者)

  • 应用在HTML标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)

  • 使用

    <template>
    	<!-- 打标识 -->
        <h1 ref="xxx">……</h1>
        或
        <school ref="xxx"></school>
    </template>
    <script>
        // 获取
        this.$refs.xxx
    </script>
    

配置项props

  • 功能

    让组件接收外部传来的数据

  • 使用

    1. 传递数据

      <template>
      	<Demo name="xxx"/>
      </template>
      
    2. 接收数据

      • 只接受类型

        <script>
        	props:['name']
        </script>
        
      • 限制类型]

        <script>
        	props:{
                name:String
            }
        </script>
        
      • 限制类型+限制必要性+指定默认值

        <script>
        	props:{
                name:{
                	type:String,    // 类型
                	required:true,  // 必要性
                	default:'张三'  // 默认值
                }
            }
        </script>
        
  • props是只读的,Vue底层会监测对props的修改,如果修改就会发出警告;

    若业务需求确定需要修改,则复制props的相关内容到data中一份再去修改data中的数据。

mixin混入

  • 功能

    可以把多个组件共用的配置提取成一个混入对象

  • 使用

    1. 定义混入

      {
      	data(){
      		……
      	},methods:{
      		……
      	}
      	……
      }
      

      定义名称为xxx.js

    2. 使用混入

      • 全局混入

        import xxx from '...'
        Vue.mixin(xxx)
        

        在main.js中使用

      • 局部混入

        <script>
            import xxx from '...'
        	mixins:['xxx']
        </script>
        

        在局部文件中使用

插件

  • 功能

    用于增强Vue

  • 本质

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

  • 使用

    1. 定义插件

      Obj.install = function (Vue,options){
      	// 添加全局过滤器
      	Vue.filter(……)
          // 添加全局指令
          Vue.directive(……)
          // 配置全局混入
          Vue.mixin(……)
          // 添加实例方法
          Vue.prototype.$myMethod = function () {
              
          }
          Vue.prototype.$myMethod = xxx
      }
      

      定义为xxx.js

    2. 使用插件

      // 引入插件
      import xxx from ''
      // 使用插件
      Vue.use(xxx)
      

      在main.js中使用

scoped样式

  • 功能

    让样式在局部生效,防止冲突

  • 使用

    <style scoped>
        xxx{
            
        }
    </style>
    

总结TodoList案例

组件化编码流程
  1. 实现静态组件:抽取(拆分)组件,组件要按照功能点拆分,使用组件实现静态页面效果,命名不要和html元素冲突
  2. 展示动态数据:数据类型、名称是什么?数据保存在哪个组件中(考虑数据的存放位置,数据是一个组件在用还是一些组件在用)
    • 一个组件在用:放在组件自身即可
    • 一些组件在用:放在他们共同的父组件上[状态提升]
  3. 交互:从绑定事件监听开始
props适用于
  1. 父组件 ===> 子组件 通信
  2. 子组件 ===> 父组件 通信(要求父先给子一个函数)

v-model使用

v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

props传值

props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐

webStorage

  • 存储内容大小一般支持5MB左右

  • 浏览器端通过Window.sessionStorageWindow.localStorage属性来实现本地存储机制

  • 相关API:

    1. xxxStorage.setItem('key','value')

      该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值

    2. xxxStorage.getItem('person')

      该方法接受一个键名作为参数,返回键名对应的值

    3. xxxStorage.removeItem('key')

      该方法接受一个键名作为参数,并把该键名从存储中删除

    4. xxxStorage.clear()

      该方法会清空存储中的所有数据

  • 备注

    1. SessionStorage存储的内容会随着浏览器窗口关闭而消失
    2. LocalStorage存储的内容需要手动清除才会消失
    3. xxxStorage.getItem('xxx')如果xxx对应的value获取不到,那么getItem的返回值是null
    4. JSON.parse(null)的结果依然是null

组件的自定义事件

  • 一种组件间通信的方式,适用于:子组件 ===> 父组件

  • 使用场景

    A是父组件,B是子组件,B需要给A传递数据,那么就要在A中给B绑定自定义事件(事件回调在A中)

  • 使用

    • 绑定自定义事件

      方法一:在父组件中:<Demo @demo="test" /><Demo v-on:demo="test" />

      方法二:在父组件中:

      <template>
      	<Demo ref="demo">
      </template>
      <script>
      	export default {
              mounted(){
                  this.$refs.xxx.$on('demo',this.test)
              }
          }
      </script>
      

    若想让自定义事件只能触发一次,可以使用修饰符once或方法$once

    • 触发自定义事件

      this.$emit('demo','数据')

    • 解绑自定义事件

      this.$off('demo')

  • 组件上也可以绑定元素DOM事件,需要使用修饰符native

  • 注意

    通过this.$refs.xxx.$on('demo',callback(){})绑定自定义事件时,回调函数要么配置methods中,要么使用箭头函数,否则this指向会出现问题

全局事件总线(GlobalEventBus)

  • 一种组件间通信的方式,适用于任意组件间通信

  • 安装全局事件总线

    new Vue({
    	……
        beforeCreate(){
        	Vue.prototype.$bus = this // 安装全局事件总线,$bus就是当前应用的vm
    	}
        ……
    })
    
  • 使用

    1. 接收数据:A组件想接收数据,则A组件中给$bus绑定自定义事件,事件的回调留在A组件自身

      <script>
      	methods(){
              demo(data){
                  ……
              }
          },
          ……
          mounted(){
              this.$bus.$on('xxx',this.demo)
          }
      </script>
      
    2. 提供数据:

      this.$bus.$emit('xxx',数据)

  • 注意

    最好在beforeDestory(){}钩子中,用$off却解绑当前组件所用到的事件

消息订阅与发布

  • 一种组件间通信的方式,适用于任意组件间通信

  • 使用步骤

    1. 安装pubsub:

      npm i pubsub-js
      
    2. 引入pubsub:

      import pubsub from 'pubsub-js'
      
    3. 接受数据:A组件需要接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身

      <script>
      	methods(){
              demo(data)P{
                  ……
              }
          },
          ……
          mounted(){
              this.pId = pubsub.subscribe('xxx',this.demo) // 订阅消息
          }
      </script>
      
    4. 提供数据:

      pubsub。publish('xxx',数据)

    5. 取消订阅:

      使用beforeDestroy钩子取消订阅,用pubsub.unsubscribe(pId)取消订阅

  • 注意

nextTick

  • 场景:

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

  • 语法:

    this.$nextTick(callback)

  • 作用:

    在下一次DOM更新结束后执行器指定的回调

封装的过渡与动画

  • 作用

    在插入、更新或移除DOM元素时,在适合的时候给元素添加样式类名

  • 图示

    在这里插入图片描述

  • 用法

    1. 准备好样式

      • 元素进入的样式

        v-enter: 进入的起点

        v-enter-active: 进入的过程中

        v-enter-to: 进入的终点

      • 元素离开的样式

        v-leave: 离开的起点

        v-leave-active: 离开的过程中

        v-leave-to: 离开的终点

    2. 使用<transition>包裹需要过渡的元素,并配置name属性

      <transition name="hello">
          <h1 v-show="isShow">你好啊!</h1>
      </transition>
      

      备注:如果有多个元素需要过度,则需要使用<transition-group>,且每个元素都要指定key

Vue-Ajax

配置代理

  • 方法一

    vue.config.js中添加如下配置:

    devServer:{
    	proxy:"http://localhost:5000"
    }
    
    1. 优点:配置简单,请求资源时直接发给前端(8080)即可
    2. 缺点:不能配置多个代理,不能灵活地控制请求是否走代理
    3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(优先配置前端资源)
  • 方法二

    编写vue.config.js配置具体代理规则:

    module.export = {
    	devServer: {
            proxy: {
                '/api1': {  //匹配所有以'/api1'为开头的请求路径
                    target: 'http://localhost:5000', //代理目标的基础路径
                    pathRewrite: { '^api1': '' },
                    ws: true, //用于支持websocket
                    changeOrigin: true //用于控制请求头中的host值
                },
                '/demo': {  //匹配所有以'/api2'为开头的请求路径
                    target: 'http://localhost:5001', //代理目标的基础路径
                    pathRewrite: { '^/demo': '' },
                    ws: true, //用于支持websocket
                    changeOrigin: true //用于控制请求头中的host值
                },
    }
    /*
    	changeOrigin设置为true时,服务器收到地请求头中的host为:'localhost:5000'
    	changeOrigin设置为false时,服务器收到地请求头中的host为:'localhost:8080'
    	changeOrigin默认值为true
    */
    
    1. 优点:可以配置多个代理,且可以灵活地控制请求是否走代理
    2. 缺点:配置略微繁琐,请求资源时必须加前缀

axios

vue_resource

插槽

  • 作用

    让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方法,适用于父组件===>子组件

  • 分类

    默认插槽、具名插槽、作用域插槽

  • 使用方式

    • 默认插槽

      <!-- 父组件中 -->
      <Category>
          <div>html结构1</div>
      </Category>
      
      <!-- 子组件中 -->
      <template>
      	<div>
          	<!-- 定义一个插槽 -->
          	<slot>插槽默认内容</slot>
          </div>
      </template>
      
    • 具名插槽

      <!-- 父组件中 -->
      <Category>
          <template slot="center">
          	<div>html结构1</div>
      	</template>
          <template v-slot:footer>
          	<div>html结构2</div>
      	</template>
      </Category>
      
      <!-- 子组件中 -->
      <template>
      	<div>
          	<!-- 定义一个插槽 -->
          	<slot name="center">插槽默认内容</slot>
              <slot name="footer">插槽默认内容</slot>
          </div>
      </template>
      
    • 作用域插槽

      <!-- 父组件中 -->
      <Category>
          <template slot-scope="scopeData">
      		<!-- 生成的是ul列表 -->
          	<ul>
                  <li v-for="g in scopeData.games" :key="g">{{g}}</li>
              </ul>
      	</template>
          <template v-slot:footer>
          	<!-- 生成的是h4标题 -->
      		<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
      	</template>
      </Category>
      
      <!-- 子组件中 -->
      <template>
      	<div>
          	<!-- 定义一个插槽 -->
          	<slot :games="games">插槽默认内容</slot>
          </div>
      </template>
      <script>
      	export default{
              name:'Category',
              props:['title'],
              data(){
                  return{
                      games:['lol',]
                  }
              }
          }
      </script>
      

      理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。

      例:games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定

Vuex

vuex

  • 概念

    在Vue中实现集中式状态/数据管理的一个Vue插件,在vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信

  • 何时用

    1. 多个组件依赖于同一状态
    2. 来自不同组件的行为需要变更同一状态
  • 原理图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXH7hDRo-1670124487779)(F:\前端\Vue\资料(含课件)\02_原理图\vuex.png)]

  • 搭建vuex环境

    1. 下载安装

      npm i vuex
      
    2. 创建文件src/store/index.js

      // 该文件用于创建vuex中的store
      
      // 引入Vue
      import Vue from 'vue'
      // 引入Vuex
      import Vuex from 'vuex'
      // 使用Vuex插件
      Vue.use(Vuex)
      
      // 准备actions--用于响应组件的动作
      const actions = {};
      // 准备mutations--用于操作数据(state)
      const mutations = {};
      // 准备state--用于存储数据
      const state = {};
      // 准备getters--用于将state中的数据进行加工
      // 当state中的数据需要经过加工后再使用时,可以使用getters加工。
      const getters = {};
      
      
      // 创建并暴露store
      export default new Vuex.Store({
          actions,
          mutations,
          state,
          getters
      })
      
    3. main.js中创建vm时传入store配置项

      ……
      // 引入store
      import store from './store'
      ……
      
      // 创建vm
      new Vue({
          el:'#app',
          render: h => h(App),
          store,
      }).$mount('#app')
      
  • 基本使用

    1. 配置部分store.js文件:初始化数据statue、配置actionsmutations、追加getters配置

      const actions = {
          increment(context, value) {
              context.commit('INCREMENT', value)
          }
      };
      const mutations = {
          INCREMENT(state, value) {
              state.sum += value
          },
      };
      const state = {
          sum:0
      };
      const getters = {
          bigSum(state){
              return state.sum *10
          }
      };
      
    2. 组件中读取vuex中的数据:

      $store.state.sum$store.getters.bigSum

    3. 组件中修改vuex中的数据:

      $store.dispatch('action中的方法名','数据')

      $store.commit('mutations中的方法名','数据')

    备注:若没有网络请求,组件中可以越过actions,即不写dispatch,直接编写commit

  • 四个map方法的使用

    1. mapState方法:帮助映射state中的数据为计算属性

      <script>
          computed:{
              /*借助mapState生成计算属性,从state中读取数据(对象写法)*/
              ...mapState({
      			sum: 'sum',
      			school: 'school',
      			subject: 'subject'
      		}),
      
      		/*借助mapState生成计算属性,从state中读取数据(数组写法)*/
      		...mapState(['sum', 'school', 'subject']),
          }
      </script>
      
    2. mapGetters方法:帮助映射getters中的数据为计算属性

      <script>
          computed:{
              /*借助mapGetters生成计算属性,从getters中读取数据(对象写法)*/
              ...mapGetters({
      			bigSum: 'bigSum',
      		}),
      
      		/*借助mapGetters生成计算属性,从getters中读取数据(数组写法)*/
      		...mapGetters(['bigSum']),
          }
      </script>
      
    3. mapActions方法:帮助生成与actions对话的方法,即包括$store.dispatch(xxx)的函数

      <script>
          methods:{
              // 借助mapActions生成对应的方法,方法会调用dispatch去联系actions(对象写法)
              ...mapActions({
                  incrementOdd: 'incrementOdd',
                  incrementWait: 'incrementWait'
              }),
                  
              // 借助mapActions生成对应的方法,方法会调用dispatch去联系actions(数组写法)
              ...mapActions([
                  'incrementOdd',
                  'incrementWait'
              ]),
          }
      </script>
      
    4. mapMutations方法:帮助生成与mutations对话的方法,即包括$store.commit(xxx)的函数

      <script>
          methods:{
              // 借助mapMutations生成对应的方法,方法会调用commit去联系mutations(对象写法)
              ...mapMutations({
                  increment: 'INCREMENT',
                  decrement: 'DECREMENT'
              }),
                  
              // 借助mapMutations生成对应的方法,方法会调用commit去联系mutations(对象写法)
              ...mapMutations([
                  'INCREMENT',
                  'DECREMENT'
              ]),
          }
      </script>
      

      备注:mapActions与mapMutations使用时,若需要传递参数需要:模板中绑定事件时传递好参数,否则参数是事件对象。

模块化

  • 目的:

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

  • 使用:

    1. 修改store.js

      const countAbout = {
          namespaced: true, // 开启命名空间
          state: {},
          actions: {},
          mutations: {},
          getters:{},
      }
      
      const personAbout = {
          namespaced: true, // 开启命名空间
          state: {},
          actions: {},
          mutations: {},
          getters:{},
      }
      
      const store = new Vuex.Store({
          modules: {
              countAbout,
              personAbout
          }
      })
      
    2. 开启命名空间后,组件中读取state数据

      <script>
          computed:{
              // 方式一:自己直接读取
              this.$store.state.personAbout.list
              // 方式二:借助mapState读取
              ...mapState('countAbout',['sum','school','subject']),
          } 
      </script>
      
    3. 开启命名空间后,组件中读取getters数据

      <script>
          computed:{
              // 方式一:自己直接读取
              this.$store.getters['personAbout/firstPersonName']
              // 方式二:借助mapState读取
              ...mapGetters('countAbout',['bigSum']),
          } 
      </script>
      
    4. 开启命名空间后,组件中调用dispatch

      <script>
          methods:{
              // 方式一:自己直接读取
              this.$store.dispatch['personAbout/addPersonWang',person]
              // 方式二:借助mapState读取
              ...mapActions('countAbout',['incrementOdd','incrementWait']),
          } 
      </script>
      
    5. 开启命名空间后,组件中调用commit

      <script>
          methods:{
              // 方式一:自己直接读取
              this.$store.commit['personAbout/ADD_PERSON',person]
              // 方式二:借助mapState读取
              ...mapMoutations('countAbout',['INCREMENT','DECREMENT']),
          } 
      </script>
      

Vue-router

路由

  • 基本概念

    一个路由就是一组映射关系(key-value),key是路径,value可能是function或component

  • 分类

    1. 后端路由

      value是function,用于处理客户端请求的路由

      工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。

    2. 前端路由

      value是component,用于展示页面内容的路由

      工作过程:当浏览器的路径改变时,对应的组件就会显示。

  • vue-router是vue的一个插件库,专门实现SPA应用

  • SPA应用(单页面Web应用),整个应用只有一个完整的页面(点击页面中的导航链接不会刷新页面,只会做页面的局部更新),数据需要通过ajax请求获取

基本使用

  • 安装

    npm i vue-router@3
    

    vue2需要采用vue-router3版本

  • 应用

    // 引入VueRouter
    import VueRouter from 'vue-router'
    // 引入路由器
    import router from './router/index'
    Vue.use(VueRouter)
    

    在main.js中编写

  • 配置

    // 该文件专门用于创建整个应用的路由器
    import VueRouter from 'vue-router'
    // 引入组件
    import About from '../components/About.vue'
    import Home from '../components/Home.vue'
    
    // 创建并暴露一个路由器
    export default new VueRouter({
        routes: [{
                path: '/about',
                component: About
            },
            {
                path: '/home',
                component: Home
            }
        ]
    })
    
  • 实现切换

    <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
    

    active-class可配置高亮样式

  • 指定展示位置

    <router-view></router-view>
    
  • 几个注意点

    1. 路由组件通常放在pages文件夹下,一般组件通常存放在components文件夹下。
    2. 通过切换路由,“隐藏”了的路由组件,默认是被销毁的,需要的时候再去挂载。
    3. 每个组件都有自己的$route属性,内部存储着自己的路由信息。
    4. 整个应用只有一个router,可有通过组件的$router属性获取到。

嵌套路由(多级路由)

  • 配置路由规则

    routes: [{
            path: '/about',
            component: About
        },
        {
            path: '/home',
            component: Home,
            children: [{
                    path: 'news',  // 此处一定不要写'/news'
                    component: News,
                },
                {
                    path: 'message', // 此处一定不要写'/message'
                    component: Message,
                }
            ]
        }
    ]
    

    /router/index.js下配置

    使用children进行配置

  • 跳转

    <router-link to="/home/news">News</router-link>
    

    要写完整路径

路由传参

query参数
  • 传递query参数

    <!-- 跳转路由并携带query参数,to的字符串写法 -->
    <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>
    
    <!-- 跳转路由并携带query参数,to的对象写法 -->
    <router-link :to="{
    	path:'/home/message/detail',
    	query:{id:m.id,title:m.title}}
    	">{{m.title}}</router-link>  
    
  • 接受query参数

    $route.query.id
    $route.query.title
    
params参数
  • 配置路由,声明params参数

    {
        path: '/home',
        component: Home,
        children: [{
                path: 'news',
                component: News,
            },
            {
                path: 'message',
                component: Message,
                children: [{
                    name: 'xiangqing',
                    path: 'detail/:id/:title', // 使用占位符声明接收params参数
                    component: Detail,
                }]
            }
        ]
    }
    
  • 传递参数

    <!-- 跳转路由并携带params参数,to的字符串写法 -->
    <router-link :to="`/home/message/detail/${m.id}&${m.title}`">{{m.title}}</router-link>
    <!-- 跳转路由并携带params参数,to的对象写法 -->
    <router-link :to="{
        name:'xiangqing',
        params:{
                 id:m.id,
                 title:m.title}}
        ">{{m.title}}</router-link>
    

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

  • 接收参数

    $route.params.id
    $route.params.title
    

接收参数

props配置
  • 配置路由,声明props

    {
        name: 'xiangqing',
        path: 'detail/:id/:title',
        component: Detail,
        // 第一种写法,值为对象,该对象中的所有key-value都以props形式传入Detail组件
        // props: { money: 'the money'}
        // 第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props形式传给Detail组件
        // props: true
        // 第三种写法,值为函数
        props($route) {
            return { id: $route.query.id, title: $route.query.title }
        }
    }
    
  • 接收参数

    props:['id','title']
    

命名路由

  • 作用

    简化路由的跳转

  • 使用

    1. 给路由命名

      {
      	path:'/demo',
           component:Demo
           children:[
               {
                   path:'test',
                   component:Test,
                   children:[
                       {
                           name:'hello' // 给路由命名
                           path:'welcome',
                           component:Hello,
                       }
                   ]
               }
           ]
      }
      
    2. 简化跳转

      <!-- 简化前,需要写完整的路径 -->
      <route-link to="/demo/test/welcome">跳转</route-link>
      
      <!-- 简化后,直接通过名字跳转 -->
      <route-link :to="{name:'hello'}">跳转</route-link>
      
      <!-- 简化写法配合传递参数 -->
      <route-link :to="{
                       name:'hello',
                       query:{
                       	id:666,
                       	title:'你好'
                       }}"
      >跳转</route-link>
      

<router-link>replace属性

  • 作用

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

  • 写入方式

    • push是追加历史记录,类似于压栈

    • replace是替换当前记录

      路由跳转时候默认为replace

  • 开启replace模式

    <router-link replace>Home</router-link>
    <router-link :replace="true">Home</router-link>
    

编程式路由导航

  • 作用

    不借助<router-link>实现路由跳转,让路由跳转更灵活

  • 语法

    <script>
        // $router的两个API
    
        this.$router.push({
            name: 'xiangqing',
            query: {
                id: m.id,
                title: m.title
            }
        })
        this.$router.replace({
            name: 'xiangqing',
            query: {
                id: m.id,
                title: m.title
            }
        })
        this.$router.back() // 前进
        this.$router.forward() // 后退
        this.$router.go() // 可前进可后退
    </script>
    

缓存路由组件

  • 作用

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

  • 语法

    <!-- 缓存一个路由组件 -->
    <keep-alive include="News">
    	<router-view></router-view>
    </keep-alive>
    <!-- 缓存多个路由组件 -->
    <keep-alive include="['News','Message']">
    	<router-view></router-view>
    </keep-alive>
    

生命周期钩子

  • 作用

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

  • 具体实现

    • activated–路由组件被激活时触发
    • deactivated–路由组件失活时触发

路由守卫

  • 作用

    对路由进行权限控制

  • 分类

    全局守卫、独享守卫、组件内守卫

  • 全局路由守卫

    <Script>
        // 全局前置路由守卫————初始化时候被调用、每次路由切换之前被调用
        router.beforeEach((to, from, next) => {
            console.log('前置路由守卫', to, from);
            if (to.meta.isAuth) { // 判断是否需要鉴权
                if (localStorage.getItem('school') === 'atguigu') {  // 权限控制的具体规则
                    next() // 放行
                } else {
                    alert('暂无权查看!')
                }
            } else {
                next() // 放行
            }
        });
        // 全局后置路由守卫————初始化时候被调用、每次路由切换之后被调用
        router.afterEach((to, from) => {
            console.log('后置路由守卫', to, from);
            document.title = to.meta.title || "vue系统"  // 修改网页title
        })
    </Script>
    
  • 独享路由后卫

    <script>
        beforeEnter: (to, from, next) => {
            console.log('前置路由守卫', to, from);
            if (to.meta.isAuth) { // 判断是否需要鉴权
                if (localStorage.getItem('school') === 'atguigu') {
                    next()
                } else {
                    alert('学校名不对,无权查看!')
                }
            } else {
                next()
            }
        }
    </script>
    
  • 组件内路由守卫

    <script>
        // 进入组件路由守卫,通过路由规则,进入该组件时被调用
        beforeRouteEnter(to, from, next) {
            
        }
        // 离开组件路由守卫,通过路由规则,离开该组件时被调用
        beforeRouteLeave(to, from, next) {
            
        }
    </script>
    

路由器的两种工作模式

  • hash值

    对于一个URL来说,hash值是指#及其后面的内容是hash值

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

  • hash模式

    1. 地址中永远带着#,不美观
    2. 若后期将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
    3. 兼容性较好
  • history模式

    1. 地址干净,美观
    2. 兼容性和hash模式相比略差
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务器404问题

UI组件库

移动端UI组件库
PC端UI组件库

扩展

  • Object.defineProperty()方法

  • 关于不同版本的Vue

    • vue.js与vue.runtime.xxx.js区别

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

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

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

  • 关于vue.config.js配置文件

    • 使用vue inspect > output.js可以查看Vue脚手架的默认配置
    • 编写vue config.js文件可以对脚手架进行个性化定制,详情参考:Vue CLI 配置参考
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值