vue源码探索之过滤器解析过程
模板编译
<body> <div id="app"> <span>{{ 1 | test(8) }}</span> </div> </body> <script src="./vue.js"></script> <script> new Vue({ el: "#app", filters: { test (val, b) { console.log(this) debugger return val + b } } });
模板在编译成render函数时候会经过下面一系列流程:
parseText
主要在parseText函数解析文本
function parseText ( text, delimiters ) { debugger var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE; if (!tagRE.test(text)) { return } var tokens = []; var rawTokens = []; var lastIndex = tagRE.lastIndex = 0; var match, index, tokenValue; while ((match = tagRE.exec(text))) { index = match.index; // push text token if (index > lastIndex) { rawTokens.push(tokenValue = text.slice(lastIndex, index)); tokens.push(JSON.stringify(tokenValue)); } // tag token var exp = parseFilters(match[1].trim()); tokens.push(("_s(" + exp + ")")); rawTokens.push({ ‘@binding‘: exp }); lastIndex = index + match[0].length; } if (lastIndex < text.length) { rawTokens.push(tokenValue = text.slice(lastIndex)); tokens.push(JSON.stringify(tokenValue)); } return { expression: tokens.join(‘+‘), tokens: rawTokens // 解析成 ["_s(_f("test")(1,8))"] } }
_f函数就是resolveFilter函数
function resolveFilter (id) { debugger return resolveAsset(this.$options, ‘filters‘, id, true) || identity }
function resolveAsset ( options, type, id, warnMissing ) { /* istanbul ignore if */ if (typeof id !== ‘string‘) { return } var assets = options[type]; // check local registration variations first if (hasOwn(assets, id)) { return assets[id] } var camelizedId = camelize(id); if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } var PascalCaseId = capitalize(camelizedId); if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } // fallback to prototype chain var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; if (warnMissing && !res) { warn( ‘Failed to resolve ‘ + type.slice(0, -1) + ‘: ‘ + id, options ); } return res }
resolveAsset就是取出我们在组件中定义在filters里面的test函数,由此可见当我们在定义filter函数中this是不指向当前组件实例的,指向window。如果要想拿到组件实例,可通过调用过滤器的时候,传入this