-
Vue實例
- Vue實例創(chuàng)建和作用
const app = new Vue({
// el: '#root',
template: '<div>{{text}}</div>',
data: {
text: 'text'
}
})
app.$mount('#root')
-- 1. app.$data
-> 所有data的數(shù)據(jù) [obj](app.data)
-- 2. app.$props
-> 所有props的數(shù)據(jù) [obj]
-- 3. app.$el
-> vue組件掛載到dom上的html節(jié)點
-- 4. app.$options
Vue實例對象的所有options, 包括默認和我們傳進去的通過options.data是同一個對象
-- 5. app.$options.render = h => { return h(div, {}, 'new render function')}
-> 這里的 h其實是createElement()方法參數(shù)1. 標簽名2. 存放標簽屬性的對象4.標簽內(nèi)容(如果還是標簽,就會循環(huán)使用createElement())
,也可以不傳參數(shù) h
直接使用this.$createElement()方法
-- 6. app.$root
-> 指的的是掛載到真實html上的根實例對象
-- 7. app.$children
-> 在父組件里通過調(diào)用slots
-> vue插槽 -> 在組件章節(jié)中會有講解 -- 9.
app.refs
-> 如果ref綁定組件到dom節(jié)點獲取模板的真實dom節(jié)點, 如果綁定到組件, 獲取組件的實例 -- 11.
app.parent, 獲取父組件的實例. 可以改變父組件的屬性, 不推薦, 在且只在new Vue實例的parent屬性中定義一個父組件, 這樣就可以獲取這個組件的實例, 普通組件中的組件間的關(guān)系是vue渲染中指定了, 無法修改
// comp1 可以通過this.$parent獲取comp0的實例
new Vue {
parent: comp0
}
2.Vue實例的屬性
- Vue實例的方法
-- 1.app.$mount()
-> 將Vue實例掛載到真實Dom上
-- 2.app.$watch()
-> 監(jiān)聽data里的數(shù)據(jù),作用同組件內(nèi)的watch, 在組件銷毀的同事, 需要注銷掉, 否則會導致內(nèi)存溢出, 在組件內(nèi)生命的watch伴隨這組件的消亡而注銷, 而調(diào)用的$watch方法需要手動注銷
// 監(jiān)聽data數(shù)據(jù)并得到注銷watch的函數(shù)
const unWatch = app.$watch('text', (newText, oldText) => {})
// 注銷watch
unWatch()
-- 3. app.$on
和app.$emit
-> 用來派發(fā)(emit)和監(jiān)聽(on)事件, 必須同事作用于同一vue對象否則不會冒泡 app.$once
-> 只觸發(fā)一次
app.$on('test', (a, b) => {
console.log(`test emited ${a} $需曾`)
})
app.$emit('test', 1, 2)
-- 4. app.$forceUpdate -> 強制組件重新渲染一次
new Vue({
...,
data: {
obj: {} // vue是響應式的框架, 如果沒有聲明對象里邊的屬性而直接給這個屬性賦值, 就不是響應式的, 可以在每次調(diào)用這個屬性的時候, 執(zhí)行一次app.$forceUpdate(), 但是這樣性能太低
}
})
-- 5. app.$set()
-> 用來給date里的數(shù)組和對象添加響應式的屬性, 相當于把某些值, 補到了data里
app.$set(app.obj, 'a', 123)
-- 6. app.$delete(app.obj, 'a')
-> app.$set()
的對應方法: 如果直接刪除nextTick(callback())
-> 這個和js的事件隊列有關(guān), vue的渲染過程是異步的,舉個例子: 在setInterval()里, 聲明一個變量
i并讓
i++五次, 最后打印
i的值, 得到的結(jié)果不會是, 一個一個往上加, 而是5個5個的往上加, 這就是js事件隊列 -> js會把當前的隊列都執(zhí)行一遍, 然后在循環(huán)一遍, 執(zhí)行新添加的隊列,如果是需要操作dom節(jié)點的, 肯定是要在dom全渲染完之后才行, $nextTick就是再dom完全渲染完之后, 才執(zhí)行回調(diào)(如果你拿不到dom或者值跟新了頁面沒更新, 這個時候你可能會用到$nextTick) -- 8.
app.$destroy()` -> 主動銷毀組件
-
vue組件的生命周期
- beforeCreate() -> 組件初始化就會執(zhí)行
-- 初始化events和 lifecycle, reactive并沒有初始化, 不要做數(shù)據(jù)的修改 - created()
-- created()之后會判斷是否有el屬性, 沒有就等待$mount方法被調(diào)用,
初始化injections 和reactive - beforeMount() -> 將組件的template編譯掛載到dom上 -> $el是vue綁定到的真事dom
中間有個 render(createElement) -> 在render之前會vue會查看是否有template屬性, 有的話, 會通過render把template渲染到頁面上, 沒有的話就會顯示vue掛載的節(jié)點 - mounted() -> $el是組件template里的數(shù)據(jù)
- beforeUpdate() -> 數(shù)據(jù)更新的時候執(zhí)行
- updated()
- activated() -> keepalive激活的時候執(zhí)行
- deactivated() - keepalive停用的時候執(zhí)行
- beforeDestroy() - 組件銷毀的時候觸發(fā)
- destroyed()
- renderError(h, err){return h('div', {}, err.stack)} -> render()報錯時會調(diào)用此方法, 只會在開發(fā)環(huán)境調(diào)用, 只管自己的組件的錯誤, 不能冒泡
- errorCaptured () {} -> 可以捕捉到子組件的報錯, 用法類似renderError() 可以在線上使用
調(diào)用一次的: create類, mount類, destroy類
ssr調(diào)用的: create類
生命周期中vue實例有哪些區(qū)別? -> $el會有所不同
注: 在使用.vue開始方式, 都沒有template, vue-loader會直接將.vue文件中的template解析成render()方法, 這樣更快
-
vue的數(shù)據(jù)綁定
- class的數(shù)據(jù)綁定
:class="{active: isActive}" -> 如果isActive是true就添加active的類名
:class="['header', {active: isActive}, isActive ? 'red' : 'green']"
- style的數(shù)據(jù)綁定: 動態(tài)綁定的style會自動添加瀏覽器前綴
:style="[s1, s2, {color: 'red'}]"
data () {return { s1, s2 }}
-
computed和watch
- computed是vue的計算屬性, 可以對data進行處理, 擁有緩存機制, 只有當相關(guān)數(shù)據(jù)改變的時候, 才會執(zhí)行computed里的相關(guān)函數(shù), 這也是為什么要用computed而不是在methods創(chuàng)建一個方法
computed寫在標簽上時候, 不用加(), 這是因為, computed是通過Object.defineProperty(obj, 'abc', { get: () => xxx, value: xxx }), 通過get方法可以直接以變量名的方式調(diào)用函數(shù)
{
computed: {
name () {
return first + last
}
}
}
// computed內(nèi)部支持Object.defineProperty()的get和set函數(shù)
{
computed: {
name: {
get () {},
set (name) {在這里可以改變data中的數(shù)據(jù)(不推薦, 容易搞出死循環(huán))}
}
}
}
- watch: 監(jiān)聽數(shù)據(jù)的變化, 當數(shù)據(jù)變化時才執(zhí)行這個watch里的方法
watch: {
first (newData, oldData) {
console.log('change', newData, oldData)
}
}
// watch可以通過設置參數(shù)去立刻執(zhí)行
在data里聲明對象時, 有幾個坑, 1. 如果為聲明對象的屬性, 那么只有第一次給obj屬性賦值時會觸發(fā)watch, 2. 即便在data里聲明了obj.a,通過obj.a的方式修改數(shù)據(jù), 也不會觸發(fā)watch監(jiān)聽, watch只會監(jiān)聽obj的對象引用, 通過this.obj = {a:1}的方式才能被watch監(jiān)聽到,
watch: {
// obj: {
// handler (newData, oldData) {
// console.log('obj.a change')
// },
// immediate: true // 立即執(zhí)行watch
// deep: true // 為true時候, watch會遞歸循環(huán)obj里的說有屬性, 性能低
// }
// 這種方式可以監(jiān)聽obj的屬性, 性能高用字符串里去寫對象的深入調(diào)用
'obj.a': () => {
console.log('obj.a change')
}
}
- vue原生指令
指令修飾符: @click.stop: 組織冒泡, @keydown.13: 按回車, v-model.number="": 輸入的數(shù)字為number類型, v-model.trim="": 輸入的內(nèi)容清除前后空格, @touchend.capture=""或@touchstart.capture="": 事件捕獲
-
v-text
: 顯示文本, 標簽只能顯示v-text里的內(nèi)容 -
v-html
: 顯示未轉(zhuǎn)義的內(nèi)容, 可以解析標簽 -
v-show
: 原理display:none -
v-if
: 節(jié)點不放在dom流里, 動態(tài)增刪節(jié)點, 性能低重繪 -
v-for
: 遍歷數(shù)組和對象, 性能優(yōu)化添加:key="內(nèi)容不要index" -> 通過:key里邊的內(nèi)容(唯一的id)去判斷是否重新渲染這一行:數(shù)組:v-for="(item, index) in items"
, 對象:v-for-"(val, key, index) in obj"
-
v-on:
簡寫@
: 綁定事件, 如果是dom節(jié)點:使用addEventListener, 如果是組件使用$on, 修飾符: .stop組織冒泡 -
v-bind:
簡寫:
:綁定變量 -
v-model
: 表單響應式的改變數(shù)據(jù), 修飾符 .number: 數(shù)字為Number類型, .lazy: blur時顯示數(shù)據(jù), .trim: 清除前后空格
-- checkbox的v-model綁定一個變量, 只要這個變量為true就是選中狀態(tài), 2. 可以對多個checkbox使用數(shù)組, 每一個checkbox的value就是這數(shù)組對應的值
-- radio: v-model綁定的變量和radio的value相等時, 為選中狀態(tài) -
v-once
: {{}}只執(zhí)行一次, 之后就不會檢測 -
v-pre
: 直接輸出{{}}和里邊的內(nèi)容
-
組件的定義
- 全局定義: Vue.component('ComP', component1)
- 組件內(nèi)定義子組件: components: { ComP: component1 }
- props: 指定子組件的可配置行為
props: ['active', 'data']
props: {
active: {
type: Boolean,
default: false,
required: true
},
data: {
type: [String, Number]
}
}
// props的自定義核驗
props: {
active: {
// type: Boolean,
validator (value) {
return typeof value === Boolean
}
}
}
-
組件的extend => 擴展vue,兩種extend方式,
-- 第一種, 實例化擴展: 類似于子組件, 可以通過 propsData
傳遞props, 鉤子函數(shù)先調(diào)用, component里的, data會覆蓋component里的
const compVue = Vue.extend(component)
new CompVue({
el: '#root',
propsData: {
prop1: 'xxx'
}
})
-- 第二種在組件內(nèi)的extends屬性中什么要繼承的組件
extends: component
如何去用呢? 在一個比較完善的組件里, 配置項太多, 或者還需要擴展, 這時候, 就可以在你的組件上extends這個組件, 然后去覆蓋或拓展他的配置
-
組件的高級屬性
-
slot
插槽:
-- 具名插槽:
const component = {
template = '<div>
<slot name="header"></slot>
<slot></slot>
</div>'
}
new Vue({
components: { ComP: component},
template: '
<com-p>
<p slot="header">我是header</p>
<p>我是默認的插槽</p>
</com-p>
'
})
-- 插槽傳值
const component = {
template = '<div>
<slot name="header"></slot>
<slot :a="aaa" b="bbb"></slot>
</div>',
data () {
return {
a: 'a的值'
}
}
}
new Vue({
components: { ComP: component},
template: '
// 組件的ref是組件的實例(不推薦, 應該使用props), dom幾點的ref是dom節(jié)點
<com-p ref="comp">
<p slot="header" ref="p">我是header</p>
<p scope-slot="obj">{{obj.a}}我是默認的插槽{{obj.b}}</p>
</com-p>
'
})
-
provide
和inject
: 往任意后代組件傳值,provide
原生不支持reactive的, 需要用到Object.defineProperty()方法
const sunCom = {
inject: ['yeye', 'data'],
template: `<div>我是孫子</div>`,
mounted () {
console.log(this.$parent.$options.name) // er-com
console.log(this.yeye, this.data.value) //
}
}
const erCom = {
name: 'er-com',
components: {sunCom},
template: `<sun-com></sun-com>`
}
new Vue({
// provide必須是一個函數(shù), 否則this實例不會出現(xiàn)的
provide () {
// 官方不推薦, 有可能會改變寫法或棄用
// 通過defineProperty()自己指定一個get方法
const data = {}
// 解釋一下下邊的代碼: 每次獲取 value的時候, 都會直接調(diào)用get()方法, 設置為可枚舉后, get方法就會每次獲取最新的數(shù)據(jù)
// vue的reactive基礎就是Object.defineProperty()里的get()方法
Object.defineProperty(data, 'value', {
get: () => this.value,
enumerable: true // 把屬性設置成可枚舉的, (可遍歷)
})
return {
yeye: this,
data
}
},
components: {erCom},
template: `<er-com><er-com>`,
data: {
value: 'yeye的value'
}
})
-
vue之render()
{
...,
render() {
return this.$createElement('div', {標簽屬性}, 標簽內(nèi)容(還有標簽就在調(diào)用[$createElement)]多節(jié)點用數(shù)組)
}
}
-
vue的原生組件:
-- <router-view>
-- <router-link>
-- <keep-alive>
-- <slot>
-- <transition>