Vue学习笔记记录

一、前置工作和初识Vue

0.前置

中文官网

英文官网

(1)介绍与描述

  • Vue 是一套用来动态构建用户界面的渐进式 JavaScript 框架。

    • 构建用户界面:把数据通过某种办法变成用户界面。

    • 渐进式:Vue 可以自底向上逐层的应用,简单应用只需要一个5轻量小巧的核心库,复杂应用可以引入各式各样的 Vue 插件。

  • 作者:尤雨溪(Evan You)

    • 2013年,受到Angular框架的启发,尤雨溪开发出了一款轻量框架——Seed。同年12月,Seed更名为Vue,版本号0.6.0。

    • 2014年,Vue正式对外发布,版本号0.8.0。Taylor otwell 在 Twitter上发表动态,说自己正在学习Vue.js。

    • 2015年,10月27日,正式发布Vue1.0.0 Evangelion(新世纪福音战士)。

    • 2016年,10月1日,正式发布Vue 2.0.0 Ghost in the Shell(攻壳机动队)。

    • 2020年,9月18日,正式发布Vue 3.0.0 0ne Piece (海贼王)。

(2)Vue的特点

  • 遵循MVVM模式

  • 编码简洁,体积小,运行效率高,适合移动/PC端开发

  • 它本身只关注 UI,可以引入其它第三方库开发项目

  • 采用组件化模式,提高代码复用率、且让代码更好维护

  • 声明式编码,让编码人员无需直接操作DOM,提高开发效率

  • 使用虚拟DOM和Diff算法,尽量复用DOM节点

(3)与其他JS框架的关联

  • 借鉴angular的模板数据绑定技术

  • 借鉴react的组件化虚拟DOM技术

(4)Vue周边库

  • vue-cli:vue 脚手架

  • vue-resource(axios):ajax 请求

  • vue-router:路由

  • vuex:状态管理(它是 vue 的插件是没有用 vue-xxx 的命名规则)

  • vue-lazyload:图片懒加载

  • vue-scroller:页面滑动相关

  • mint-ui:基于vue的UI组件库(移动端)

  • element-ui:基于vue的UI组件库(PC端)

(5)前置工作

  • 给浏览器安装Vue Devtools插件

  • 标签引入Vue包

  • (可选)阻止vue在启动时生成生产提示Vue.config.productionTip = false

  • favicon需要将页签图标放在项目根路径,重新打开就有了(shfit+F5强制刷新)

1.初识Vue

  • 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象

  • demo容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法

  • demo容器里的代码被称为【Vue模板】

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

  • 真实开发中只有一个Vue实例,并且会配合着组件一起使用

  • {{xxx}}是Vue的语法:插值表达式,{{xxx}}可以读取到data中的所有属性

    • 注意区分:js表达式会产生一个值,可以放在任何一个需要值的地方

    • 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新(Vue实现的响应式)

初始示例代码

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8" />
 5         <title>初识Vue</title>
 6         <!-- 引入Vue -->
 7         <script type="text/javascript" src="../js/vue.js"></script>
 8     </head>
 9     <body>
10         <div id="demo">
11             <h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
12         </div>
13 
14         <script type="text/javascript" >
15             Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
16 
17             //创建Vue实例
18             new Vue({
19                 el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
20                 data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
21                     name:'atguigu',
22                     address:'北京'
23                 }
24             })
25 
26         </script>
27     </body>
28 </html>

2.模板语法

Vue模板语法有2大类:

  • 插值语法:

    功能:用于解析标签体内容

    写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性

  • 指令语法:

    功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)

    举例:v-bind:href="xxx" 或简写为 :href="xxx",xxx同样要写js表达式,且可以直接读取到data中的所有属性

 1 <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>模板语法</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h1>插值语法</h1>
13              <h3>你好,{{name}}</h3>
14              <hr/>
15              <h1>指令语法</h1>
16              <a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a>
17              <a :href="school.url" x="hello">点我去{{school.name}}学习2</a>
18          </div>
19      </body>
20 21      <script type="text/javascript">
22          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
23 24          new Vue({
25              el:'#root',
26              data:{
27                  name:'jack',
28                  school:{
29                      name:'大前端',
30                      url:'http://www.atguigu.com',
31                  }
32              }
33          })
34      </script>
35  </html>

3.数据绑定

Vue中有2种数据绑定的方式:

  • 单向绑定(v-bind):数据只能从data流向页面

  • 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data

    tips:

    1.双向绑定一般都应用在表单类元素上(如:input、select等)

    2.v-model:value可以简写为v-model,因为v-model默认收集的就是value值

    3.如果属性没有加v-bind指令,那么属性中“”里的值就是普通字符串,如果加了v-bind指令,就会把“”里的值解析为表达式

 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="UTF-8" />
         <title>数据绑定</title>
         <!-- 引入Vue -->
         <script type="text/javascript" src="../js/vue.js"></script>
     </head>
     <body>
         <!-- 准备好一个容器-->
         <div id="root">
             <!-- 普通写法 -->
             <!-- 
                 单向数据绑定:<input type="text" v-bind:value="name"><br/>
                 双向数据绑定:<input type="text" v-model:value="name"><br/> 
             --><!-- 简写 -->
             单向数据绑定:<input type="text" :value="name"><br/>
             双向数据绑定:<input type="text" v-model="name"><br/><!-- 如下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上 -->
             <!-- <h2 v-model:x="name">你好啊</h2> -->
         </div>
     </body><script type="text/javascript">
         Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
             el:'#root',
             data:{
                 name:'大前端'
             }
         })
     </script>
 </html>

4.el与data的两种写法

el有2种写法

  • a.new Vue时候配置el属性

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

 <script>
    // 第一种
  const vm = new Vue({
  el:'#root',
  data:{
  name:'jack',
        }
  })
     
     // 第二种
     vm.$mount('#root')
 </script>

data有2种写法

  • a.对象式:data:{ }

  • b.函数式:data() { return {} }

    在组件中,data必须使用函数式,否则会报错

    一个重要原则:由Vue管理的函数,一定不要写箭头函数,否则this就不再是Vue实例了。

 1  <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>el与data的两种写法</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h1>你好,{{name}}</h1>
13          </div>
14      </body>
15 16      <script type="text/javascript">
17          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
18 19          //el的两种写法
20          /* const v = new Vue({
21              //el:'#root', //第一种写法
22              data:{
23                  name:'大前端'
24              }
25          })
26          console.log(v)
27          v.$mount('#root') //第二种写法 */
28 29          //data的两种写法
30          new Vue({
31              el:'#root',
32              //data的第一种写法:对象式
33              /* data:{
34                  name:'大前端'
35              } */
36 37              //data的第二种写法:函数式
38              data(){
39                  console.log('@@@',this) //此处的this是Vue实例对象
40                  return{
41                      name:'大前端'
42                  }
43              }
44          })
45      </script>
46  </html>

5.Vue中的MVVM

img

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

  • V:视图(View):模板代码

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

  • 观察发现:

    • 1.data中所有的属性,最后都出现在了vm身上。

    • 2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。

 1 <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>理解MVVM</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h1>学校名称:{{name}}</h1>
13              <h1>学校地址:{{address}}</h1>
14              <!-- <h1>测试一下1:{{1+1}}</h1>
15              <h1>测试一下2:{{$options}}</h1>
16              <h1>测试一下3:{{$emit}}</h1>
17              <h1>测试一下4:{{_c}}</h1> -->
18          </div>
19      </body>
20 21      <script type="text/javascript">
22          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
23 24          const vm = new Vue({
25              el:'#root',
26              data:{
27                  name:'大前端',
28                  address:'北京',
29              }
30          })
31          console.log(vm)
32      </script>
33  </html>

6.数据代理

建议学习文章地址:

https://zh.javascript.info/property-descriptors

https://zh.javascript.info/property-accessors

属性标志:

对象属性(properties),除 value 外,还有三个特殊的特性(attributes),也就是所谓的“标志”

  • writable — 如果为 true,则值可以被修改,否则它是只可读的

  • enumerable — 如果为 true,则表示是可以遍历的,可以在for.. .in Object.keys()中遍历出来

  • configurable — 如果为 true,则此属性可以被删除,这些特性也可以被修改,否则不可以

Object.getOwnPropertyDescriptor(obj, propertyName)

这个方法是查询有关属性的完整信息:obj是对象, propertyName是属性名

 1  let user = {
 2    name: "John"
 3  };
 4  5  let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
 6  7  8  console.log(descriptor)
 9 10  /* 属性描述符:
11  {
12    "value": "John", 
13    "writable": true,  // 控制属性是否可以被修改,默认值是false
14    "enumerable": true,  // 控制属性是否可以被枚举,默认值是false
15    "configurable": true  // 控制属性是否可以被删除
16  }
17  */

打印结果

在这里插入图片描述

Object.defineProperty(obj, prop, descriptor)

obj:要定义属性的对象。

prop:要定义或修改的属性的名称

descriptor:要定义或修改的属性描述符

 1 let user = {
 2    name: "John"
 3  };
 4  5  Object.defineProperty(user, "name", {
 6    writable: false
 7  });
 8  9  user.name = "Pete";
10 11  // 打印后还是显示 'John',无法修改name值

其他的属性标志就不演示了,接下来看重点:访问器属性。

访问器属性:

本质上是用于获取和设置值的函数,但从外部代码来看就像常规属性。

访问器属性由 “getter” 和 “setter” 方法表示。在对象字面量中,它们用 getset 表示:

1  let obj = {
2      get name() {
3          // 当读取 obj.propName 时,getter 起作用
4      },
5      set name() {
6          // 当执行 obj.name = value 操作时,setter 起作用
7      }
8  }

 

更复杂一点的使用

 1  let user = {
 2      surname: 'gao',
 3      name: 'han'
 4      
 5      get fullName() {
 6          return this.name + this.surname;
 7      }
 8  }
 9 10  console.log(user.fullName)

从外表看,访问器属性看起来就像一个普通属性。这就是访问器属性的设计思想。我们不以函数的方式调用user.fullName,我们正常读取它:getter 在幕后运行。

vue的计算属性的底层构造感觉用到了这种思想,我目前还没看过源码,是这样猜想的。

截至目前,fullName 只有一个 getter。如果我们尝试赋值操作 user.fullName=,将会出现错误:

 user.fullName = "Test"; // Error(属性只有一个 getter)

user.fullName 添加一个 setter 来修复它:

 1  let user = {
 2      surname: 'gao',
 3      name: 'han'
 4      
 5      get fullName() {
 6          return this.name + ' ' + this.surname;
 7      }
 8  9      set fullName(value) {
10          // 这个用到了新语法 结构赋值
11          [this.surname, this.name] = value.split(' ');
12      }
13  }
14 15  user.fullName = 'Li Hua'
16 17  console.log(user.name);
18  console.log(user.surname);

终于可以介绍数据代理了

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

先来看个案例:

1  let obj = {
2      x: 100
3  }
4 5  let obj2 = {
6      y: 200
7  }

这时候提一个需求:我们想要访问 obj 中的 x 的值,但我们最好不要直接去访问 obj ,而是想要通过 obj2 这个代理对象去访问。

这时候就可以用上 Object.defineProperty(),给 obj2 添加上访问器属性(也就是getter和setter)

 1  let obj = {
 2      x: 100
 3  }
 4  5  let obj2 = {
 6      y: 200
 7  }
 8  9  Object.defineProperty(obj2, 'x', {
10      get() {
11          return obj.x;
12      },
13      set(value) {
14          obj.x = value;
15      }
16  })

这就是数据代理,也不难吧

接下来介绍Vue中的数据代理

  • Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)

  • Vue中数据代理的好处:更加方便的操作data中的数据

  • 基本原理:

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

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

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

我来用一个案例来详细解释这一个过程。

 1  <!-- 准备好一个容器-->
 2  <div id="root">
 3      <h2>学校名称:{{name}}</h2>
 4      <h2>学校地址:{{address}}</h2>
 5  </div>
 6  7  <script>
 8      const vm = new Vue({
 9          el: '#root',
10          data: {
11              name: '浙江师范大学',
12              address: '浙江金华'
13          }
14      })
15  </script>

我们在控制台打印 new 出来的 vm

在这里插入图片描述

可以看到,写在配置项中的 data 数据被绑定到了 vm 对象上,结果是,是 Vue 将 _data中的name,address 数据代理到vm本身上。

一脸懵逼?

先来解释下_data 是啥,_data就是vm身上的_data属性,就是下图那个

在这里插入图片描述

这个_data是从哪来的?

 1  <script>
 2      
 3      const vm = new Vue({
 4          el: '#root',
 5          // 我们在Vue 初始化的配置项中写了 data 属性。
 6          data: {
 7              name: '浙江师范大学',
 8              address: '浙江金华'
 9          }
10      })
11  </script>

 

new Vue 时, Vue通过一系列处理,将匹配项上的data数据绑定到了_data 这个属性上,并对这个属性进行了处理(数据劫持),但这个属性就是来源于配置项中的 data,我们可以来验证一下。

 1  <script>
 2      
 3      let data1 = {
 4          name: '浙江师范大学',
 5          address: '浙江金华'
 6      }
 7      
 8      const vm = new Vue({
 9          el: '#root',
10          // 我们在Vue 初始化的配置项中写了 data 属性。
11          data: data1
12      })
13  </script>

 

在这里插入图片描述

打印结果为true,说明两者就是同一个

好了,再回到数据代理上来,将vm._data中的值,再代理到vm本身上来,用vm.name 代替vm._data.name。这就是 Vue 的数据代理

在这里插入图片描述

这一切都是通过 Object.defineProperty() 来完成的,我来模拟一下这个过程

1  Object.defineProperty(vm, 'name', {
2      get() {
3          return vm._data.name;
4      },
5      set(value) {
6          vm._data.name = value
7      }
8  })

这样有啥意义?明明通过 vm._data.name 也可以访问 name 的值,为啥费力去这样操作?

在插值语法中,{{ name }} 取到的值就相当于 {{ vm.name }},不用数据代理的话,在插值语法就要这样去写了。

{{ _data. name }} 这不符合直觉,怪怪的。vue 这样设计更利于开发者开发,我们在研究原理会觉得有些复杂(笑~)

来个尚硅谷张天禹老师做的图

在这里插入图片描述

即Vue将data中的数据拷贝了一份到_data属性中,又将_data里面的属性提到Vue实例中(如name),通过defineProperty实现数据代理,这样可以通过getter/setter操作name,进而操作_data中的name,而_data又对data进行数据劫持,实现响应式。

7.事件处理

事件的基本使用:

  • 1.使用v-on:xxx 或@xxx绑定事件,其中xxx是事件名

  • 2.事件的回调需要配置在methods对象中,最终会在vm上

  • 3.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象

  • 注意:

    • methods中配置的函数,不用用箭头函数,否则this就不是vm了

    • @click="demo"和@click="demo($event)"效果一致,但后者可以传参

 1  <!-- 准备好一个容器-->
 2  <div id="root">
 3      <h2>欢迎来到{{name}}学习</h2>
 4      <!-- <button v-on:click="showInfo">点我提示信息</button> -->
 5      <button @click="showInfo1">点我提示信息1(不传参)</button>
 6      <!-- 主动传事件本身 -->
 7      <button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
 8  </div>
 9 10  <script>
11      const vm = new Vue({
12          el:'#root',
13          data:{
14              name:'vue',
15          },
16          methods:{
17              // 如果vue模板没有写event,会自动传 event 给函数
18              showInfo1(event){
19                  // console.log(event.target.innerText)
20                  // console.log(this) //此处的this是vm
21                  alert('同学你好!')
22              },
23              showInfo2(event,number){
24                  console.log(event,number)
25                  // console.log(event.target.innerText)
26                  // console.log(this) //此处的this是vm
27                  alert('同学你好!!')
28              }
29          }
30      });
31  </script>

Vue中的事件修饰符

  • prevent:阻止默认事件(常用)

  • stop:阻止事件冒泡(常用)

  • once:事件只触发一次(常用)

  • capture:使用事件的捕获模式

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

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

  • 【注】修饰符可以连续写,比如:@click.prevent.stop="showInfo"

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="UTF-8" />
  5         <title>事件修饰符</title>
  6         <!-- 引入Vue -->
  7         <script type="text/javascript" src="../js/vue.js"></script>
  8         <style>
  9             *{
 10                 margin-top: 20px;
 11             }
 12             .demo1{
 13                 height: 50px;
 14                 background-color: skyblue;
 15             }
 16             .box1{
 17                 padding: 5px;
 18                 background-color: skyblue;
 19             }
 20             .box2{
 21                 padding: 5px;
 22                 background-color: orange;
 23             }
 24             .list{
 25                 width: 200px;
 26                 height: 200px;
 27                 background-color: peru;
 28                 overflow: auto;
 29             }
 30             li{
 31                 height: 100px;
 32             }
 33         </style>
 34     </head>
 35     <body>
 36         <!-- 准备好一个容器-->
 37         <div id="root">
 38             <h2>欢迎来到{{name}}学习</h2>
 39             <!-- 阻止默认事件(常用) -->
 40             <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
 41 
 42             <!-- 阻止事件冒泡(常用) -->
 43             <div class="demo1" @click="showInfo">
 44                 <button @click.stop="showInfo">点我提示信息</button>
 45                 <!-- 修饰符可以连续写 -->
 46                 <!-- <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> -->
 47             </div>
 48 
 49             <!-- 事件只触发一次(常用) -->
 50             <button @click.once="showInfo">点我提示信息</button>
 51 
 52             <!-- 使用事件的捕获模式 -->
 53             <div class="box1" @click.capture="showMsg(1)">
 54                 div1
 55                 <div class="box2" @click="showMsg(2)">
 56                     div2
 57                 </div>
 58             </div>
 59 
 60             <!-- 只有event.target是当前操作的元素时才触发事件; -->
 61             <div class="demo1" @click.self="showInfo">
 62                 <button @click="showInfo">点我提示信息</button>
 63             </div>
 64 
 65             <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
 66             <ul @wheel.passive="demo" class="list">
 67                 <li>1</li>
 68                 <li>2</li>
 69                 <li>3</li>
 70                 <li>4</li>
 71             </ul>
 72 
 73         </div>
 74     </body>
 75 
 76     <script type="text/javascript">
 77         Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
 78 
 79         new Vue({
 80             el:'#root',
 81             data:{
 82                 name:'大前端'
 83             },
 84             methods:{
 85                 showInfo(e){
 86                     alert('同学你好!')
 87                     // console.log(e.target)
 88                 },
 89                 showMsg(msg){
 90                     console.log(msg)
 91                 },
 92                 demo(){
 93                     for (let i = 0; i < 100000; i++) {
 94                         console.log('#')
 95                     }
 96                     console.log('累坏了')
 97                 }
 98             }
 99         })
100     </script>
101 </html>

Vue键盘事件

1.Vue中常用的按键别名:

  • 回车 => enter

  • 删除 => delete (捕获“删除”和“退格”键)

  • 退出 => esc

  • 空格 => space

  • 换行 => tab (特殊,必须配合keydown去使用)

  • 上 => up

  • 下 => down

  • 左 => left

  • 右 => right

2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

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

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

(2).配合keydown使用:正常触发事件。

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

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

 1  <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>键盘事件</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h2>欢迎来到{{name}}学习</h2>
13              <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo">
14          </div>
15      </body>
16 17      <script type="text/javascript">
18          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
19          Vue.config.keyCodes.huiche = 13 //定义了一个别名按键
20 21          new Vue({
22              el:'#root',
23              data:{
24                  name:'大前端'
25              },
26              methods: {
27                  showInfo(e){
28                      // console.log(e.key,e.keyCode)
29                      console.log(e.target.value)
30                  }
31              },
32          })
33      </script>
34  </html>

8.计算属性

实现方法:插值语法实现、method实现(数据发生变化,模板就会被重新解析)、computed计算属性

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

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

  • get函数什么时候执行?

    • (1)初次读取时会执行一次

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

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

  • 备注:

    • 计算属性最终会出现在vm上,直接读取使用即可

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

    • 如果计算属性确定不考虑修改,可以使用计算属性的简写形式

 1 <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>姓名案例_计算属性实现</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              姓:<input type="text" v-model="firstName"> <br/><br/>
13              名:<input type="text" v-model="lastName"> <br/><br/>
14              全名:<span>{{fullName}}</span> <br/><br/>
15          </div>
16      </body>
17 18      <script type="text/javascript">
19          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
20 21          const vm = new Vue({
22              el:'#root',
23              data:{
24                  firstName:'',
25                  lastName:'',
26              },
27              computed:{
28                  //完整写法
29                  /* fullName:{
30                      get(){
31                          console.log('get被调用了')
32                          return this.firstName + '-' + this.lastName
33                      },
34                      set(value){
35                          console.log('set',value)
36                          const arr = value.split('-')
37                          this.firstName = arr[0]
38                          this.lastName = arr[1]
39                      }
40                  } */
41                  //简写
42                  fullName(){
43                      console.log('get被调用了')
44                      return this.firstName + '-' + this.lastName
45                  }
46              }
47          })
48      </script>
49  </html>

9.监视属性

监视属性watch:

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

  • 监视的属性必须存在,才能进行监视,既可以监视data,也可以监视计算属性

  • 配置项属性immediate:false,改为true,则初始化时调用一次handler(newValue, oldValue)

  • 监视的两种写法:

    • (1) new Vue时传入watch: {}配置

    • (2) 通过vm.$watch()监视

 1 <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>天气案例_监视属性</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h2>今天天气很{{info}}</h2>
13              <button @click="changeWeather">切换天气</button>
14          </div>
15      </body>
16 17      <script type="text/javascript">
18          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
19          
20          const vm = new Vue({
21              el:'#root',
22              data:{
23                  isHot:true,
24              },
25              computed:{
26                  info(){
27                      return this.isHot ? '炎热' : '凉爽'
28                  }
29              },
30              methods: {
31                  changeWeather(){
32                      this.isHot = !this.isHot
33                  }
34              },
35              /* watch:{
36                  isHot:{
37                      immediate:true, //初始化时让handler调用一下
38                      //handler什么时候调用?当isHot发生改变时。
39                      handler(newValue,oldValue){
40                          console.log('isHot被修改了',newValue,oldValue)
41                      }
42                  }
43              } */
44          })
45 46          vm.$watch('isHot',{
47              immediate:true, //初始化时让handler调用一下
48              //handler什么时候调用?当isHot发生改变时。
49              handler(newValue,oldValue){
50                  console.log('isHot被修改了',newValue,oldValue)
51              }
52          })
53      </script>
54  </html>

深度监视:

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

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

备注:

  • (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!

  • (2).使用watch时根据数据的具体结构,决定是否采用深度监视。

 1  <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>天气案例_深度监视</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h2>今天天气很{{info}}</h2>
13              <button @click="changeWeather">切换天气</button>
14              <hr/>
15              <h3>a的值是:{{numbers.a}}</h3>
16              <button @click="numbers.a++">点我让a+1</button>
17              <h3>b的值是:{{numbers.b}}</h3>
18              <button @click="numbers.b++">点我让b+1</button>
19              <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>
20              {{numbers.c.d.e}}
21          </div>
22      </body>
23 24      <script type="text/javascript">
25          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
26          
27          const vm = new Vue({
28              el:'#root',
29              data:{
30                  isHot:true,
31                  numbers:{
32                      a:1,
33                      b:1,
34                      c:{
35                          d:{
36                              e:100
37                          }
38                      }
39                  }
40              },
41              computed:{
42                  info(){
43                      return this.isHot ? '炎热' : '凉爽'
44                  }
45              },
46              methods: {
47                  changeWeather(){
48                      this.isHot = !this.isHot
49                  }
50              },
51              watch:{
52                  isHot:{
53                      // immediate:true, //初始化时让handler调用一下
54                      //handler什么时候调用?当isHot发生改变时。
55                      handler(newValue,oldValue){
56                          console.log('isHot被修改了',newValue,oldValue)
57                      }
58                  },
59                  //监视多级结构中某个属性的变化
60                  /* 'numbers.a':{
61                      handler(){
62                          console.log('a被改变了')
63                      }
64                  } */
65                  //监视多级结构中所有属性的变化
66                  numbers:{
67                      deep:true,
68                      handler(){
69                          console.log('numbers改变了')
70                      }
71                  }
72              }
73          })
74 75      </script>
76  </html>

监视属性简写

 1  <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>天气案例_监视属性_简写</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              <h2>今天天气很{{info}}</h2>
13              <button @click="changeWeather">切换天气</button>
14          </div>
15      </body>
16 17      <script type="text/javascript">
18          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
19          
20          const vm = new Vue({
21              el:'#root',
22              data:{
23                  isHot:true,
24              },
25              computed:{
26                  info(){
27                      return this.isHot ? '炎热' : '凉爽'
28                  }
29              },
30              methods: {
31                  changeWeather(){
32                      this.isHot = !this.isHot
33                  }
34              },
35              watch:{
36                  //正常写法
37                  /* isHot:{
38                      // immediate:true, //初始化时让handler调用一下
39                      // deep:true,//深度监视
40                      handler(newValue,oldValue){
41                          console.log('isHot被修改了',newValue,oldValue)
42                      }
43                  }, */
44                  //简写
45                  /* isHot(newValue,oldValue){
46                      console.log('isHot被修改了',newValue,oldValue,this)
47                  } */
48              }
49          })
50 51          //正常写法
52          /* vm.$watch('isHot',{
53              immediate:true, //初始化时让handler调用一下
54              deep:true,//深度监视
55              handler(newValue,oldValue){
56                  console.log('isHot被修改了',newValue,oldValue)
57              }
58          }) */
59 60          //简写
61          /* vm.$watch('isHot',(newValue,oldValue)=>{
62              console.log('isHot被修改了',newValue,oldValue,this)
63          }) */
64 65      </script>
66  </html>

computed和watch之间的区别:

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

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

两个重要的小原则:

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

2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象

 1  <!DOCTYPE html>
 2  <html>
 3      <head>
 4          <meta charset="UTF-8" />
 5          <title>姓名案例_watch实现</title>
 6          <!-- 引入Vue -->
 7          <script type="text/javascript" src="../js/vue.js"></script>
 8      </head>
 9      <body>
10          <!-- 准备好一个容器-->
11          <div id="root">
12              姓:<input type="text" v-model="firstName"> <br/><br/>
13              名:<input type="text" v-model="lastName"> <br/><br/>
14              全名:<span>{{fullName}}</span> <br/><br/>
15          </div>
16      </body>
17 18      <script type="text/javascript">
19          Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
20 21          const vm = new Vue({
22              el:'#root',
23              data:{
24                  firstName:'',
25                  lastName:'',
26                  fullName:'张-三'
27              },
28              watch:{
29                  firstName(val){
30                      setTimeout(()=>{
31                          console.log(this)
32                          this.fullName = val + '-' + this.lastName
33                      },1000);
34                  },
35                  lastName(val){
36                      this.fullName = this.firstName + '-' + val
37                  }
38              }
39          })
40      </script>
41  </html>

10.绑定样式

(1)class样式

写法::class="xxx",xxx可以是字符串、对象、数。

所以分为三种写法,字符串写法,数组写法,对象写法

字符串写法

字符串写法适用于:类名不确定,要动态获取。

 1  <style>
 2      .normal{
 3          background-color: skyblue;
 4      }
 5  </style>
 6  7  <!-- 准备好一个容器-->
 8  <div id="root">
 9      <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
10      <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
11  </div>
12 13  <script>
14      const vm = new Vue({
15          el:'#root',
16          data:{
17              mood:'normal'
18          }
19      })
20  </script>

数组写法

数组写法适用于:要绑定多个样式,个数不确定,名字也不确定。

 <style>
     .atguigu1{
         background-color: yellowgreen;
     }
     .atguigu2{
         font-size: 30px;
         text-shadow:2px 2px 10px red;
     }
     .atguigu3{
         border-radius: 20px;
     }
 </style><!-- 准备好一个容器-->
 <div id="root">
     <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
     <div class="basic" :class="classArr">{{name}}</div>
 </div><script>
     const vm = new Vue({
         el:'#root',
         data:{
             classArr: ['atguigu1','atguigu2','atguigu3']
         }
     })
 </script>

对象写法

对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

 <style>
     .atguigu1{
         background-color: yellowgreen;
     }
     .atguigu2{
         font-size: 30px;
         text-shadow:2px 2px 10px red;
     }
 </style><!-- 准备好一个容器-->
 <div id="root">
     <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
     <div class="basic" :class="classObj">{{name}}</div>
 </div><script>
     const vm = new Vue({
         el:'#root',
         data:{
             classObj:{
                 atguigu1:false,
                 atguigu2:false,
             }
         }
     })
 </script>

(2)style样式

有两种写法,对象写法,数组写法

对象写法

 <!-- 准备好一个容器-->
 <div id="root">
     <!-- 绑定style样式--对象写法 -->
     <div class="basic" :style="styleObj">{{name}}</div>
 </div><script>
     const vm = new Vue({
         el:'#root',
         data:{
             styleObj:{
                 fontSize: '40px',
                 color:'red',
             }
         }
     })
 </script>

数组写法

 <!-- 准备好一个容器-->
 <div id="root">
     <!-- 绑定style样式--数组写法 -->
     <div class="basic" :style="styleArr">{{name}}</div>
 </div><script>
     const vm = new Vue({
         el:'#root',
         data:{
             styleArr:[
                 {
                     fontSize: '40px',
                     color:'blue',
                 },
                 {
                     backgroundColor:'gray'
                 }
             ]
         }
     })
 </script>

11.条件渲染

(1)v-if

  • 写法:

    (1)v-if="表达式"

    (2)v-else-if="表达式"

    (3)v-else="表达式"

  • 适用于:切换频率较低的场景

  • 特点:不展示的DOM元素直接被移除

  • 注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”

 <!-- 准备好一个容器-->
 <div id="root">
     <!-- 使用v-if做条件渲染 -->
     <h2 v-if="false">欢迎来到{{name}}</h2>
     <h2 v-if="1 === 1">欢迎来到{{name}}</h2>
     
     
     <!-- v-else和v-else-if -->
     <div v-if="n === 1">Angular</div>
     <div v-else-if="n === 2">React</div>
     <div v-else-if="n === 3">Vue</div>
     <div v-else>哈哈</div>
     
     
     <!-- v-if与template的配合使用 -->
     <!-- 就不需要写好多个判断,写一个就行 -->
     <!-- 这里的思想就像事件代理的使用 -->
     <template v-if="n === 1">
         <h2>你好</h2>
         <h2>尚硅谷</h2>
         <h2>北京</h2>
     </template>
 </div><script>
     const vm = new Vue({
         el:'#root',
         data:{
             styleArr:[
                 {
                     fontSize: '40px',
                     color:'blue',
                 },
                 {
                     backgroundColor:'gray'
                 }
             ]
         }
     })
 </script>

(2)v-show

  • 写法:v-show="表达式"

  • 适用于:切换频率较高的场景。

  • 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(displat:none)

  • 备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

  • v-if 是实打实地改变dom元素,v-show 是隐藏或显示dom元素

  • template标签不影响结构,页面html中不会有此标签,但只能配合v-if,不能配合v-show

 <!-- 准备好一个容器-->
 <div id="root">
     <!-- 使用v-show做条件渲染 -->
     <h2 v-show="false">欢迎来到{{name}}</h2>
     <h2 v-show="1 === 1">欢迎来到{{name}}</h2>
 </div>
posted @ 2023-06-28 17:11  Caoer199  阅读(13)  评论(0编辑  收藏  举报