vue学习
介绍
- vue 中文网
- vue github
- Vue.js 是一套构建用户界面(UI)的渐进式JavaScript框架
起步
创建一个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 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
数据
-
只有当实例被创建时就已经存在于
data中的 property 才是响应式的。app.b = 'hi',那么对于b的改动,将不会引起视图的更新 如果。如果你知道你会在晚些时候需要一个 property,但是一开始它为空或不存在,那么你仅需要设置一些初始值
- 使用Object.freeze阻止修改现有的 property, 也就意味着响应式系统无法追踪。非要追踪,那就只有报错了
<script>
let obj = {
message : 'Hello Vue!'
}
Object.freeze(obj)
let app = new Vue({
el: '#app',
data: obj
})
</script>
- 动态添加数据的注意点
-
注意:只有
data中的数据才是响应式的,动态添加进来的数据默认为非响应式 -
可以通过以下方式实现动态添加数据的响应式
-
Vue.set(object, key, value)- 适用于添加单个属性 -
Object.assign()- 适用于添加多个属性
-
-
用过循环的方式,也可以使用Vue.set添加多个属性
实例生命周期钩子
- 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
钩子函数 - beforeCreate()
- 说明:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
- 注意:此时,无法获取 data中的数据、methods中的方法
钩子函数 - created()
- 注意:这是一个常用的生命周期,可以调用methods中的方法、改变data中的数据
- vue实例生命周期 参考1
- vue实例生命周期 参考2
- 使用场景:发送请求获取数据
钩子函数 - 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>'
}
})
- 使用javascript表达式
指令
指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
通俗来讲,指令就是利用一些特殊前缀,提供一些特殊功能,帮我们更好的操作控制dom
- v-if
v-if指令将根据表达式isShow的值的真假来插入
-
v-show
v-show指令根据表达式的真假值来显示,他是css层面的显示和隐藏,不管真假,都会解析,只是不显示 -
v-on 缩写
@click@click="handler" -
v-bind 缩写
::isShow="true"
修饰符
- .stop:阻止冒泡
- .prevent 阻止默认事件
- .self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响
- . once:设置事件只能触发一次,比如按钮的点击等。
计算属性和监听器
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。那么可以通过方法,或者计算属性来在外面实现,在模板里直接输出返回的值
计算属性 computed
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
监听数据变化 watch
watch是一个对象,键是需要观察的表达式,值是对应回调函数- 当表达式的值发生变化后,会调用对应的回调函数完成响应的监视操作
class和style绑定
- 使用方式: class="expression"
- 表达式类型: 字符串,数组,对象
条件渲染
- 两种使用方式 v-if, v-show
v-if指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染,是惰性的。- 多个条件判断,
v-if可以和v-else-ifv-else相配合
这里只渲染
B元素,惰性渲染,有就渲染,没有就不渲染
v-show的元素始终会被渲染并保留在 DOM 中。v-show只是简单地切换元素的 CSS 的display,也就是说每次都会渲染,只是css层面的显示和隐藏。
虽然没有匹配到
type === 'A',但是使用v-show还是渲染了,只是css层面display属性的切换
列表渲染
用v-for把一个数组/对象 对应为一组元素
- v-for 里使用数组
v-for="(item, index) in arrayItems"
- v-for里使用对象
v-for="(value, key, index) in objectItems"
注意 : 在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。
会发现他会从小到大自动排序,这里说明一下对象在遍历时的顺序
Object.keys()也是采用for...in 来进行遍历
- 创建一个空的列表用于存放 keys
- 将所有合法的数组索引按升序的顺序存入
- 将所有字符串类型索引按属性创建时间以升序的顺序存入
- 返回 keys 注意必须要符合 「合法的数组索引」 ,也即只有正整数才行,负数或者浮点数,一律当做字符串处理。
所以当key是正整数时,并且是从大到小的顺序返回,那么防止程序自动排序,我们可以将key变为形式上不是合法数组索引,比如 "+1", "1.0"
再或者对返回结果进行排序
事件处理
事件处理方法
-
可以用
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 元素使用
valueproperty 和input事件; - checkbox 和 radio 使用
checkedproperty 和change事件; - select 字段将
value作为 prop 并将change作为事件。
文本
复选框
单个复选框,绑定到布尔值:
多个复选框,绑定到同一个数组: checked : []
单选按钮
和复选框一样,只是类型是type='radio'
选择框
- 多选选择框 数据由字符串改为数组即可
修饰符
- v-lazy
在默认情况下,
v-model在每次input事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加lazy修饰符,从而转为在change事件_之后_进行同步:
我们再来细分一下blur和change事件
-
输入框的 change 和 blur 事件绝大多数情况下表现是一致的,输入结束后离开输入框会先后触发 change 和 blur。那么这两个事件的区别在哪呢?
-
当文本框获得焦点后,
没有输入任何内容,或者最终文本框的值没有改变时,是不会触发 change 事件的,而 blur 事件始终会触发。如果希望文本框的值一发生改变就立马执行某些操作,而不是等到离开再执行,那么可以使用 keyup 事件。
number .number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
组件
vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?
- 父子组件之间通信
- 非父子组件之间通信(兄弟组件、隔代关系组件等)
一、props/$emit
- 父组件向子组件通信 父组件通过属性绑定的形式,向子组件进行通信,子组件通多props接收父组件的传值
父组件
子组件
2. 子组件向父组件通信
子组件通过$emit触发一个事件,当这个语句被执行时,回将参数传递给父组件,父组件通过v-on监听,并接收数据
子组件
父组件
二、$parent/$children
父组件通过parent向父组件通信
要注意边界情况,如在#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组件
A组件
B组件
四、ref / refs
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据
父组件
子组件
五、eventBus
eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。
eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难(数据处理不清晰,无法及时追踪数据处理源)
- 初始化,需要创建一个事件总线,并将其导出。以便其他模块可以使用或者监听他
eventBus.js
2. 发送事件/ 接收事件
既可以是父子组件,也可以是兄弟组件,祖孙组件
下面以兄弟组件为例
A组件点击求和按钮,,B组件利用A组件传来的值,进行求和展示
A组件 通过 $emit向事件中注册心发送事件
B组件 通过$on 向事件中心注册接收事件
4. 移除事件监听者
如果想移除事件的监听, 可以像下面这样操作:
import { EventBus } from './eventBus'
EventBus.$off('addition', {})
总结
常见使用场景可以分为三类:
- 父子组件通信:
props;$parent/$children;provide/inject;ref - 兄弟组件通信:
eventBus; vuex - 跨级通信:
eventBus;provide/inject
后续会继续梳理一下核心插件,以及具体细节的实现