這塊放到後面的開發demo裏再寫吧,說不定可以結合數據可視化組件進行分析寫。html
混入 (mixin) 提供了一種很是靈活的方式,來分發 Vue 組件中的可複用功能。一個混入對象能夠包含任意組件選項。當組件使用混入對象時,全部混入對象的選項將被「混合」進入該組件自己的選項。vue
// 定義一個混入對象
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// 定義一個使用混入對象的組件
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
複製代碼
當組件和混入對象含有同名選項時,這些選項將以恰當的方式進行「合併」。node
數據對象在內部會進行遞歸合併,並在發生衝突時以組件數據優先。react
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',//組件數據優先
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
複製代碼
同名鉤子函數將合併爲一個數組,所以都將被調用。另外,混入對象的鉤子將在組件自身鉤子以前調用。vuex
var mixin = {
created: function () {
console.log('混入對象的鉤子被調用')
}
}
new Vue({
mixins: [mixin],
created: function () {
console.log('組件鉤子被調用')
}
})
// => "混入對象的鉤子被調用"
// => "組件鉤子被調用"
複製代碼
值爲對象的選項,例如 methods、components 和 directives,將被合併爲同一個對象。兩個對象鍵名衝突時,取組件對象的鍵值對。編程
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
})
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"
複製代碼
反正衝突時候組件數據最大就對了。數組
Vue.extend() 也使用一樣的策略進行合併。bash
混入也能夠進行全局註冊。使用時格外當心!一旦使用全局混入,它將影響每個以後建立的 Vue 實例。使用恰當時,這能夠用來爲自定義選項注入處理邏輯。app
// 爲自定義的選項 'myOption' 注入一個處理器。
Vue.mixin({
created: function () {
var myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
new Vue({
myOption: 'hello!'
})
// => "hello!"
複製代碼
慎用!!!dom
自定義選項將使用默認策略,即簡單地覆蓋已有值。若是想讓自定義選項以自定義邏輯合併,能夠向 Vue.config.optionMergeStrategies 添加一個函數。(不過模塊化以後感受基本用不到了啦)
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
// 返回合併後的值
}
複製代碼
對於多數值爲對象的選項,可使用與 methods 相同的合併策略
var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods
複製代碼
一個更高級的例子
const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
if (!toVal) return fromVal
if (!fromVal) return toVal
return {
getters: merge(toVal.getters, fromVal.getters),
state: merge(toVal.state, fromVal.state),
actions: merge(toVal.actions, fromVal.actions)
}
}
複製代碼
Vue 推薦在絕大多數狀況下使用模板來建立你的 HTML。然而在一些場景中,你真的須要 JavaScript 的徹底編程的能力。這時你能夠用渲染函數,它比模板更接近編譯器。
假設咱們要生成一些帶錨點的標題
<h1>
<a name="hello-world" href="#hello-world">
Hello world!
</a>
</h1>
對於上面的 HTML,你決定這樣定義組件接口
<anchored-heading :level="1">Hello world!</anchored-heading>
<h1 v-if="level === 1">
<slot></slot>
</h1>
複製代碼
咱們來嘗試使用 render 函數替代一大串v-if與v-else-if
Vue.component('anchored-heading', {
render: function (createElement) {
return createElement(
'h' + this.level, // 標籤名稱
this.$slots.default // 子節點數組
)
},
props: {
level: {
type: Number,
required: true
}
}
})
複製代碼
向組件中傳遞不帶 v-slot 指令的子節點時,好比 anchored-heading 中的 Hello world!,這些子節點被存儲在組件實例中的 $slots.default 中。
用來訪問被插槽分發的內容。每一個具名插槽有其相應的 property (例如:v-slot:foo 中的內容將會在 vm.$slots.foo 中被找到)。default property 包括了全部沒有被包含在具名插槽中的節點,或 v-slot:default 的內容。
用來訪問做用域插槽。對於包括 默認 slot 在內的每個插槽,該對象都包含一個返回相應 VNode 的函數。
做用域插槽函數如今保證返回一個 VNode 數組,除非在返回值無效的狀況下返回 undefined。
全部的 $slots
如今都會做爲函數暴露在 $scopedSlots
中。若是你在使用渲染函數,不論當前插槽是否帶有做用域,咱們都推薦始終經過 $scopedSlots
訪問它們。這不只僅使得在將來添加做用域變得簡單,也可讓你最終輕鬆遷移到全部插槽都是函數的 Vue 3。
<div>
<h1>My title</h1>
Some text content
<!-- TODO: Add tagline -->
</div>
複製代碼
對應的DOM節點樹
每一個元素都是一個節點。每段文字也是一個節點。甚至註釋也都是節點。一個節點就是頁面的一個部分。就像家譜樹同樣,每一個節點均可以有孩子節點 (也就是說每一個部分能夠包含其它的一些部分)。高效地更新全部這些節點會是比較困難的,不過所幸你沒必要手動完成這個工做。你只須要告訴 Vue 你但願頁面上的 HTML 是什麼
這能夠是在一個模板裏
<h1>{{ blogTitle }}</h1>
或者一個渲染函數裏
render: function (createElement) {
return createElement('h1', this.blogTitle)
}
複製代碼
在這兩種狀況下,Vue 都會自動保持頁面的更新,即使 blogTitle 發生了改變。
Vue 經過創建一個虛擬 DOM 來追蹤本身要如何改變真實 DOM
上面的return到底會返回什麼呢?
其實不是一個實際的 DOM 元素。它更準確的名字多是 createNodeDescription,由於它所包含的信息會告訴 Vue 頁面上須要渲染什麼樣的節點,包括及其子節點的描述信息。咱們把這樣的節點描述爲「虛擬節點 (virtual node)」,也常簡寫它爲「VNode」。「虛擬 DOM」是咱們對由 Vue 組件樹創建起來的整個 VNode 樹的稱呼。
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一個 HTML 標籤名、組件選項對象,或者
// resolve 了上述任何一種的一個 async 函數。必填項。
'div',
// {Object}
// 一個與模板中 attribute 對應的數據對象。可選。
{
// (詳情見下一節)
},
// {String | Array}
// 子級虛擬節點 (VNodes),由 `createElement()` 構建而成,
// 也可使用字符串來生成「文本虛擬節點」。可選。
[
'先寫一些文字',
createElement('h1', '一則頭條'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
複製代碼
正如 v-bind:class 和 v-bind:style 在模板語法中會被特別對待同樣,它們在 VNode 數據對象中也有對應的頂層字段。
該對象也容許你綁定普通的 HTML attribute,也容許綁定如 innerHTML 這樣的 DOM property (這會覆蓋 v-html 指令)
這塊詳見官方文檔吧,我也不是很搞得懂,後面再作補充好了
VNode 必須惟一,組件樹中的全部 VNode 必須是惟一的。
這意味着,下面的渲染函數是不合法的
render: function (createElement) {
var myParagraphVNode = createElement('p', 'hi')
return createElement('div', [
// 錯誤 - 重複的 VNode
myParagraphVNode, myParagraphVNode
])
}
複製代碼
若是你真的須要重複不少次的元素/組件,你可使用工廠函數來實現。
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
複製代碼
只要在原生的 JavaScript 中能夠輕鬆完成的操做,Vue 的渲染函數就不會提供專有的替代方法。好比,在模板中使用的 v-if 和 v-for
<ul v-if="items.length">
<li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
//這些均可以在渲染函數中用 JavaScript 的 if/else 和 map 來重寫
props: ['items'],
render: function (createElement) {
if (this.items.length) {
return createElement('ul', this.items.map(function (item) {
return createElement('li', item.name)
}))
} else {
return createElement('p', 'No items found.')
}
}
複製代碼
渲染函數中沒有與 v-model 的直接對應——你必須本身實現相應的邏輯。
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
複製代碼
對於 .passive、.capture 和 .once 這些事件修飾符,Vue 提供了相應的前綴能夠用於 on
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}
複製代碼
對於全部其它的修飾符,私有前綴都不是必須的,由於你能夠在事件處理函數中使用事件方法(有種源碼重現的味兒了)
你能夠經過 this.$slots 訪問靜態插槽的內容,每一個插槽都是一個 VNode 數組
render: function (createElement) {
// `<div><slot></slot></div>`
return createElement('div', this.$slots.default)
}
複製代碼
也能夠經過 this.$scopedSlots 訪問做用域插槽,每一個做用域插槽都是一個返回若干 VNode 的函數
props: ['message'],
render: function (createElement) {
// `<div><slot :text="message"></slot></div>`
return createElement('div', [
this.$scopedSlots.default({
text: this.message
})
])
}
複製代碼
若是要用渲染函數向子組件中傳遞做用域插槽,能夠利用 VNode 數據對象中的 scopedSlots 字段
render: function (createElement) {
// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
return createElement('div', [
createElement('child', {
// 在數據對象中傳遞 `scopedSlots`
// 格式爲 { name: props => VNode | Array<VNode> }
scopedSlots: {
default: function (props) {
return createElement('span', props.text)//??須要demo進行驗證
}
}
})
])
}
複製代碼
render這塊有點搞暈了,等衝一遍react再回來寫好了。通常來說用HTML模板就足足夠夠了。