本节主要时对Vue官网内容进行补充。
> 我自己第一次学习Vue官网的时,由于很多概念以及用法不清楚,导致刚刚上手时遇到了一些困难。希望通过本章对某些自认为比较难理解的概念,以及后期开发中可以会涉及到的知识点进行扩展描述,希望对你有所帮助。
## 1 内容分发(slot插槽)
我们都知道向子组件传递数据可以通过绑定porps属性。如果我们现在有这样一个需求:
> 需要将一段HTML代码片段传递给子组件,并且在相应的子组件template中显示这一段HTML内容。
你会怎么做?
```js
// 第一步: 将HTML代码转成String字符串
// 第二步: 将字符串通过绑定 props 传给子组件
// 第三布:用字符串替换子组件相应位置元素的innrHTML
```
是不是觉得很麻烦?这时你就可以使用vue提供的slot元素。
```
// 在child组件的模板中你可能会这样写
<div class="child">
<slot>当你在父组件中没有写内容时,你会看到这句话!!</slot>
</div>
```
```
// 调用方式一: 父组件中
<child></child>
// ----------------------
// 渲染结果
<div class="child">
当你在父组件中没有写内容时,你会看到这句话!!
</div>
```
```
// 调用方式二: 父组件中
<child>
我这是在父组件中写的东东!!
</child>
// --------------------------------
// 渲染结果
<div class="child">
我这是在父组件中写的东东!!
</div>
```
#### 作用域插槽
在父组件中可以获得子组件的数据
```
// child-component
<div class="child">
<slot text="hello from child"></slot>
</div>
//parent-component
<div class="parent">
<child>
<template slot-scope="props">
<span>hello from parent</span>
<span>{{ props.text }}</span> // hello from child
</template>
</child>
</div>
```
## 2 is
#### 功能之一:解除DOM 模板限制
> 有些 HTML 元素,诸如` <ul>`、`<ol>`、`<table>` 和 `<select>`,对于哪些元素可以出现在其内部是有严格限制的。而有些元素, 诸如 `<li>`、`<tr> `和 `<option>`,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
```
<table>
<blog-post-row></blog-post-row>
</table>
```
这个自定义组件 `<blog-post-row> `会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的` is `特性给了我们一个变通的办法:
```
<table>
<tr is="blog-post-row"></tr>
</table>
```
#### 功能之二:动态组件
------------------
## 3 vm.$nextTick()
#### 什么是Vue.nextTick()
**官方文档解释如下:**
![](https://segmentfault.com/img/bV0wqS?w=701&h=615/view)
总得来说
>Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
通过Promise实现nextTick。当不支持Promise时,Vue底层通过setTimeout来实现。
> 因此,在代码中通过setTimeout可以实现相同功能。有人测试过,设置50ms的定时器是一个最佳值。
>个人感觉 setTimeout 比 nextTick 好用。在项目开发中,如遇到 nextTick 不好使情况下,尝试 用 setTimeout 来替换。注意,setTimeou 的回调函数应该使用 `() => {} ` 形式,否侧会出现this指向问题。
#### 为什么用Vue.nextTick()
> Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和DOm操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。
![](http://p878i6l4k.bkt.clouddn.com/Vue%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86.png)
> 当你设置 vm.someData = 'new value',DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用
#### 注需要意
在 created 和 mounted 阶段,如果需要操作渲染后的试图,也要使用 nextTick 方法。官方文档说明:
> 注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted
## 4 computed vs watch
> 相同: computed和watch都起到监听/依赖一个数据,并进行处理的作用
>
> 异同:它们其实都是vue对监听器的实现,只不过computed主要用于对同步数据的简单处理。watch则主要用于数据输入时异步操作或者开销较大的情况。**能用computed的时候优先用computed**,避免了多个数据影响其中某个数据时多次调用watch的尴尬情况。**对于视图层的改变则优先使用watch**。
>
## 5 vm.$refs操作DOM
>一个对象,持有注册过 ref 特性 的所有 DOM 元素和组件实例。
```
<div ref="myDiv">
xxx
</div>
// 在组件中,获取div myDiv元素
console.log(this.$refs.myDiv)
```
`ref`属性不仅可以用在原生DOM元素上,还可以用在自定义的组件中。这样的好处就是,你可以在父组件中调用子组件的方法
```
// 调用子组件的reset()方法
this.$refs.childComponent.reset()
```
注意
> `vm.$refs` 只在组件渲染完成后才填充,并且它是非响应式的。它仅仅是一个直接操作子组件的应急方案——应当避免在模板或计算属性中使用 $refs。