vue学习记录

149 阅读9分钟

vue学习

介绍

起步

创建一个vue实例,并指定一个元素,将其挂载到Dom元素上
<div id="app">
  {{ message }}
</div>
<script>
    let obj = {
            message : 'Hello Vue!'
    }
    let app = new Vue({ 
            el: '#app', 
            data: obj
            })
</script>
Hello Vue

当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

image.png

image.png

数据

  • 只有当实例被创建时就已经存在于 data 中的 property 才是响应式的。

     app.b = 'hi', 
    

    那么对于b的改动,将不会引起视图的更新 如果。如果你知道你会在晚些时候需要一个 property,但是一开始它为空或不存在,那么你仅需要设置一些初始值

image.png

  • 使用Object.freeze阻止修改现有的 property, 也就意味着响应式系统无法追踪。非要追踪,那就只有报错了
<script>
let obj = {
	message : 'Hello Vue!'
}
Object.freeze(obj)
let app = new Vue({ 
	el: '#app', 
	data: obj
	})
</script>

image.png

  • 动态添加数据的注意点
  1. 注意:只有data中的数据才是响应式的,动态添加进来的数据默认为非响应式

  2. 可以通过以下方式实现动态添加数据的响应式

    •  Vue.set(object, key, value) - 适用于添加单个属性
    •  Object.assign() - 适用于添加多个属性
  3. 用过循环的方式,也可以使用Vue.set添加多个属性

实例生命周期钩子

  • 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

钩子函数 - beforeCreate()

  • 说明:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
  • 注意:此时,无法获取 data中的数据、methods中的方法

钩子函数 - created()

钩子函数 - beforeMounted()

  • 说明:在挂载开始之前被调用

钩子函数 - mounted()

  • 说明:此时,vue实例已经挂载到页面中,可以获取到el中的DOM元素,进行DOM操作

钩子函数 - beforeUpdated()

  • 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
  • 注意:此处获取的数据是更新后的数据,但是获取页面中的DOM元素是更新之前的

钩子函数 - updated()

  • 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。

钩子函数 - beforeDestroy()

  • 说明:实例销毁之前调用。在这一步,实例仍然完全可用。
  • 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等

钩子函数 - destroyed()

  • 说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。 在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

插值

  • 文本 数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
<span>Message: {{ msg }}</span>
  • 原始HTML 双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html
    <div id="app">
       <p v-html="message"> </p>
    </div>
let app = new Vue({ 
	el: '#app', 
	data: {
		message: '<span style="color:red">Hellow Vue!</span>'
	}
})

image.png

  • 使用javascript表达式

image.png

指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

通俗来讲,指令就是利用一些特殊前缀,提供一些特殊功能,帮我们更好的操作控制dom

  • v-if v-if 指令将根据表达式 isShow 的值的真假来插入

image.png

  • v-show v-show 指令根据表达式的真假值来显示,他是css层面的显示和隐藏,不管真假,都会解析,只是不显示

  • v-on 缩写 @click @click="handler"

  • v-bind 缩写 : :isShow="true"

修饰符

  • .stop:阻止冒泡
  • .prevent 阻止默认事件
  • .self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响
  • . once:设置事件只能触发一次,比如按钮的点击等。

计算属性和监听器

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。那么可以通过方法,或者计算属性来在外面实现,在模板里直接输出返回的值

计算属性 computed

image.png

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

监听数据变化 watch

  • watch是一个对象,键是需要观察的表达式,值是对应回调函数
  • 当表达式的值发生变化后,会调用对应的回调函数完成响应的监视操作

image.png

image.png

image.png

class和style绑定

  • 使用方式: class="expression"
  • 表达式类型: 字符串,数组,对象

image.png

image.png

条件渲染

  • 两种使用方式 v-if, v-show
  • v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染,是惰性的。
  • 多个条件判断,v-if 可以和v-else-if v-else相配合

image.png

image.png 这里只渲染B元素,惰性渲染,有就渲染,没有就不渲染

  • v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 的display,也就是说每次都会渲染,只是css层面的显示和隐藏。

image.png

image.png

image.png 虽然没有匹配到type === 'A',但是使用v-show还是渲染了,只是css层面display属性的切换

列表渲染

v-for把一个数组/对象 对应为一组元素

  • v-for 里使用数组 v-for="(item, index) in arrayItems"

image.png

image.png

image.png

  • v-for里使用对象 v-for="(value, key, index) in objectItems"

image.png

image.png

image.png

注意 : 在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。

image.png

image.png

image.png 会发现他会从小到大自动排序,这里说明一下对象在遍历时的顺序

Object.keys()也是采用for...in 来进行遍历

  1. 创建一个空的列表用于存放 keys
  2. 将所有合法的数组索引按升序的顺序存入
  3. 将所有字符串类型索引按属性创建时间以升序的顺序存入
  4. 返回 keys 注意必须要符合 「合法的数组索引」 ,也即只有正整数才行,负数或者浮点数,一律当做字符串处理。

所以当key是正整数时,并且是从大到小的顺序返回,那么防止程序自动排序,我们可以将key变为形式上不是合法数组索引,比如 "+1", "1.0"

再或者对返回结果进行排序

image.png

事件处理

事件处理方法

  • 可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

  • v-on 还可以接收一个需要调用的方法名称,来处理复杂的业务逻辑

  • 有时也需要访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法

事件修饰符

<!-- 阻止单击事件继续传播 --> 
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 --> 
<form v-on:submit.prevent="onSubmit"></form> 
<!-- 修饰符可以串联 --> 
<a v-on:click.stop.prevent="doThat"></a> 
<!-- 只有修饰符 --> 
<form v-on:submit.prevent></form> 
<!-- 添加事件监听器时使用事件捕获模式 --> 
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 --> 
<div v-on:click.capture="doThis">...</div> 
<!-- 只当在 event.target 是当前元素自身时触发处理函数 --> 
<!-- 即事件不是从内部元素触发的 --> 
<div v-on:click.self="doThat">...</div>

按键修饰符

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

系统修饰符

表单输入绑定

你可以用 v-model 指令在表单 <input><textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。 v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

文本

image.png

image.png

复选框

单个复选框,绑定到布尔值:

image.png

image.png

image.png 多个复选框,绑定到同一个数组: checked : []

单选按钮

和复选框一样,只是类型是type='radio'

选择框

image.png

image.png

image.png

  • 多选选择框 数据由字符串改为数组即可

修饰符

  • v-lazy 在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:

我们再来细分一下blur和change事件

  1. 输入框的 change 和 blur  事件绝大多数情况下表现是一致的,输入结束后离开输入框会先后触发 change 和 blur。那么这两个事件的区别在哪呢?

  2. 当文本框获得焦点后,没有输入任何内容,或者最终文本框的值没有改变时,是不会触发 change 事件的,而 blur 事件始终会触发。如果希望文本框的值一发生改变就立马执行某些操作,而不是等到离开再执行,那么可以使用 keyup 事件。

image.png

image.png

image.png

number .number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

image.png

image.png image.png

trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

image.png

image.png

组件

vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?

  • 父子组件之间通信
  • 非父子组件之间通信(兄弟组件、隔代关系组件等)

一、props/$emit

  1. 父组件向子组件通信 父组件通过属性绑定的形式,向子组件进行通信,子组件通多props接收父组件的传值

父组件

image.png 子组件

image.png 2. 子组件向父组件通信 子组件通过$emit触发一个事件,当这个语句被执行时,回将参数传递给父组件,父组件通过v-on监听,并接收数据

子组件 image.png 父组件

image.png

image.png

二、$parent/$children

父组件通过children,向子组件通信。子组件通过children,向子组件通信。子组件通过parent向父组件通信

image.png

image.png

要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent$children的值不一样,$children 的值是数组,而$parent是个对象

总结

上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。

三、provide/inject

简单来说,就是父组件通过provide提供变量,子组件通过inject注入变量

注意: 不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

比如现在有三个组件,A组件,B组件。父组件App调用A组件,A组件调用B组件

App组件

image.png A组件

image.png B组件

image.png

四、ref / refs

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据

父组件 image.png 子组件

image.png

image.png

五、eventBus

eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。

eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难(数据处理不清晰,无法及时追踪数据处理源)

  1. 初始化,需要创建一个事件总线,并将其导出。以便其他模块可以使用或者监听他

eventBus.js

image.png 2. 发送事件/ 接收事件

既可以是父子组件,也可以是兄弟组件,祖孙组件

下面以兄弟组件为例

A组件点击求和按钮,,B组件利用A组件传来的值,进行求和展示

image.png

A组件 通过 $emit向事件中注册心发送事件

image.png B组件 通过$on 向事件中心注册接收事件

image.png

4. 移除事件监听者

如果想移除事件的监听, 可以像下面这样操作:

import { EventBus } from './eventBus'
EventBus.$off('addition', {})

总结

常见使用场景可以分为三类:

  • 父子组件通信: props; $parent / $children; provide / inject ; ref
  • 兄弟组件通信: eventBus ; vuex
  • 跨级通信: eventBusprovide / inject

后续会继续梳理一下核心插件,以及具体细节的实现