#### 前言
本部分我们主要添加一些在Vue学习中遇到的问题,大部分内容都来自于官方文档,不喜勿喷。通过对这部分官方文档主要内容的学习,希望能够快速入门Vue开发。
#### 1.通过.native为Vue组件添加原生事件
比如下面的为`ButtonMessage`组件添加原生的click事件:
```js
// 只有为Vue的组件添加.native才行,如果是下面的div或者p元素添加并不会起作用
```
其实Vue官网也有明确说明的,你也可以[点击](https://segmentfault.com/q/1010000007896386)这里。
#### 2.Vue.use使用Vue组件
比如下面的例子:
```js
import ElementUI from 'element-ui';
import TreeView from "vue-json-tree-view";
Vue.use(ElementUI);
Vue.use(TreeView)
```
这是Vue注册插件的方式。详细内容可以查看[浅谈Vue.use](https://segmentfault.com/a/1190000012296163)。比如下面是[Element-ui](https://github.com/liangklfang/element/blob/dev/packages/button/index.js)对Button组件的用法:
```js
import ElButton from './src/button';
ElButton.install = function(Vue) {
Vue.component(ElButton.name, ElButton);
};
export default ElButton;
```
下面是"./src/button"下Button组件的代码:
```js
```
在main.js中注册child组件,child的组件template指定id为上面的模板:
```js
Vue.component("child", {
// template: "
This is child
",
template: "#anchored-heading-template",
// template指定一个id的情况
props: {
level: {
type: Number,
required: true
}
}
});
```
在App.vue中我们指定template如下:
```js
// 指定:level为1
hello world
<\/template>
```
详见[Vue.js 定义组件模板的七种方式](https://www.w3cplus.com/vue/seven-ways-to-define-a-component-template-by-vuejs.html)。下面再给出一个[this.$slots](http://blog.csdn.net/yangyiboshigou/article/details/74457691)的例子:
```js
// child组件接受slot
Vue.component("child", {
render: function(createElement) {
var header = this.$slots.header;
var center = this.$slots.center;
var footer = this.$slots.footer;
//createElement第一个参数是标签名,第二个参数是值
return createElement("div", [
createElement("div", header),
createElement("div", center),
createElement("div", footer)
]);
}
});
```
下面是对child组件的使用:
```js
this is header
this is center
this is footer
```
最后渲染出来的组件DOM结构为:
```html
```
##### 6.2 通过elm获取到slot对应的DOM
```js
Vue.component("c-child", {
props: ["target"],
mounted() {
// this.target会或获取到父组件的一个实例
this.target(function(t) {
console.log("子组件调用了父组件的this.target方法", t);
});
console.log("this.$slots.reference==",this.$slots.reference[0].elm);
},
template: `我是c-child组件
`
});
```
上面定义了一个组件c-child,我们看看如何使用这个c-child组件:
```html
我是slot的子级元素
```
此时你可以看到c-child组件在mounted中通过$slots获取到了真实的DOM,而获取方法如下:
```js
this.$slots.reference[0].elm
```
这里你可以看到reference获取到的是一个**数组**,所以你可以通过如下方式来使用c-child组件:
```html
我是slot的子级元素
我是slot的2子级元素
```
而此时两个slot为reference的span都会被添加到slot="reference"指定的元素中。例子代码可以[点击](https://github.com/liangklfangl/Vue-Demo/blob/master/src/components/%24ref.vue)这里获取。
#### 7.使用inline-template取消slot
比如在main.js中注册如下内容:
```js
// 注册my-checkbox组件+inline-template
Vue.component("my-checkbox", {
data() {
return { checked: false, title: "Check me" };
},
methods: {
check() {
this.checked = !this.checked;
}
}
});
```
在使用my-checkbox的时候可以通过如下方式来完成:
```js
```
#### 8.通过render方法定义Vue组件
```js
Vue.component("my-checkbox", {
data() {
return { checked: false, title: "Check me" };
},
methods: {
check() {
this.checked = !this.checked;
}
},
render(createElement) {
return createElement(
"div",
{ attrs: { class: "checkbox-wrapper" }, on: { click: this.check } },
[
createElement("div", {
class: { checkbox: true, checked: this.checked }
}),
createElement("div", { attrs: { class: "title" } }, [this.title])
]
);
}
});
```
该方法的优点是你的模板更接近编译器,并允许你使用完整的JavaScript 功能,而不是指令提供的子集著作权归作者所有。
#### 9.render方法使用jsx
```js
Vue.component("my-checkbox", {
data() {
return { checked: false, title: "Check me" };
},
methods: {
check() {
this.checked = !this.checked;
}
},
render() {
return (
{" "}
{" "}
{this.title}
{" "}
);
}
});
```
#### 10.修改Vue的prototype
```js
import axios from 'axios';
Vue.prototype.$axios = axios;
```
在组件中就可以通过该$axios方法来获取数据了:
```js
export default {
methods: {
getData(){
let self = this;
if(process.env.NODE_ENV === 'development'){
self.url = '/ms/table/list';
};
// 通过self.$axios发送数据
self.$axios.post(self.url, {page:self.cur_page}).then((res) => {
self.tableData = res.data.list;
})
}
}
}
```
#### 11.Vue的生命周期
如下图:

请仔细阅读[官方文档](https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA)。
| 生命周期方法 | 方法描述 |
|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| beforeCreate | 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 |
| created | 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,**$el 属性目前不可见**。 |
| beforeMount | 在挂载开始之前被调用:相关的 render 函数**首次被调用**。该钩子在服务器端渲染期间不被调用。 |
| mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用[ vm.$nextTick 替换掉 mounted](https://cn.vuejs.org/v2/api/#mounted)。该钩子在服务器端渲染期间不被调用。 |
| beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。 |
| updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick 替换掉 updated。 该钩子在服务器端渲染期间不被调用。 |
下面再说下一些和生命周期相关的问题:
(1)数据请求的方法[一般在created里面就可以](https://segmentfault.com/q/1010000010643393),如果涉及到需要页面加载完成之后的话就用mounted。
(2)created的时候,视图中的html并没有渲染出来,所以此时如果直接去[操作HTML的DOM节点](http://blog.csdn.net/xdnloveme/article/details/78035065),一定找不到相关的元素,而在mounted中,由于此时html已经渲染出来了,所以可以直接操作DOM节点。
#### 12.Vue中不要使用箭头函数
**不要在选项属性或回调上使用箭头函数**,比如:
```js
created: () => console.log(this.a)
vm.$watch('a', newValue => this.myMethod())
```
因为**箭头函数是和父级上下文绑定在一起的,this不会是如你所预期的Vue实例**,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
#### 13.Vue中的[key](https://cn.vuejs.org/v2/api/#key)
key的特殊属性主要用在**Vue的虚拟DOM算法**,在新旧nodes对比时辨识VNodes。如果不使用 key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于key的变化重新排列元素顺序,并且会**移除key不存在的元素**。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。最常见的用例是结合 v-for:
```html
```
它也可以用于强制替换元素/组件而不是重复使用它(类似React的key实现组件卸载)。当你遇到如下场景时它可能会很有用:完整地触发组件的生命周期钩子触发过渡。例如:
```html
{{ text }}
```
当 text 发生改变时, 会随时被更新,因此会触发过渡,请[查看官方文档](https://cn.vuejs.org/v2/guide/list.html#key)。
#### 14.Vue中的v-model和v-bind区别
1. v-bind是数据绑定,没有双向绑定效果,但不一定在表单元素上使用,任何有效元素上都可以使用;
2. v-model是双向绑定,基本上只用在表单元素上;
3. 当v-bind和v-model同时用在一个元素上时,它们各自的作用没变,但v-model优先级更高,而且需区分这个元素是单个的还是一组出现的。
官方文档有明确说明v-model的**作用**:\其实是\的语法糖
**下面给出v-bind和v-model共存的情况**:
```html
```
下面是对应的data数据:
```js
data: { options: [1, 2, 3, 4, 5], selected: [],}
```
data.selected是一个数组,当一个选项被选中之后,这个选项的value值会被加入到data.selected中。这个时候:value就是有效的,因为它表示把options数组中对应的选项值传递给value,并不是双向绑定的意思,而只是传值过去。相当于说,**v-bind负责value的值,v-model负责选中状态**。当然,v-model是双向绑定,界面上你去勾选会影响data.selected的值,你在程序中操作了data.selected,也会反过来影响界面。v-model影响的是勾选效果,而v-bind影响的是值。
注意,只有当type="checkbox"是确定的情况下,才会让上述情况生效,type值不能是动态值,因为v-model被多次绑定同一个变量时,需要去检查type值,而如果这个时候type是动态的,比如用:type="type"进行动态绑定,就会导致模板编译报错。完整的代码如下:
```js
<\/template>
```
[下面是dialog对于state的声明使用](https://github.com/Kelichao/vue.js.2.0/blob/master/src/pages/dialogPage.vue):
```js
// 2.v-if判断是否可见
```
##### 15.3 兄弟[组件之间通信](http://zengxt.pw/2017/01/07/vue%E9%9D%9E%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E6%80%8E%E4%B9%88%E9%80%9A%E4%BF%A1/)
```js
var eventBus = new Vue({});
// Vue.component注册组件
Vue.component("foo", {
template:
"the count of foo is {{fooCount}}
" +
'
',
data: function() {
return {
fooCount: 0
};
},
methods: {
addBar: function() {
// 触发事件
eventBus.$emit("addBar");
}
},
mounted: function() {
eventBus.$on(
"addFoo",
function(num) {
this.fooCount += num;
}.bind(this)
);
}
});
// bar 组件
Vue.component("bar", {
template:
"the count of bar is {{barCount}}
" +
'
',
data: function() {
return {
barCount: 0
};
},
methods: {
addFoo: function() {
// 触发事件,同时传递一个参数
eventBus.$emit("addFoo", 2);
}
},
// 在 组件创建的钩子函数中 监听事件
mounted: function() {
eventBus.$on(
"addBar",
function() {
this.barCount++;
}.bind(this)
);
}
});
```
此时eventBus对象必须是两个组件都能够访问的。
#### 16.Vue中的slot与slot-scope
比如下面的[插槽](https://segmentfault.com/a/1190000012996217)的例子:
```js
这里是父组件
// 1.第一次使用:用flex展示数据
{{item}}
// 2.第二次使用:用列表展示数据
// 3.第三次使用:直接显示数据
{{user.data}}
//4.第四次使用:不使用其提供的数据
我就是模板
```
ref或者document.getElementById都能够获取到dom,而$refs相对document.getElementById的方法,会减少获取dom节点的消耗。
##### 24.3 为子组件指定一个ref来获取到vue组件实例
比如下面的例子:
```js