日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue源码后记-更多options参数(1)

發布時間:2024/4/14 vue 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue源码后记-更多options参数(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  我是這樣計劃的,寫完這個還寫一篇數據變動時,VNode是如何更新的,順便初探一下diff算法。

  至于vue-router、vuex等插件源碼,容我緩一波好吧,vue看的有點傷。

?

  其實在之前講其余內置指令有涉及到on事件綁定,這里再詳細從頭看一下事件綁定的正統流程吧!

  上html代碼:

<body><div id='app'><div @click.self.number='click'>{{computedValue | filter}}</div></div></body><script src='./vue.js'></script><script>new Vue({el: '#app',data: {value: 1},computed: {computedValue: function() {return this.value * 2}},methods: {click: function() {console.log('click!');}},filters: {filter: function(value) {if (!value) {return;}return value * 4;}}})</script>

  包含最常見的click事件,計算屬性以及過濾器,鉤子函數講過就不寫了,所有的函數都是最簡單模式。

?

1、mergeOptions

  源碼看的有點惡心,流程都能背下來了。

  第一步是進行參數合并,傳入的對象作為options與默認的options進行合并,并通過strat對象對應的方法處理:

// parent => baseOptions// child => optionsfunction mergeOptions(parent, child, vm) {// code...function mergeField(key) {var strat = strats[key] || defaultStrat;options[key] = strat(parent[key], child[key], vm, key);}return options}

  這里主要是調用strat對象方法對每一個options的鍵進行處理,目前傳進來有data、computed、methods、filters四個。

  data前面講過,其余三個依次看一下。

?

  computed、methods

  兩個參數對應同一個方法:

strats.props =strats.methods =strats.computed = function(parentVal, childVal) {if (!childVal) {return Object.create(parentVal || null)}if (!parentVal) {return childVal}var ret = Object.create(null);extend(ret, parentVal);extend(ret, childVal);return ret};

  比較簡單,將兩個合并,直接返回該對象并掛載到vm上:

  

  filters

function mergeAssets(parentVal, childVal) {var res = Object.create(parentVal || null);return childVal ?extend(res, childVal) :res}

  非常無趣的函數:

?

2、initState

  vue上面屬性添加完后,接下來是數據初始化階段:

function initState(vm) {vm._watchers = [];var opts = vm.$options;if (opts.props) { initProps(vm, opts.props); }if (opts.methods) { initMethods(vm, opts.methods); }if (opts.data) {initData(vm);} else {observe(vm._data = {}, true /* asRootData */ );}if (opts.computed) { initComputed(vm, opts.computed); }if (opts.watch) { initWatch(vm, opts.watch); }}

  可以看到這里對props、methods、data、computed、watch幾個屬性都做了初始化。

methods

function initMethods(vm, methods) {var props = vm.$options.props;for (var key in methods) {// 重新綁定上下文vm[key] = methods[key] == null ? noop : bind(methods[key], vm); {if (methods[key] == null) {// 函數對象值為空時 }// 判斷重名if (props && hasOwn(props, key)) {// warning }}}}

  這個Init函數做了2件事,第一是對所有函數進行上下文綁定并掛載到vm上,第二是與props進行排重,不允許出現相同鍵名。

?initComputed

function initComputed(vm, computed) {var watchers = vm._computedWatchers = Object.create(null);for (var key in computed) {var userDef = computed[key];var getter = typeof userDef === 'function' ? userDef : userDef.get; {if (getter === undefined) {// warn No getter functiongetter = noop;}}// create internal watcher for the computed property.watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions);if (!(key in vm)) {defineComputed(vm, key, userDef);} else {// key查重 }}}function defineComputed(target, key, userDef) {if (typeof userDef === 'function') {sharedPropertyDefinition.get = createComputedGetter(key);sharedPropertyDefinition.set = noop;} else {// setter、getter }Object.defineProperty(target, key, sharedPropertyDefinition);}function createComputedGetter(key) {return function computedGetter() {var watcher = this._computedWatchers && this._computedWatchers[key];if (watcher) {if (watcher.dirty) {watcher.evaluate();}if (Dep.target) {watcher.depend();}return watcher.value}}}

  處理computed時,內部會new一個watcher來專門監聽相關數據變動,然后用defineProperty在vm上聲明一個對象。

?

2、parseHTML

  合并完參數并做init初始化后,第二步應該是解析DOM字符串了。

  直接看關鍵點,外層的div跳過,只看里層的,首先是:

<div @click.self.number='click'>

  切割函數為:

var startTagMatch = parseStartTag();if (startTagMatch) {handleStartTag(startTagMatch);continue}

  第一次暴力切割后,直接以=分割屬性:

  接下來進入handleStartTag => start =>?processAttrs

function processAttrs(el) {var list = el.attrsList;var i, l, name, rawName, value, modifiers, isProp;for (i = 0, l = list.length; i < l; i++) {name = rawName = list[i].name;value = list[i].value;// name => @click.self.numberif (dirRE.test(name)) {el.hasBindings = true;// 修飾符// modifiers => {self:true,number:true}modifiers = parseModifiers(name);if (modifiers) {// name => @clickname = name.replace(modifierRE, '');}if (bindRE.test(name)) { // v-bind// code...} else if (onRE.test(name)) { // v-onname = name.replace(onRE, '');addHandler(el, name, value, modifiers, false, warn$2);} else { // normal directives// code... }} else {// code... }}}function parseModifiers(name) {// modifierRE => /\.[^.]+/g;var match = name.match(modifierRE);if (match) {var ret = {};match.forEach(function(m) {ret[m.slice(1)] = true;});return ret}}

  這里會首先對事件name進行修飾符判斷,截取出self與number兩個字段,保存到modifiers對象中。

  修飾符處理完后,進入v-on指令分支,首先正則替換掉第一個@字符,進入addHandler函數。

function addHandler(el, name, value, modifiers, important, warn) {// handle capture,passive,oncevar events;if (modifiers && modifiers.native) {delete modifiers.native;events = el.nativeEvents || (el.nativeEvents = {});} else {events = el.events || (el.events = {});}var newHandler = {value: value,modifiers: modifiers};var handlers = events[name];/* istanbul ignore if */if (Array.isArray(handlers)) {important ? handlers.unshift(newHandler) : handlers.push(newHandler);} else if (handlers) {events[name] = important ? [newHandler, handlers] : [handlers, newHandler];} else {// {value:click,modifiers:{self:true,number:true}}events[name] = newHandler;}}

  該函數處理特殊事件類型,包括capture、once、passive,并會給事件字符串添加特殊的前綴。

  完事后,該AST會被添加一個events屬性,如圖:

?

  下面轉換節點內部的表達式:

{{computedValue | filter}}

  關鍵函數是parseFilters,用來分割過濾器:

function parseFilters(exp) {// var...for (i = 0; i < exp.length; i++) {prev = c;c = exp.charCodeAt(i);if (inSingle) {// code...} else if (c === 0x7C && // pipeexp.charCodeAt(i + 1) !== 0x7C &&exp.charCodeAt(i - 1) !== 0x7C &&!curly && !square && !paren) {// 第一次匹配到 | 時if (expression === undefined) {// first filter, end of expressionlastFilterIndex = i + 1;expression = exp.slice(0, i).trim();}// 多個filter串聯 else {pushFilter();}} else {// code... }}if (expression === undefined) {expression = exp.slice(0, i).trim();} else if (lastFilterIndex !== 0) {pushFilter();}function pushFilter() {(filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim());lastFilterIndex = i + 1;}if (filters) {for (i = 0; i < filters.length; i++) {expression = wrapFilter(expression, filters[i]);}}return expression}

  其中切割大括號的部分跳過,主要看是如何處理分割后的filter:

function wrapFilter(exp, filter) {// filter有可能帶有參數 => {{value | filter(args)}}var i = filter.indexOf('(');if (i < 0) {// _f: resolveFilterreturn ("_f(\"" + filter + "\")(" + exp + ")")} else {var name = filter.slice(0, i);var args = filter.slice(i + 1);return ("_f(\"" + name + "\")(" + exp + "," + args)}}

  這里本來只有兩種情況,一種只有函數名,一種是帶參數的函數。

  1、單純函數

{{computedValue | filter}}

  如果只有函數名,此時i為-1,會進入第一個分支,直接返回對應的拼接字符串,如圖:

   2、帶參數的函數

{{computedValue | filter(1)}}

  此時會進入分支2,并且通過正則進行切割,name為函數名,args為參數,最后返回拼接字符串:

  3、???

  后來,我又發現了第三種情況,就是如果函數名被括號給包起來,解析會變得有點奇怪。

{{computedValue | (filter)}}

  此時,由于檢測到小括號的存在,后面的被認為是形參,一個空白字符串被當成函數名進行拼接,返回如圖:

  當然,這個會報錯,filter被認為是形參,又不存在對應的函數,既然有warning提示,也不算啥問題,盡量不作死就行。

?

  至此,AST的轉化完成,下一節講render函數的生成。

轉載于:https://www.cnblogs.com/QH-Jimmy/p/7412074.html

總結

以上是生活随笔為你收集整理的Vue源码后记-更多options参数(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品美女久久久久av超清 | 香蕉久久综合 | 波多野结衣高清视频 | 另类国产 | av亚洲在线观看 | 中文字幕在线观看的网站 | 国产爆乳无码一区二区麻豆 | 亚洲黄色在线 | 91视频免费视频 | а√天堂8资源在线官网 | 欧美成人一区二免费视频软件 | 一区二区三区伦理 | 黄色福利视频 | 亚洲免费区 | 亚洲欧美一区二区三区四区五区 | 亚洲午夜精品久久久久久人妖 | 人妻久久久一区二区三区 | 欧美日韩一区二区三区四区五区 | 毛片综合| www视频在线观看 | 久草视频国产 | 哪里可以免费看av | 久久久国产成人一区二区三区 | 一级黄色免费 | 日韩精品一区二区三区四区五区 | 国产精品久久777777 | 综合久久一区二区 | 国产在线视视频有精品 | 亚洲大成色 | 浓精喷进老师黑色丝袜在线观看 | 亚洲av永久一区二区三区蜜桃 | 丁香花婷婷 | 3p视频在线| 久久福利影视 | va婷婷在线免费观看 | 中国肥胖女人真人毛片 | 精品不卡一区二区三区 | 欧美精品久久久久久久久老牛影院 | 日日爽视频 | 亚洲动漫精品 | 日韩在线综合 | 手机在线免费观看av | 最色成人网| 丰满岳跪趴高撅肥臀尤物在线观看 | 国产在线不卡av | 男插女av| 日韩免费小视频 | 熟女人妻一区二区三区免费看 | 黄色.com | 啪啪天堂 | 天天色天天射综合网 | 日本激情视频网站 | 日本少妇一区二区 | 欧美黑人xxxⅹ高潮交 | 国产一级啪啪 | 国产传媒av | 潮见百合子 | 亚洲男人天堂久久 | 国产九一精品 | 毛片毛片毛片毛片毛片毛片毛片 | 国产经典一区 | 日韩精品一区二区三区电影 | 中国老熟妇自拍hd发布 | 国产久草视频 | 国产午夜精品理论片在线 | 日韩av在线免费观看 | 成年人视频免费看 | 色天使亚洲 | 欧美在线va | 四虎福利视频 | 日韩精品一区中文字幕 | 韩国三级hd中文字幕的背景音乐 | 国产婷婷一区二区 | 一级特毛片 | 国产精品视频免费在线观看 | 少妇又色又紧又大爽又刺激 | 成人手机视频在线观看 | 日韩一级片视频 | 午夜影院在线观看免费 | 欧美三级日本三级 | 日韩免费淫片 | 欧美高清视频一区二区三区 | 成人免费在线电影 | 亚洲视频二 | 久久久www | 日本二区视频 | 日噜| 五月激情啪啪 | 纯爱无遮挡h肉动漫在线播放 | 五月依人网 | 三级视频在线观看 | 99999视频| 午夜精品久久99蜜桃的功能介绍 | 免费a级片在线观看 | 全部免费毛片在线播放一个 | 伊人久久国产精品 | 国产欧美日本 | 亚洲无线看 | 色偷偷网站 |