Vue源码解析(五)
来源:互联网 发布:vb用户管理系统 编辑:程序博客网 时间:2024/05/19 06:51
接下来看看renderMixin方法,这个方法在Vue的原型上增加了$nextTick
、_render
以及_o、_n、_s
等方法。
Vue.prototype.$nextTick = function (fn) { return nextTick(fn, this) };
$nextTick
方法传入一个函数,同时调用nextTick方法,传入的fn是dom刷新之后的回调。
var nextTick = (function () { var callbacks = []; var pending = false; var timerFunc; function nextTickHandler () { pending = false; var copies = callbacks.slice(0); callbacks.length = 0; for (var i = 0; i < copies.length; i++) { copies[i](); } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native Promise.then or MutationObserver. // MutationObserver has wider support, however it is seriously bugged in // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It // completely stops working after triggering a few times... so, if native // Promise is available, we will use it: /* istanbul ignore if */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); var logError = function (err) { console.error(err); }; timerFunc = function () { p.then(nextTickHandler).catch(logError); // in problematic UIWebViews, Promise.then doesn't completely break, but // it can get stuck in a weird state where callbacks are pushed into the // microtask queue but the queue isn't being flushed, until the browser // needs to do some other work, e.g. handle a timer. Therefore we can // "force" the microtask queue to be flushed by adding an empty timer. if (isIOS) { setTimeout(noop); } }; } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS IE11, iOS7, Android 4.4 var counter = 1; var observer = new MutationObserver(nextTickHandler); var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = String(counter); }; } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = function () { setTimeout(nextTickHandler, 0); }; } return function queueNextTick (cb, ctx) { var _resolve; callbacks.push(function () { if (cb) { try { cb.call(ctx); } catch (e) { handleError(e, ctx, 'nextTick'); } } else if (_resolve) { _resolve(ctx); } }); if (!pending) { pending = true; timerFunc(); } if (!cb && typeof Promise !== 'undefined') { return new Promise(function (resolve, reject) { _resolve = resolve; }) } }})();
nextTick方法采用了一个闭包,然后返回的函数为queueNextTick。如其名queueNextTick是一个NextTick队列,多次调用nextTick方法会放入队列中,然后按照顺序依次进入传入的回调函数。callbacks为回调函数的队列,dom更新完成后(如何确定的更新完成?),依次执行。执行回调队列方法一共采用了3中方式:1、Promise 2、MutationObserver 3、setTimeout。
Vue.prototype._render = function () { var vm = this; var ref = vm.$options; var render = ref.render; var staticRenderFns = ref.staticRenderFns; var _parentVnode = ref._parentVnode; if (vm._isMounted) { // clone slot nodes on re-renders for (var key in vm.$slots) { vm.$slots[key] = cloneVNodes(vm.$slots[key]); } } vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject; if (staticRenderFns && !vm._staticTrees) { vm._staticTrees = []; } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. vm.$vnode = _parentVnode; // render self var vnode; try { vnode = render.call(vm._renderProxy, vm.$createElement); } catch (e) { handleError(e, vm, "render function"); // return error render result, // or previous vnode to prevent render error causing blank component /* istanbul ignore else */ { vnode = vm.$options.renderError ? vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e) : vm._vnode; } } // return empty vnode in case the render function errored out if (!(vnode instanceof VNode)) { if ("development" !== 'production' && Array.isArray(vnode)) { warn( 'Multiple root nodes returned from render function. Render function ' + 'should return a single root node.', vm ); } vnode = createEmptyVNode(); } // set parent vnode.parent = _parentVnode; return vnode };
_render方法为内部方法,主要是渲染vnode(虚拟节点)。
var VNode = function VNode ( tag, data, children, text, elm, context, componentOptions) { this.tag = tag; this.data = data; this.children = children; this.text = text; this.elm = elm; this.ns = undefined; this.context = context; this.functionalContext = undefined; this.key = data && data.key; this.componentOptions = componentOptions; this.componentInstance = undefined; this.parent = undefined; this.raw = false; this.isStatic = false; this.isRootInsert = true; this.isComment = false; this.isCloned = false; this.isOnce = false;};
VNode的构造函数,传递了tag,data,children等参数,VNode构造函数的参数比较多,某些参数的作用如isStatic不是特别清楚。
Vue.prototype._o = markOnce; Vue.prototype._n = toNumber; Vue.prototype._s = toString; Vue.prototype._l = renderList; Vue.prototype._t = renderSlot; Vue.prototype._q = looseEqual; Vue.prototype._i = looseIndexOf; Vue.prototype._m = renderStatic; Vue.prototype._f = resolveFilter; Vue.prototype._k = checkKeyCodes; Vue.prototype._b = bindObjectProps; Vue.prototype._v = createTextVNode; Vue.prototype._e = createEmptyVNode; Vue.prototype._u = resolveScopedSlots;
vue的原型上添加了_o、_n、_s
等14个内部方法,源码的注释说明是render函数的一些帮助函数,都放在了vue的原型上。这个地方不是很理解的是为什么要采用单字母来命名方法,有什么特别的意义?
阅读全文
0 0
- Vue源码解析(五)
- Vue源码解析(一)
- Vue源码解析(二)
- Vue源码解析(三)
- Vue源码解析(四)
- 自己实现MVVM(Vue源码解析)
- vue源码解析
- 源码有毒:Jfinal源码解析(五)
- Java集合源码解析(五)HashSet源码解析
- Vue学习之源码分析--VNode节点(Vue.js实现(五)
- Android源码解析之(五)-->IntentService
- c3p0源码解析 五 (C3P0Config类)
- (五)Mina源码解析之编解码器
- Tomcat源码解析(五):安全性控制
- AOP源码解析(五)获取代理
- TFS源码解析五
- springIOC源码解析(五)
- 前端框架--自己实现MVVM(Vue源码解析)
- 将字符串数据按照指定的编码写入到文本文件中
- 作用域安全的构造函数
- 2017-09-06,学习到mysql忘记密码的修补方法
- python设计模式之原型模式
- Tortoise SVN使用方法,简易图解
- Vue源码解析(五)
- go-hbase的坑
- 如何将exe文件包装为Windows服务
- 浏览器的加载、解析、和渲染--总结
- JAVA学习60_Java从字符串中提取数字
- eclipse+tomcat+jdk安装配置
- POJ 1001 Exponentiation(高精度乘法)
- CodeForces
- Unicode以及.rc的一点问题