Vue是一套Web前端框架,看了Vue的文档之后,觉得Vue有一些很有意思的地方,就把它记录下来。
Vue实例的data属性
看下面的例子:
// Our data object
var data = { a: 1 }
// The object is added to a Vue instance
var vm = new Vue({
data: data
})
// Getting the property on the instance
// returns the one from the original data
vm.a == data.a // => true
// Setting the property on the instance
// also affects the original data
vm.a = 2
data.a // => 2
// ... and vice-versa
data.a = 3
vm.a // => 3
Vue的实例创建之后,会把入参对象中的data下面的所有属性拷到自己的户下,比如上面例子中data.a被拷贝到vm.a
。不过更让人惊奇的是,data.a
的值变化了之后,vm.a
的值竟然也跟着变化。
然后Vue实例本身的属性和方法则是以$
开头,例如:
vm.$data
vm.$el
vm.$watch(...)
Vue的Lifecycle钩子
Vue的Lifecycle钩子比React要多很多,每次执行一个操作之前和之后基本都会有一个钩子:
- beforeCreated和created
- beforeMount和mounted
- beforeUpdate和updated
- beforeDestroy和destroyed
Vue的模板语法
html内容需要使用rawHtml
才能放到一个element里面
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
对于v-bind
, <div v-bind:id="dynamicId"></div>
可以缩写为<div :id="dynamicId"></div>
。
对于v-on
,<a v-on:click="doSomething"></a>
可以缩写为<a @click="doSomething"></a>
。
在模板里面只能写一行JavaScript表达式
Okay的
{{ message.split('').reverse().join('') }}
不Okay的
{{ if (ok) { return message } }}
双向数据绑定很简单,可以使用v-model
<input v-model="question">
v-if
用来在模板中做条件控制。因为Vue的指令不能做元素使用,也就是说没有<v-if>
这个标签,所以必须把v-if
放在<template>
标签上,也就是这样<template v-if="ok">
。当然,<template>
本身最终不会生成HTML代码。
Vue的Component
Vue的Component非常像Web的自定义元素(Custom Elements,在标准Web Components Spec中有说明)
不过对于Vue来说,Component就是一个提供预制选项和模板的Vue实例的类,并且Component的data
属性必须是一个函数,这样由Component生成Vue实例的时候,每个实例能有自己的data
拷贝:
Vue.component('todo-item', {
// The todo-item component now accepts a
// "prop", which is like a custom attribute.
// This prop is called todo.
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
可以在Vue实例的内部注册子Component
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
上面的做法叫做Local Registration, 在Component Registration有解释。
Component的Props可以是Object
props的Component的输入参数,不仅是一个数组,也可以是一个object:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object
}
扩展JS对象生成新的Component
可以通过Vue.extend来把一个普通JS对象转化成一个Component
var Comp = Vue.extend({
props: ['msg'],
template: '<div>{{ msg }}</div>'
})
var vm = new Comp({
propsData: {
msg: 'hello'
}
})
这是一个很灵活生成Component的方法,可以随时随地操作,可以用来分解大型的Component。
Component的名字可以是驼峰状和骨肉相连状
HTML本身对标签的名字是大小写不敏感的。所以驼峰状的名字(例如: <MyComponentName>
)有可能和HTML标签起冲突。 但是Vue支持另外一种命令方式,那就是骨肉相连状(Kebab),比如<my-component-name>
。
模板里面的CSS
Vue可以直接在模板里面绑定CSS,并且CSS可以是一个JavaScript对象:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
Slot:联系子Component的脐带
<navigation-link>
是一个Vue Component,它带的模板是下面这样的:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
可以看到模板中有<slot></slot>
这个槽。这个的作用是预留位置,然后在Component实例化的时候,把Component包含的内容放置到这个槽里面。
我们来实例化这个Component:
<navigation-link url="/profile">
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
上面的效果等同于:
<a
v-bind:href="url"
class="nav-link"
>
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</a>
你还可以给Slot取名字,参考Named Slots。
反刍的Scoped Slots
利用Scoped Slots,我们可以让一个Component把肚子的参数吐出来,供给Component的调用者使用,这个过程有点像反刍。
首先我们有一个叫<todo-list>
的Component,里面包含若干条todo数据,并且使用以下模板:
<ul>
<li
v-for="todo in todos"
v-bind:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
如果我们在调用<todo-list>
的时候想使用里面的todo数据,比如todo.text
,可以这样操作:
<todo-list v-bind:todos="todos">
<!-- Define `slotProps` as the name of our slot scope -->
<template slot-scope="slotProps">
<!-- Define a custom template for todo items, using -->
<!-- `slotProps` to customize each todo. -->
<span v-if="slotProps.todo.isComplete">✓</span>
{{ slotProps.todo.text }}
</template>
</todo-list>
通过指定slot-scope="slotProps"``slotProps
属性就像<todo-list>
张开的口,可以获取到其内部数据集合,比如slotProps.todo.text
。
如果不需要访问所有的内部数据,我们可以只取slotProps
里面的部分属性:
<todo-list v-bind:todos="todos">
<template slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>
注意,上面的例子中slot-scope="{ todo }"
只从之前的slotProps
里面选取了todo
属性,而不是之前slotProps
那样获取所有的属性。
scoped slot可以用来制作Renderless Component