一、Vue实例
Vue实例又称为Vue组件。
1.Vue2.0创建Vue组件的方法:
new Vue({...})
<!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 src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> </head> <body> <div id="app"> {{ msg }} </div> <script> new Vue({ el:'#app', data:{ msg:'西安' } }) </script> </body> </html>
2.Vue3.0创建Vue组件的方法:
Vue.createApp(...):创建Vue组件。
.mount(...):将vue组件挂载到页面的某个标签上。
方法一(推荐):
<!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 src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <div>{{ count }}</div> </div> <script> const obj = { data(){ return{ count:1 } } } Vue.createApp(obj).mount('#app') </script> </body> </html>
方法二(不推荐):
<!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 src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app">{{ count }}</div> <script> const obj = {} Vue.createApp({ data(){ return{ count:120 } } }).mount('#app') </script> </body> </html>
二、Vue组件的属性
1. 存储属性(data)
存储属性是一个函数。在组件创建时会调用此函数来构建响应性的数据系统。是组件的存储属性,专门用来存放数据。
获取该属性值的方式:
Vue组件名.变量名
Vue组件名.$data.变量名
本质是访问的同一个数据块。<!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 src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app">{{ count }}</div> <script> const obj = { data(){ return { count:120 } } } let instance = Vue.createApp(obj).mount('#app') //instance就是Vue组件 //获取存储属性data属性值的方式一: console.log(instance.count) //获取存储属性data属性值的方式二: console.log(instance.$data.count) </script> </body> </html>
2.计算属性(computed)
通常可以将存储属性的值直接渲染到html的元素上。但在有些场景下存储属性的值不适合直接渲染,需要处理之后再进行渲染。
计算属性指的是 通过一系列运算 之后,最终得到一个 属性值 。 这个动态计算出来的属性值 可以被 模板结构 或 methods 方法使用。注意:
- 计算属性应该定义为“方法”格式
- 计算属性可以当作“属性值”被使用
优点:
- 实现了代码的复用
- 只要计算属性中依赖的数据源变化了,则计算属性会自动更新求值
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <div>{{ type }}</div> <!--v-on绑定事件,若使用v-on绑定单个事件可以简写为@事件名 --> <button @click="add">Add</button> </div> <script> const obj = { data(){ return { count: 0 } }, //定义计算属性 computed:{ type(){ return this.count>10?"大":"小" } }, methods: { add(){ this.count++ } } } let instance = Vue.createApp(obj).mount("#app") console.log(instance.type) //获得初始值 </script>
注意:
- 存储属性(例如下例中的count)主要用于数据的存取,我们可以通过赋值运算来修改它的属性值。
- 通常,计算属性只用来取值,不会用来存值,因此计算属性默认提供的是取值方法(get方法);计算属性也可以通过赋值进行存数据,但是存数据的方法需要手动实现(set方法)
- 当使用计算属性时,默认调用get方法(该方法不能显式调用);当给计算属性赋值时,调用的是set方法(该方法不能显式调用)
<script src="https://unpkg.com/vue@next"></script> <div id="app"> <div>{{ type }}</div> <button @click="add">Add</button> </div> <script> const obj = { data(){ return { count: 0 } }, //定义计算属性 computed:{ type: { get(){ //实现计算属性的get方法,用来取值 return this.count>10?"大":"小" }, set(newVal){ //实现计算属性的set方法,用来设置的值 if(newVal == "大"){ this.count = 11 }else { this.count = 0 } } } }, methods: { add(){ this.count++ }, sub:function(prarms){ }, m1:(prarms)=>{ } } } let instance = Vue.createApp(obj).mount("#app") console.log("count="+instance.count) console.log("type="+instance.type) //人为赋值“大”后,count变为11 instance.type = "大" console.log("count="+instance.count) </script>
3.侦听属性(属性侦听器watch)
可以方便的监听某个属性的变化,以完成复杂的业务逻辑。在Vue中的属性侦听器是watch。
作用:watch是vue内部提供的一个用于侦听功能的更通用的方法,其用来响应数据的变化,通过特定的数据变化驱动一些操作。
vue官方文档解释当需要在数据变化时执行异步或开销较大的操作时,推荐使用该方法。
Vue侦听器是提供给开发者可以用来监测某些数据的变化,从而针对这些数据的变化进行某些操作。Vue侦听器提供了两种语法格式:
3.1 普通数据类型(方法格式的侦听器):
侦听器本质上是一个函数,如果要监听哪一个数据的变化,就把那个数据作为函数名
const vm = new Vue({
el: '#app' ,
data: { username: '" },watch: {
//侦听器本质上是一个函数,要监视哪个数据的变化,就把数据名作为方法名即可
//newVal 是"变化后的新值",oldval是"变化之前的旧值”username(newval,oldval) {
console.log(newVal, oldVal)}
}})
<div id="app"> <input type="text" v-model="searchText"> </div> <!-- Vue2.0写法 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <script> const vm = new Vue({ el: '#app', data: { searchText:'' }, //定义属性侦听器 watch:{ searchText(oldText,newText){ if(newText.length > 10){ alert('文本内容太长') } } } }) </script> <!-- Vue3.0写法 --> <script src="https://unpkg.com/vue@next"></script> <script> const obj = { data(){ return{ searchText:'' } }, //定义属性侦听器 watch:{ searchText(oldText,newText){ if(newText.length > 10){ alert('文本内容太长') } } } } Vue.createApp(obj).mount('#app') </script>
案例:使用 watch 检测用户名是否可用监听 username 值的变化,并使用 jquery 发起 Ajax 请求, 检测当前输入的用户名是否可 用:<div id="app"> <input type="text" v-model="username"> </div> <script src="./lib/jquery-v3.6.0.js"></script> <!-- Vue2.0写法 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <script> const vm = new Vue({ el: '#app', data: { username: '' }, watch: { username(newVal) { // 为了不让为空时报错,就在为空时return if (newVal === '') return // 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用!!! $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) { console.log(result) }) } } }) </script> <!-- Vue3.0写法 --> <script src="https://unpkg.com/vue@next"></script> <script> const obj = { data() { return { username: '' } }, watch: { username(newVal) { // 为了不让为空时报错,就在为空时return if (newVal === '') return // 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用!!! $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) { console.log(result) }) } } } Vue.createApp(obj).mount('#app') </script>
方法格式的监听器有两个缺点:
- 因为是函数,所以无法在刚进入页面的时候,自动触发,只有当值改变的时候才会执行。
- 如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器。
3.2 对象类型( 对象格式的侦听器):
const vm = new Vue({
el: '#app' ,
data: { username: '" },watch: {
// 定义对象格式的侦听器:只要监听到了username变化就会自动触发handler函数
username: {
// 对象中有handler属性,即侦听器的处理函数
handler(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
})
对象格式的侦听器有两个优点:
- 可以通过immediate属性,控制侦听器自动触发一次(默认是false)
- 可以 通过deep属性,控制侦听器深度监听到对象中每一个属性的变化。
① 如果我们想在第一次绑定的时候执行此监听函数 则需要 设置 immediate为true。
<div id="app"> <input type="text" v-model="username"> </div> <script src="./lib/jquery-v3.6.0.js"></script> <!-- Vue2.0写法 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <script> const vm = new Vue({ el: '#app', data: { username: 'admin' }, // 所有的侦听器,都应该被定义到 watch 节点下 watch: { // 定义对象格式的侦听器:只要监听到了username变化就会自动触发handler函数 username: { // 对象中有handler属性,即侦听器的处理函数 // 写法一:推荐 handler(newVal, oldVal) { console.log(newVal, oldVal) }, // 写法二: // handler:function(){} // immediate 选项的默认值是 false // immediate 的作用是:控制侦听器是否自动触发一次! immediate: true } } }) </script> <!-- Vue3.0写法 --> <script src="https://unpkg.com/vue@next"></script> <script> const obj = { data() { return { username: 'admin' } }, // 所有的侦听器,都应该被定义到 watch 节点下 watch: { // 定义对象格式的侦听器:只要监听到了username变化就会自动触发handler函数 username: { // 对象中有handler属性,即侦听器的处理函数 // 写法一:推荐 handler(newVal, oldVal) { console.log(newVal, oldVal) }, // 写法二: // handler:function(){} // immediate 选项的默认值是 false // immediate 的作用是:控制侦听器是否自动触发一次! immediate: true } } } Vue.createApp(obj).mount('#app') </script>
② 当需要监听对象的改变时,此时就需要设置深度侦听deep为true。
<div id="app"> <!-- 绑定在对象的属性上 --> <input type="text" v-model="info.username"> <input type="text" v-model="info.address.city"> </div> <script src="./lib/jquery-v3.6.0.js"></script> <!-- Vue2.0写法 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <script> const vm = new Vue({ el: '#app', data: { // 用户的信息对象 info: { username: 'admin', address: { city: '北京' } } }, // 所有的侦听器,都应该被定义到 watch 节点下 watch: { // 1. 侦听的是对象所以得到的也是对象 info: { handler(newVal) { console.log(newVal) }, // 开启深度监听,只要对象中任何一个属性变化了,都会触发“对象的侦听器” deep: true }, // 2. 如果要侦听的是对象的子属性的变化,则必须包裹一层单引号 'info.username'(newVal) { console.log(newVal) } } }) </script> <!-- Vue3.0写法 --> <script src="https://unpkg.com/vue@next"></script> <script> const obj = { data() { return { // 用户的信息对象 info: { username: 'admin', address: { city: '北京' } } } }, // 所有的侦听器,都应该被定义到 watch 节点下 watch: { // 1. 侦听的是对象所以得到的也是对象 info: { handler(newVal) { console.log(newVal) }, // 开启深度监听,只要对象中任何一个属性变化了,都会触发“对象的侦听器” deep: true }, // 2. 如果要侦听的是对象的子属性的变化,则必须包裹一层单引号 'info.username'(newVal) { console.log(newVal) } } } Vue.createApp(obj).mount('#app') </script>
4.定义方法的属性(methods)
在该属性下定义Vue组件的函数。
Vue自动为methods绑定this,以便于它始终指向组件实例。这将确保方法在用作事件监听或回调时保持正确的this指向。在定义methods 时应避免使用箭头函数,因为这会阻正Vue绑定恰当的this指向。
这些methods和组件实例的其它所有property一样可以在组件的模板中被访问。在模板中,它们通常被当做事件监听使用:
methods方法会每次在调用方法时候,都执行一次方法。computed 属性和methods属性的区别:
computed 属性是vue的计算属性,是数据层到视图的数据转化映射;计算属性是基于他们的依赖进行缓存的,只有在相关依赖发现改变时,他们才会重新求值,也就是说,只要他的依赖没有发生变化,那么每次访问的时候计算属性都会立即返回之前的计算结果,不在执行函数。只要计算属性依赖的数据项不发生改变,计算属性只会执行一次,然而methods里的方法调用几次就执行几次。
computed methods computed 是响应式的 methods并非响应式 调用方式不一样,computed定义的成员像属性一样访问 methods定义的成员必须以函数形式调用 computed是带缓存的,只有依赖数据发生改变,才会重新进行计算 methods里的函数在每次调用时都要执行 computed中的成员可以只定义一个函数作为只读属性,也可以定义get/set变成可读属性 这点时methods中的成员做不到的 computed不支持异步当computed内有异步操作时无效,无法监听数据的变化 可以异步 如果声明的计算属性计算量非常大的时候,而且访问量次数非常多,改变的时机却很小,那就需要用到computed;缓存会让我们减少很多计算量。
三、Vue组件的函数
1.使用限流函数
1.1 限流
- 场景1:点击按钮向服务器发起数据请求,在请求的数据回来之前多次单击按钮是无效的且会消耗资源。
- 场景2:页面中某个按钮会导致页面的刷新,我们需要限制用户对该按钮进行频繁的操作。
为了避免以上两种情况的发生,我们将使用Vue中的限流来解决该问题。
1.2 限流函数
在指定的时间间隔内不允许重复执行同一个函数。
示例:页面中有一个按钮,单击按钮后在控制台输出当前的时间,要求这个按钮的两次事件触发间隔不能小于5秒。
<!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 src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <!-- 给按钮绑定click事件 --> <button @click="myClick">按钮</button> </div> <script> // 当我们点击页面中的按钮时,会在终端打印出当前日期和时间,打印后的5s内我们多次点击按钮都不会执行打印操作,5s后则可以继续通过点击按钮来打印,依次循环 const obj = { data() { return { throttle: false } }, methods: { myClick() { if (!this.throttle) { //如果throttle取反为真,即为false时 console.log(Date()) //打印日期 } else { return //不打印 } this.throttle = true //设throttle为true setTimeout(() => { this.throttle = false //五秒钟后true变为false }, 5000) } } } Vue.createApp(obj).mount("#app") </script> </body> </html>
封装:将限流的逻辑封装成单独的工具方法——一次编写多次使用
<!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 src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <button @click="myClick">按钮</button> </div> <script> var throttle = false function throttleTool(callback, timeout) { //throttleTool:限流的工具函数;callback:回调函数;timeout:时间限制 if (!throttle) { //如果throttle取反为真,就调用回调函数 callback() //主要业务(输出日期)放在此回调函数中 } else { return } throttle = true setTimeout(() => { throttle = false }, timeout) } const obj = { data() { return { throttle: false } }, methods: { myClick() { throttleTool(() => { console.log(Date()) }, 2000) } } } Vue.createApp(obj).mount("#app") </script> </body> </html>
2.使用Lodash库进行函数限流
是一款高性能的JavaScript实用工具库,提供了大量的数组、对象、字符串等边界的操作方法,使开发者更简单的使用JavaScript,在Lodash库中提供了debounce函数进行方法的限流。
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
<!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 src="https://unpkg.com/vue@next"></script> <!--引入Lodash库--> <script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script> <body> <div id="app"> <button @click="myClick">按钮</button> </div> <script> const obj = { data(){ return{ } }, methods:{ myClick:_.debounce(function(){ console.log(Date()) },2000) } } Vue.createApp(obj).mount('#app') </script> </body> </html>