一捧搞、vue
-
provide, inject
provide選項應該是一個對象或返回一個對象的函數(shù)察净。該對象包含可注入其子孫的屬性疆股。
inject選項應該是:
- 一個字符串根资,或
- 一個對象架专,對象的key是本地的綁定名,value是:
- 在可用的注入內(nèi)容中搜索用的key(字符串或Symbol)或
- 一個對象玄帕,該對象的:
- from 屬性是在可用的注入內(nèi)容中搜索用的key
- default 屬性時降級情況下使用的value
// 父組件 provide:{ } // 子組件 inject:{ foo:{ from:'foo', default:'test' } }, mounted(){ console.log(this.foo); // test } <!--另外一種寫法--> // 子組件 inject:['foo']; mounted(){ console.log(this.foo);// test }
-
el
提供一個在頁面上已經(jīng)存在的DOM元素作為Vue實例的掛載目標部脚。可以是CSS選擇器裤纹,也可以是一個HTMLElement委刘。
在實例掛載之后,元素可以用vm.
mount()手動開啟編譯
源代碼:
if (vm.$options.el) { vm.$mount(vm.$options.el) }
var app = new Vue({ data:{ message:'hello Vue!' }, el:'#bpp', directives:{ }, provide(){ return { getData(){ console.log('123') } } }, beforeCreate(){ console.log(this.message) }, mounted(){ console.log(this._data, this._provided) } }); // 在 id= bpp的元素上加載Vue實例
數(shù)組去重
function dedupe (latest, sealed) {
// compare latest and sealed to ensure lifecycle hooks won't be duplicated
// between merges
if (Array.isArray(latest)) {
const res = []
sealed = Array.isArray(sealed) ? sealed : [sealed]
for (let i = 0; i < latest.length; i++) {
if (sealed.indexOf(latest[i]) < 0) {
res.push(latest[i])
}
}
return res
} else {
return latest
}
}
- compositionstart compositionend
- compositionstart 事件觸發(fā)于一段文字的輸入之前(類似于 keydown 事件罩抗,但是該事件僅在若干可見字符的輸入之前拉庵,而這些可見字符的輸入可能需要一連串的鍵盤操作、語音識別或者點擊輸入法的備選詞)套蒂。
- compositionend 事件觸發(fā)一段文字輸入完成或者刪除文字時
<input type="text" id="text" />
function trigger(el,type){
const e = document.createEvent('HTMLEvents');
e.initEvent(type,true,true);
el.dispatchEvent(e);
}
var dom = document.getElementById('text');
dom.addEventListener('compositionstart', onCompositionStart)
dom.addEventListener('compositionend', onCompositionEnd)
function onCompositionStart(e){
e.target.composing = true
console.log('===========================');
console.log('e',e);
console.log('===========================');
}
function onCompositionEnd(e){
e.target.composing = false
console.log('===========================');
console.log('end',e);
console.log('===========================');
trigger(dom,'ceshi');
}
dom.addEventListener('ceshi',function(value){
console.log(value)
})
二. 源碼分析
1.入口文件
package.json
scripts:{
"dev": "rollup -w -c build/config.js --environment TARGET:web-full-dev",
}
build/config.js
TARGET: web-full-dev
// Runtime+compiler development build (Browser)
'web-full-dev': {
entry: path.resolve(__dirname, '../src/entries/web-runtime-with-compiler.js'),
dest: path.resolve(__dirname, '../dist/vue.js'),
format: 'umd',
env: 'development',
alias: { he: './entity-decoder' },
banner
},
if (process.env.TARGET) {
module.exports = genConfig(builds[process.env.TARGET])
}
entries/web-runtime-with-compiler.js
import Vue from './web-runtime'
web-runtime.js
import Vue from 'core/index'
core/index.js
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
initGlobalAPI(Vue)
instance/index
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue) // 添加_init方法
// 初始化一些數(shù)據(jù)钞支,其中 beforeCreate鉤子在initState()數(shù)據(jù)之前,導致在beforeCreate鉤子中拿不到data或者props的值操刀,create鉤子中能拿到data或者props中的值
stateMixin(Vue) // 初始化 props,data,computed,watch 全部通過defineReactive變成響應式數(shù)據(jù) 添加$watch方法
eventsMixin(Vue) // 添加$on $off $emit方法
lifecycleMixin(Vue) // 添加_update方法烁挟,$forceUpdate方法,$destroy
renderMixin(Vue) // 添加 _render方法骨坑,添加$nextTick方法
initMixin()
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
global-api/index.js
export function initGlobalAPI (Vue: GlobalAPI) {}
<!--添加工具函數(shù)-->
initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
-
其中響應式數(shù)據(jù)核心:
Observe,Dep,Watcher,defineReactive- Obejct.defineProperty
方法會直接在一個對象上定義一個新屬性撼嗓,或者修改一個對象的現(xiàn)有屬性, 并返回這個對象欢唾。
語法:Object.defineProperty(obj, prop, descriptor)
參數(shù)
obj 要在其上定義屬性的對象且警。 prop 要定義或修改的屬性的名稱。 descriptor 將被定義或修改的屬性描述符礁遣。
注: configurable 為false時斑芜,屬性不能被刪除,為true時能被刪除祟霍,默認值為false
- defineReactive
主要作用就是在get時將watcher對象放入Dep.subs數(shù)組中杏头,set時去更新視圖
簡易實現(xiàn)(詳細參考Vue源碼)
function defineReactive(obj,key,val){ const dep = new Dep(); Object.defineProperty(obj,key,{ enumerable:true, configurable:true, get: function reactiveGetter(){ dep.addSub(Dep.target); return val; }, set: function reactiveSetter(newVal){ if(val == newVal){ return; } dep.nodify(); val = newVal; // cb(val); } }); }
- Observer 將現(xiàn)有數(shù)據(jù)變成可視化數(shù)據(jù)
簡易實現(xiàn)
function observer(value){ if(!value || typeof value !='object'){ return ; } // 遞歸循環(huán) for(let key in value){ if(Obejct.prototype.toString.call( value[key]) == '[Object object]'){ dgObj(value[key],key,value); }else{ defineReactive(value, key , value[key]); } } }
- Dep 主要作用收集watcher對象
簡易實現(xiàn)
function Dep(){ // this.subs = []; } Dep.prototype ={ subs:[], addSub:function(subs){ this.subs.push(subs); }, nodify:function(){ this.subs.forEach(sub =>{ sub.update(); }); } }; Dep.target = null;
- Watcher 將Dep.target賦值,更新視圖
function Watcher(){ Dep.target = this; } Watcher.prototype ={ update:function(){ console.log('視圖更新了7心拧4纪酢!垂谢!~~~'); } }
- Vue構造函數(shù)
簡易實現(xiàn)
function Vue (options){ this._data = options.data; new Watcher(); observer(this._data); }
以上都是簡單實現(xiàn)厦画,并且有好多細節(jié)沒有體現(xiàn)出來疮茄,例如:添加watcheer實例時會有id記錄這個對象有沒有存在于數(shù)組中滥朱,如果有就不會在添加了;在給對象賦值時VUE中也考慮到了如果當前對象存在自己的setget屬性的情況力试,但是本例中沒有考慮這種情況只是簡單的賦值 等;詳細細節(jié)可以去VUE源碼中查看