vue基础
v-bind : 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)
虚拟DOM和Diff算法复用DOM
DOM是浏览器把 HTML 页面解析成的对象结构。
如果用原生js操作dom
浏览器会:
- 删除原 DOM
- 重新创建 DOM
- 重新渲染页面
操作 非常慢,因为涉及重新计算布局和重新绘制页面,所以频繁更新 DOM 性能很差。
然后就有了虚拟dom
用 JavaScript 对象来描述真实 DOM
Diff 算法就是:
比较两个虚拟 DOM 的差异
DOM复用意思是:
数据没变的DOM节点继续使用,不重新创建
Vue Diff 时会用 key
1
| <li v-for="item in list" :key="item.id">
|
MVVM
MVVM 是 Vue 的核心架构模式,其中:
- Model 表示数据模型(data)
- View 表示视图(HTML页面)
- ViewModel 表示视图模型(Vue实例)
ViewModel 作为 View 和 Model 的桥梁,实现:
当数据发生变化时,ViewModel 会自动更新视图;当用户操作视图时,数据也会同步更新,从而实现视图与数据的自动同步。
版本
目前主流是vue2和3
核心区别
响应式原理不同
Vue2 使用 Object.defineProperty 来监听数据变化,而 Vue3 使用 Proxy。
Proxy 功能更强,可以监听对象新增属性和数组变化,因此 Vue3 的数据响应更完善。
API 写法不同
Vue2 主要使用 Options API(如 data、methods、computed 等)。
Vue3 新增了 Composition API(如 setup、ref、reactive),代码结构更加灵活,更适合大型项目开发。
开发环境
使用火狐导入插件

英文官网: https://vuejs.org/
中文官网: https://cn.vuejs.org/
Introduction — Vue.js

引入

简单例子

比如这个
两部分把容器和实例建立连接 但此时这个是写死的
如果我们想方便的更改 引入data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <!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> </head> <body> <!-- 准备好一个 Vue 要控制的容器区域 --> <div id="app"> <h1>Hello World</h1> <!-- 将数据放入页面中使用插值表达式即‘{{ 对应数据的key }}’ --> <h1>Hello {{ name }}</h1> </div> <!-- 引入下载的 vue --> <script src="./js/vue.js"></script> <!-- 使用CDN引入 --> <!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> --> <script> // 设置为 false 以阻止 vue 在启动时生成生产提示。 Vue.config.productionTip = false
// 创建一个 Vue 实例对象 // Vue 构造函数中传入的参数为配置对象 const app = new Vue( { // element -- el Vue实例对象要控制的容器 // el 的值为 css 选择器( id 选择器 / 类选择器 ) // 填入 js 的选择标签对象的方法也行 // el: document.getElementById('app') // 一般写 css 选择器, 简单 el: '#app', // data 用于存放页面的数据 // data 中的数据供 el 所指向的容器使用 // data 的值先写为对象(后面会写为函数, 后面会介绍) data: { // 数据为键值对 name: '张三' } } ) </script> </body> </html>
|

Vue实例和容器是一 一对应的


1. Object.defineProperty()方法
该方法用于给对象添加属性
需要传入三个参数:
- 需要进行属性添加的对象 2. 将要添加到对象的新属性名 3. 配置对象,在配置对象中可以指定新属性的值
使用Object.defineProperty()向对象中添加属性
1 2 3 4 5 6 7 8 9 10 11 12
| <script> let person = { name: 'zs', sex: 'male' } // 向person对象中新添加一个age属性 Object.defineProperty(person, 'age', { value: 18 }) console.log(person) </script>
|
默认情况下,使用Object.defineProperty()添加的属性的值是不可以修改的。
要使Object.defineProperty()添加的属性值可以修改,在添加属性时,配置对象的 writable 的值设置为 true,使用Object.defineProperty()添加的属性值可以修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script> let person = { name: 'zs', sex: 'male' } // 向person对象中新添加一个age属性 Object.defineProperty(person, 'age', { value: 18, // enumerable 控制属性是否可以枚举,默认值为 false enumerable: true, // 控制属性值是否可以被修改,默认值为 false writable: true })
</script>
|
默认情况下,使用Object.defineProperty()添加的属性的值是不可以删除的。
要使Object.defineProperty()添加的属性值可以删除,在添加属性时,配置对象的 configurable 的值设置为 true,使用Object.defineProperty()添加的属性值可以删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script> let person = { name: 'zs', sex: 'male' } // 向person对象中新添加一个age属性 Object.defineProperty(person, 'age', { value: 18, // enumerable 控制属性是否可以枚举,默认值为 false enumerable: true, // 控制属性值是否可以被修改,默认值为 false writable: true, // 控制属性是否可以被删除,默认值为 false configurable: true })
</script>
|
向对象中新添加的属性赋值为另外定义的变量,当变量的值发生改变时,对象中的新属性值也会对应的发生变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <script> let number = 18 let person = { name: 'zs', sex: 'male' } // 向person对象中新添加一个age属性 Object.defineProperty(person, 'age', { // value: 18, // // enumerable 控制属性是否可以枚举,默认值为 false // enumerable: true, // // 控制属性值是否可以被修改,默认值为 false // writable: true, // // 控制属性是否可以被删除,默认值为 false // configurable: true
// 当读取person的age属性的时候,get函数(getter)会被调用,且返回值就是age的值 // get: function() { // console.log('读取age属性') // return number // } // 简写 get() { console.log('读取age属性') return number },
// 修改person的age属性的时候,set函数(setter)会被调用,且会收到修改的具体值 set(value) { console.log('修改了age的属性值:', value) } }) </script>
|
Vue 2 的数据代理机制
Vue 2 核心就是 响应式系统,实现方式是:
- Vue 初始化时,会遍历
data 对象的每个属性。
- 对每个属性使用
Object.defineProperty() 定义 getter 和 setter。
- getter 用来依赖收集(知道哪些模板用到了这个属性)。
- setter 用来派发更新(属性变化时自动刷新 DOM)。
事件
vue 提供了v-on:事件绑定指令,用来辅助程序员为DOM元素绑定事件监听。
原生的DOM对象有onclick、oninput等原生事件,在vue中可以使用v-on:click、v-on:input等来监听DOM元素的对应事件,并为其绑定相应的事件处理函数,其中事件处理函数需要在vue实例对象的methods节点中进行声明。
v-on: 简写为 @。
基本的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <!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> </head> <body> <div id="root"> <h1>Hello {{name}}!</h1> <!-- 监听按钮的点击事件,同时为其绑定事件处理函数 show1 --> <button v-on:click="show1">提示信息1</button> <!-- 监听按钮的点击事件,同时为其绑定事件处理函数 show1 --> <button @click="show2">提示信息2</button> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> const vm = new Vue({ el: '#root', data: { name: 'zs' }, methods: { show1() { alert('你好!') }, show2() { alert('你好!!') }, }, }) </script> </body> </html>
|
计算属性
插值语法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <!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> </head> <body> <!-- 准备容器 --> <div id="root"> 姓:<input type="text" v-model="firstName"> <br><br> 名:<input type="text" v-model="lastName"> <br><br> 姓名:<span>{{firstName}}-{{lastName}}</span> </div> <!-- 引入vue --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> new Vue({ el: '#root', data: { firstName: '张', lastName:'三' } }) </script> </body> </html>
|
计算属性实现
计算属性,即使用原有的data 中的属性进行处理,处理后生成新的属性。
在vue 中,计算属性写在配置项computed中,配置项 computed需要书写成对象形式。
如果要使用计算属性,那么需要在计算属性中实现get()方法
多次使用计算属性,计算属性只会计算一次,因为计算属性会将计算的结果进行缓存。(前提计算属性所依赖的数据不发生变化,依赖的数据变化计算属性会重新进行计算)
相对于methods,计算属性的效率更高,因为methods不存在缓存,所以每次调用方法,方法都会重新执行一次,而计算属性只要依赖的数据不发生变化,计算属性的计算过程只有在第一次读取时执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <!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> </head> <body> <!-- 准备容器 --> <div id="root"> 姓:<input type="text" v-model="firstName"> <br><br> 名:<input type="text" v-model="lastName"> <br><br> 姓名:<span>{{ fullName }}</span> </div> <!-- 引入vue --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> const vm = new Vue({ el: '#root', data: { firstName: '张', lastName:'三' }, computed: { // 由于计算属性的处理可能很复杂,所以写成对象的形式 fullName: { // 当计算属性被读取时,get函数会被调用,且返回值作为计算属性的值 get() { console.log('get被调用') return this.firstName + '-' + this.lastName } } } }) </script> </body> </html>
|
监视属性
handler()为属性侦听器的回调函数,当被监视的属性值变化时,回调函数会自动调用,进行相应的处理
1 2 3 4 5 6 7 8 9
| watch: { isHot: { // 当被监视的属性值变化时,回调函数会自动调用,进行相应的处理 handler() { console.log('isHot被修改了') } } }
|
当被监视的属性值变化时,回调函数会自动调用,进行相应的处理,同时会向处理函数传入两个参数,第一个参数为改变后的值,第二个参数修改之前的值。
immediate 默认值为false
immediate的值设置为true,初始化数据元素时,立即调用属性侦听器的回调函数handler()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <!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> </head> <body> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="isHot = !isHot">切换天气</button> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> const vm = new Vue({ el: '#root', data: { // 标记天气是否炎热 isHot: true }, computed: { info() { return this.isHot ? '炎热' : '凉爽' } } })
// 使用vue实例监视属性必须保证vue实例已经创建完成 // 调用$watch()方法实现 // 第一个参数为需要进行监视的属性名 // 第二个参数为对应的配置项 vm.$watch('isHot', { // 初始化时,立即调用handler() immediate: true, // 当被监视的属性值变化时,回调函数会自动调用,进行相应的处理 handler(newVal, oldVal) { console.log('isHot被修改了', '新的值为:', newVal, '旧的值为:', oldVal) } }) </script> </html>
|
深度监视
实现深度监视使用deep,默认值为false。vue提供的属性侦听器默认不能监视多级结构中某个属性的变化。
开启深度监视,能够监视多级结构中某个属性的变化。
vue自身可以监测对象内部值的改变,即vue能够监视多级结构中某个属性的变化,但是vue提供的watch默认不可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <!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> </head> <body> <div id="root"> <h2>a的值:{{num.a}}</h2> <button @click="num.a++">点击使a加一</button> <h2>b的值:{{num.b}}</h2> <button @click="num.b++">点击使b加一</button> <br><br> <button @click="num = {a: 666, b: 888}">点击修改num的值</button> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> const vm = new Vue({ el: '#root', data: { isHot: true, num: { a: 1, b: 2 } }, watch: { // 监视num,当num里面的值修改了也视为num改变 num: { deep: true, handler(newVal, oldVal) { console.log('num被修改了') } } } }) </script> </html>
|
computed和watch之间的区别:
computed能完成的功能,watch都可以完成
watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个重要的小原则:
所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vue实例对象或 组件实例对象
所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vue实例对象或 组件实例对象。
Vue监视数据的原理
vue会监视data中所有层次的数据。
如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
3.对于不会修改原数组的方法,如:filter()、concat() 和 slice(),它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组
特别注意:Vue.set() 和 vm.$set() 不能给 vm 或 vm的根数据对象 添加属性 ! ! !
收集表单数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>收集表单数据</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <!-- 阻止表的的默认事件 --> <form @submit.prevent="demo"> <!-- v-model.trim 去除用户输入的两端的空白字符 --> 账号:<input type="text" v-model.trim="userInfo.account" /> <br /><br /> 密码:<input type="password" v-model="userInfo.password" /> <br /><br /> <!-- type="number" 只允许输入数字, v-model.number 将输入的内容的数据类型转为数字类型 --> 年龄:<input type="number" v-model.number="userInfo.age" /> <br /><br /> 性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="male" /> 女<input type="radio" name="sex" v-model="userInfo.sex" value="female" /> <br /><br /> 爱好: 学习<input type="checkbox" v-model="userInfo.hobby" value="study" /> 打游戏<input type="checkbox" v-model="userInfo.hobby" value="game" /> 吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat" /> <br /><br /> 所属校区 <select v-model="userInfo.city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="wuhan">武汉</option> </select> <br /><br /> 其他信息: <!-- v-model.lazy 在失去焦点时才进行数据的更新 --> <textarea v-model.lazy="userInfo.other"></textarea> <br /><br /> <input type="checkbox" v-model="userInfo.agree" />阅读并接受<a href="http://www.atguigu.com">《用户协议》</a> <button>提交</button> </form> </div> </body>
<script type="text/javascript"> Vue.config.productionTip = false
new Vue({ el: '#root', data: { // 将用户信息写成对象形式 userInfo: { account: '', password: '', age: 18, sex: 'female', hobby: [], city: 'beijing', other: '', agree: '', }, }, methods: { demo() { // 显示用户信息 console.log(JSON.stringify(this.userInfo)) }, }, }) </script> </html>
|
若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器
在 filters 节点中定义过滤器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <!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> </head> <body> <div id="root"> <h1>时间戳转换</h1> <h2>当前时间的时间戳:{{time}}</h2> <!-- 通过管道符调用过滤器 --> <h2>当前时间:{{time | getDateTime}}</h2> </div> </body> <!-- 导入day.js --> <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script> <!-- 导入vue.js --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> const vm = new Vue({ el: '#root', data: { // 当前时间的时间戳 time: Date.now() }, filters: { // 将时间戳转换指定格式的时间 getDateTime() { return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss'); } } }) </script> </html>
|
定义全局过滤器
Vue.filter(‘过滤器名’, 对应的处理函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <!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> </head> <body> <div id="root"> <h1>时间戳转换</h1> <h2>当前时间的时间戳:{{time}}</h2> <!-- mySlice为全局过滤器 --> <h2>当前时间:{{time | getDateTime('YYYY/MM/DD') | mySlice}}</h2> </div>
<div id="root2"> <h1>时间戳转换</h1> <h2>当前时间:{{time}}</h2> <!-- mySlice为全局过滤器 --> <h2>当前时间:{{time | mySlice}}</h2> </div> </body> <!-- 导入day.js --> <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script> <!-- 导入vue.js --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> // 定义全局过滤器 Vue.filter('mySlice', function(value) { return value.slice(0, 4) })
const vm = new Vue({ el: '#root', data: { time: Date.now() }, filters: { // 局部过滤器 // 属于vm getDateTime(value, formatStr='YYYY-MM-DD HH:mm:ss') { return dayjs(value).format(formatStr); } } })
const vm2 = new Vue({ el: '#root2', data: { time: '2022/10/10' } }) </script> </html>
|
在v-bind中使用过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <!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> </head> <body> <div id="root"> <h1>时间戳转换</h1> <h2>当前时间的时间戳:{{time}}</h2> <h2>当前时间:{{time | getDateTime('YYYY/MM/DD') | mySlice}}</h2> <p :x="time | getDateTime('YYYY/MM/DD') | mySlice"></p> </div> </body> <!-- 导入day.js --> <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script> <!-- 导入vue.js --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> // 定义全局过滤器 Vue.filter('mySlice', function(value) { return value.slice(0, 4) })
const vm = new Vue({ el: '#root', data: { time: Date.now() }, filters: { // 局部过滤器 // 属于vm getDateTime(value, formatStr='YYYY-MM-DD HH:mm:ss') { return dayjs(value).format(formatStr); } } }) </script> </html>
|
生命周期
生命周期,又名:生命周期回调函数 、生命周期函数、生命周期钩子。生命周期是Vue在关键时刻帮我们调用的一些特殊名称的函数。生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。生命周期函数中的this指向是vm 或 组件实例对象。
生命周期函数的书写位置与data、methods同级
1. 初始化阶段
此阶段 Vue 实例开始创建,但模板尚未解析,页面显示原始 HTML 结构。

2. 模板编译阶段
此阶段涉及 DOM 的编译和挂载过程,区分了 outerHTML 与 innerHTML 的解析策略。

3. 数据更新阶段
响应式数据发生变化时触发更新流程,实现界面与数据的同步。

4. 实例销毁阶段
通过调用 vm.$destroy() 手动触发实例销毁流程。

脚手架
https://cli.vuejs.org/

ref属性
使用 ref 属性标记 html 标签元素
ref 属性应用在 html 标签元素上,获取的是对应的真实 DOM 元素
使用 ref 属性标记子组件
ref 属性应用在组件标签上,获取的是对应组件实例对象
mixin(混入)
功能:可以把多个组件共用的配置提取成一个混入对象
使用方式:
第一步定义混合:
1 2 3 4 5
| { data(){....}, methods:{....} .... }
|
第二步使用混入:
全局混入:Vue.mixin(xxx)
插件
功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
定义插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 对象.install = function (Vue, options) { Vue.filter(....)
Vue.directive(....)
Vue.mixin(....)
Vue.prototype.$myMethod = function () {...} Vue.prototype.$myProperty = xxxx }
|
使用插件:Vue.use()
组件的自定义事件
一种组件间通信的方式,适用于:子组件 ===> 父组件
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
绑定自定义事件:
第一种方式,在父组件中:<Demo @atguigu="test"/> 或 <Demo v-on:atguigu="test"/>
第二种方式,在父组件中:
1 2 3 4 5
| <Demo ref="demo"/> ...... mounted(){ this.$refs.xxx.$on('atguigu',this.test) }
|
若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
触发自定义事件:this.$emit('atguigu',数据)
解绑自定义事件this.$off('atguigu')
组件上也可以绑定原生DOM事件,需要使用native修饰符。
注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
vue脚手架配置代理
3.1 方法一
在vue.config.js中添加如下配置:
1 2 3
| devServer:{ proxy:"http://localhost:5000" }
|
优点:配置简单,请求资源时直接发给前端(8080)即可。
缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
3.2 方法二
编写vue.config.js配置具体代理规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| module.exports = { devServer: { proxy: { '/api1': {// 匹配所有以 '/api1'开头的请求路径 target: 'http://localhost:5000',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api1': ''} }, '/api2': {// 匹配所有以 '/api2'开头的请求路径 target: 'http://localhost:5001',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api2': ''} } } } } /* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080 changeOrigin默认值为true */
|
说明:
优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
缺点:配置略微繁琐,请求资源时必须加前缀。
路由
- 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
- 前端路由:key是路径,value是组件。
1.基本使用
安装vue-router,命令:npm i vue-router
应用插件:Vue.use(VueRouter)
编写router配置项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import VueRouter from 'vue-router'
import About from '../components/About' import Home from '../components/Home'
const router = new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home } ] })
export default router
|
实现切换(active-class可配置高亮样式)
1
| <router-link active-class="active" to="/about">About</router-link>
|
指定展示位置
1
| <router-view></router-view>
|
2.几个注意点
- 路由组件通常存放在
pages文件夹,一般组件通常存放在components文件夹。
- 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 每个组件都有自己的
$route属性,里面存储着自己的路由信息。
- 整个应用只有一个router,可以通过组件的
$router属性获取到。
路由器的两种工作模式
- 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
- hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观 。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。