【js】 vue 2.5.1 源码学习(六) initProxy initLifeCycle 渲染函数的作用域代理
- // 大体思路 (五)
- // 本节内容:
- // 1. initProxy 渲染函数的作用域代理
- // ==> es6 如果支持proxy (hasProxy) 就用proxy 不支持就用 defineProperty()
- // proxy 和 defineProperty 区别?
- // definedProperty 只能监听对象的属性 描述属性
- // proxy 是一个构造函数 监听对象 支持拦截操作 代理obj对象对obj并不直接做处理。
- // var obj = {name: 'max'}
- // var peoxyobj = new Proxy(obj,{
- // has: function(target,key){
- // console.log('hahahhah')
- // }
- // })
- // has 钩子函数 可以拦截proxyobj 判断对象是否具有某个属性时触发钩子函数
- // has 可以拦截 with语句
- // with 改变执行中的作用域
- // console.log("name" in peoxyobj)
- // with(obj){
- // console.log(name) //== obj.name 将环境指向obj
- // }
- // with 不推荐使用 性能差
- // ==> options.render && options.render._withStripped?
- // getHeadler :
- // hasHeadler ;
- // vm._renderProxy = new Proxy(vm,h)
- // ==>hasHeadler
- // ==> alloweGlobals 检测是否为一些全局变量 或者是 render内置方法 _
- // ==>getHeadler
- // options.render 准备就绪了
- // 2. initLifecycle 实例对象$children $parent 处理
- // 将当前实例添加到父实例的 $children属性中,并设置自身的$parent的属性指向父实例。
- // abstrat // 抽象组件 1.不会出现在父级的路径上,2.不会参与dom渲染。
- (function(global,factory){
- // 兼容 cmd
- typeof exports === 'object' && module !== 'undefined' ? module.exports = factory():
- // Amd
- typeof define === 'function' && define.amd ? define(factory) : global.Vue = factory();
- })(this,function(){
- var uip = 0;
- function warn(string){
- console.error('Vue Wran:' + string)
- }
- function warnNonpresent(target,key){
- warn('属性方法'+ key + '未在实例对象上定义,渲染功能正在尝试访问这个不存在的属性!')
- }
- function resolveConstructorOptions(Con){
- var options = Con.options;
- // 判断是否为vm的实例 或者是子类
- return options
- }
- var hasOwnPropeerty = Object.prototype.hasOwnProperty
- function hasOwn(obj , key){
- return hasOwnPropeerty.call(obj,key)
- }
- function makeMap(str, expectsLoweraseC){
- if(expectsLoweraseC){
- str = str.toLowerCase()
- }
- var map = Object.create(null)
- var list = str.split(',')
- for(var i = 0 ; i < list.length; i++){
- map[list[i]] = true
- }
- return function(key){
- return map[key]
- }
- }
- var isbuiltInTag = makeMap('slot,component',true)
- var isHTMLTag = makeMap(
- 'html,body,base,head,link,meta,style,title,' +
- 'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
- 'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
- 'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
- 's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
- 'embed,object,param,source,canvas,script,noscript,del,ins,' +
- 'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
- 'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
- 'output,progress,select,textarea,' +
- 'details,dialog,menu,menuitem,summary,' +
- 'content,element,shadow,template,blockquote,iframe,tfoot'
- );
- var isSVG = makeMap(
- 'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
- 'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
- 'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
- true
- );
- var ASSET_TYPES = [
- 'component',
- 'directive',
- 'filter'
- ];
- var LIFECYCLE_HOOKS = [
- 'beforeCreate',
- 'created',
- 'beforeMount',
- 'mounted',
- 'beforeUpdate',
- 'updated',
- 'beforeDestroy',
- 'destroyed',
- 'activated',
- 'deactivated',
- 'errorCaptured'
- ];
- var isReservedTag = function(key){
- return isHTMLTag(key) || isSVG(key)
- }
- function validataComponentName(key){
- //检测component 的自定义名称是否合格
- // 只能是字母开头或下划线,必须是字母开头
- if(!(/^[a-zA-Z][\w-]*$/g.test(key))){
- warn('组件的名称必须是字母或中横线,必须由字母开头')
- }
- // 1. 不能为内置对象,2.不能是html ,和avg的内部标签
- if( isbuiltInTag(key) || isReservedTag(key)){
- warn('不能为html标签或者avg的内部标签')
- }
- }
- function checkComonpents(child){
- for(var key in child.components){
- validataComponentName(key)
- }
- }
- // 配置对象
- var config = {
- // 自定义的策略
- optionMergeStrategies:{}
- }
- var strats = config.optionMergeStrategies
- strats.el = function(parent,child , key , vm){
- if(!vm){
- warn('选项'+key+'只能在vue实例用使用')
- }
- return defaultStrat(parent,child , key , vm)
- }
- function mergeData(to,form){
- // 终极合并
- if(!form){
- return to
- }
- // 具体合并。
- }
- function mergeDataorFn(parentVal,childVal,vm){
- // 合并 parentVal childVal 都是函数
- if(!vm){
- if(!childVal){
- return parentVal
- }
- if(!parentVal){
- return childVal
- }
- return function mergeDataFn(parentVal,childVal,vm){//只是一个函数 什么样的情况下调用 加入响应式系统
- // 合并子组件对应的data 和 父组件对应的data
- return mergeData(
- typeof parentVal === 'function' ? parentVal.call(this,this) : parentVal, // -----忘记写
- typeof childVal === 'function' ? childVal.call(this,this): childVal) // -----忘记写
- }
- }else{ // vue实例
- return function mergeInstanceDataFn(parentVal,childVal,vm){//只是一个函数 什么样的情况下调用 加入响应式系统
- var InstanceData = typeof childVal === 'function' ? childVal.call(vm,vm): childVal; // -----忘记写
- var defaultData = typeof parentVal === 'function' ? parent.call(vm,vm): parentVal; // -----忘记写
- if(InstanceData){
- return mergeData(parentVal,childVal)
- }else{ // -----忘记写
- defaultData
- }
- }
- }
- }
- strats.data = function(parent,child , key , vm){
- if(!vm){
- // console.log(typeof child === 'function')
- if(child && !(typeof child === 'function')){
- warn('data必须返回是一个function')
- }
- return mergeDataorFn(parent,child)
- }
- return mergeDataorFn(parent,child,vm)
- }
- // 生命周期策略的合并,值等于一个function 如果是有两个,放到一个数组里面。
- function mergeHook(parentVal,childVal,key,vm){
- // console.log(key)
- // console.log(parentVal.concat(childVal) )
- return childVal ? parentVal ? parentVal.concat(childVal):
- Array.isArray(childVal) ? childVal : [childVal] : parentVal
- }
- LIFECYCLE_HOOKS.forEach(function(key){
- strats[key] = mergeHook
- });
- // 检测是否为object
- function isPlainObject(obj){
- return Object.prototype.toString.call(obj) === '[object Object]'
- }
- function assetObjectType(obj){
- if(!isPlainObject(obj)){
- marn('选项的值'+obj+'无效:必须是一个对象的')
- }
- }
- // 对parent实现链式调用。
- function extend(to,form){
- for(key in form){
- to[key] = form[key]
- }
- return to
- }
- // 实现Assets 的策略合并 conmponents filter diretive
- function mergeAssets(parentVal,childVal,key,vm){
- var parent = Object.create(parentVal || null) // 保证子类的每个值的指向都是一个新的object。否则回出现相互引用的现象。
- if(childVal){
- assetObjectType(childVal)
- return extend(parent,childVal)
- }
- return parent
- }
- ASSET_TYPES.forEach(function(key){
- strats[key+'s'] = mergeAssets
- })
- // 实现watch的策略和并,将相同的属性放到一个数组里面。
- strats.watch = function(parentVal,childVal , key , vm){
- if(!childVal){
- return Object.create(parentVal)
- }
- var res = {}
- res = extend(res,parentVal)
- for(var key in childVal){
- var parent = res[key]
- var child = childVal[key]
- res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) :
- Array.isArray(child) ? child : [child] ;
- }
- return res
- }
- // 实现props指令的合并策略
- strats.props = function(parentVal,childVal , key , vm){
- if(!childVal){
- return parentVal
- }
- var res = Object.create( null)
- extend(res,parentVal)
- if(childVal){
- extend(res,childVal)
- }
- return res
- }
- function defaultStrat(parent,child , key , vm){
- return child === undefined ? parent :child ;
- }
- var cmalizeRE = /-(\w)/g
- function camelize(val){
- return val.replace(cmalizeRE,function(c,m){
- return m ? m.toUpperCase(): ""
- })
- }
- function normalizeProps(options){
- var props = options.props
- if(!props){
- return
- }
- var i , val , name
- var res = {}
- if(Array.isArray(props)){
- i = props.length
- while(i--){
- val = props[i]
- if(toString.call(val) === '[object String]'){
- name = camelize(val)
- res[name] = {type: null}
- }else{
- warn('使用数组愈发时props成员' +val+ '必须时一个数组')
- }
- }
- }else if(isPlainObject(props)){
- for(var key in props){
- val = props[key]
- name = camelize(key)
- res[name] = isPlainObject(val) ? val : {type: val}
- }
- }else {
- warn('选项props的值必须是一个对象或者是数组')
- }
- options.props = res
- }
- function mormalizeDirectives(options){
- var dir = options.directives
- var res = {}
- if(!dir){
- return
- }
- if(dir){
- for(var key in dir){
- var val = dir[key]
- var name = camelize(key)
- if(isPlainObject(val)){
- res[name] = val
- }
- if(toString.call(val) === '[object Function]'){
- res[name] = {
- bind: val,
- upata: val
- }
- }
- }
- }
- options.directives = res
- }
- function mergeOptions(parent,child,vm){
- var options = {}
- // 检测是component 是否是合法的
- checkComonpents(child)
- // 规范props
- normalizeProps(child)
- // 规范 dirctives
- mormalizeDirectives(child)
- // console.log(parent, child)
- for(key in parent){
- magerField(key)
- }
- for(key in child){
- if(!hasOwn(parent ,key)){ // parent 中循环过地方不进行循环
- magerField(key) // ----忘记写
- }
- }
- // 默认合并策略
- function magerField(key){
- // 自定义策略 默认策略
- // console.log(key)
- var result = strats[key] || defaultStrat // ---忘记写
- options[key] = result(parent[key],child[key] , key , vm)
- }
- // console.log(options)
- return options
- }
- var allowedGlobals = makeMap(
- 'Infinity,undefined,NaN,isFinite,isNaN,' +
- 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
- 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
- 'require' // for Webpack/Browserify
- );
- function isNative(Ctor){
- return typeof Ctor !== undefined && /native code/.test(toString.call(Ctor))
- }
- var hasproxy = typeof Proxy !== undefined && isNative(Proxy)
- var hasHeadler = {
- has: function(target,key){
- var val = key in target
- // key 是否是全局对象 或者内置方法 _
- var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_')
- if(!val && !isAllowed){
- warnNonpresent(target,key)
- }
- return val || !isAllowed
- }
- }
- var getHeadler = {
- get: function(target,key){
- if( typeof key === 'string' && !(key in target)){
- warnNonpresent(target,key)
- }
- return target[key]
- }
- }
- // 数据代理
- function initProxy(vm){
- var options = vm.$options
- // 判断是否是es6 是否存在Proxy
- if(hasproxy){
- // 渲染函数拦截那些操作。 1. has 查询 2. get 或者
- var headler = options.render && options.render._withStripeed ?
- getHeadler:
- hasHeadler;
- vm._renderPorxy= new proxy(vm,headler)
- }else{
- // 如果不支es6 Proxy
- vm._renderPorxy = vm
- }
- }
- // 初始化当前实例的$children 和$parent 的指向
- function initLifeCycle(vm){
- var options = vm.$options
- // 当前组件 父实例
- var parent = options.parent // 组件的实例对象
- // 是否抽象组件
- if(parent && !parent.abstrat){
- while(parent.$options.abstrat && parent.$parent){
- parent = parent.$options.parent
- }
- parent.$children.push(vm)
- }
- vm.$parent = parent
- vm.$root = parent ? parent.$root : vm;
- vm.$children = [];
- vm.$refs = {};
- vm._watcher = null;
- vm._inactive = null;
- vm._directInactive = false;
- vm._isMounted = false; // 是否挂载
- vm._isDestroyed = false; // 是否销毁
- vm._isBeingDestroyed = false; // 是否正在销毁
- }
- function initMinxin(options){
- Vue.prototype._init = function(options){
- var vm = this
- // 记录生成的vue实例对象
- vm._uip = uip++ // //-------忘记写
- //合并选项
- vm.$options =mergeOptions(resolveConstructorOptions(vm.constructor),options,vm)
- // // 初始化数值代理
- initProxy(vm)
- // 初始化当前实例的$children 和$parent 的指向
- initLifeCycle(vm)
- }
- }
- function Vue(options){
- // 安全机制
- if(!(this instanceof Vue)){ //-------忘记写
- warn('Vue是一个构造函数,必须是由new关键字调用')
- }
- this._init(options)
- }
- initMinxin() // 初始化选项1: 规范 2: 合并策略。
- Vue.options = {
- components: {
- transtions: {},
- keepAlive:{},
- solt:{},
- transtionsGroup:{}
- },
- directives:{},
- _bash: Vue
- }
- function initExend(Vue){
- Vue.extend = function(extendOptions){
- extendOptions = extendOptions || {} // -----忘记写
- var Super = this
- var Child = function VueComponent(options) {
- this._init(options)
- }
- Child.prototype = Object.create(Super.prototype)
- Child.prototype.constructor = Child // 改变constructor 的指向
- Child.options = mergeOptions(Super.options,extendOptions)
- // 子类继承父类的静态方法。
- Child.extend = Vue.extend
- // console.log(new Child({}))
- return Child
- }
- }
- initExend(Vue)
- return Vue
- })
html代码如下
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>第四课</title>
- </head>
- <body>
- <div id="app">
- <huml></huml>
- </div>
- <script src="vue.js"></script>
- <!-- <script src="vue2.5.1.js"></script> -->
- <script type="text/javascript">
- var componentA = {
- el: "#app"
- }
- var vm = new Vue({
- el:"#app",
- data: {
- message: "hello Vue",
- key: "wodow"
- },
- components:{
- humle: componentA
- }
- })
- // console.log(Vue)
- var Parent = Vue.extend({
- data: function() {},
- props: {
- 'rrr': 1
- },
- components:{
- huml: componentA
- },
- created : function(){
- },
- watch: {
- test: function(){}
- }
- })
- var Child = Parent.extend({
- components:{
- humlt: componentA
- },
- created: function(){
- },
- props: {
- 'ddd': 3,
- "dcdc-vfv": Number
- },
- directives: {
- test: {
- bind: function(){}
- },
- test2: function(){}
- },
- watch: {
- aa: function(){},
- test: function(){}
- }
- });
- console.log(vm)
- console.log (Parent.options)
- console.log(Child.options)
- </script>
- </body>
- </html>
【js】 vue 2.5.1 源码学习(六) initProxy initLifeCycle 渲染函数的作用域代理的更多相关文章
- 【js】vue 2.5.1 源码学习 (四) 钩子函数 资源选项 watch 的合并策略
大体思路 (三) 1.钩子函数 自定义策略 LIFECYCLE_HOOKS= [] created = [function(){} , function(){}] 组装方法 ...
- 如何实现全屏遮罩(附Vue.extend和el-message源码学习)
[Vue]如何实现全屏遮罩(附Vue.extend和el-message源码学习) 在做个人项目的时候需要做一个类似于电子相册浏览的控件,实现过程中首先要实现全局遮罩,结合自己的思路并阅读了(饿了么) ...
- Hadoop源码学习笔记(2) ——进入main函数打印包信息
Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...
- 【js】 vue 2.5.1 源码学习(十二)模板编译
大体思路(十) 本节内容: 1. baseoptions 参数分析 2. options 参数分析 3. parse 编译器 4. parseHTNL 函数解析 // parse 解析 parser- ...
- 【js】vue 2.5.1 源码学习 (十一) 模板编译compileToFunctions渲染函数
大体思路(九) 本节内容: 1. compileToFunctions定位 1. compileToFunctions定位 ==> createCompiler = createCompiler ...
- 【js】vue 2.5.1 源码学习 (十) $mount 挂载函数的实现
大体思路(九) 本节内容: 1. $mount 挂载函数的实现. // 将Vue.prototype.$mount 缓存下来 ==>mountComponet(this,el) { // 组建挂 ...
- 【js】vue 2.5.1 源码学习 (九) 响应数组对象的变
大体思路(八) 本节内容: 1.Observe 如何响应数组的变化 代理原型 数组变异方法 shell cacheArrProto methods 新添加的数组需要加到显示系统里面,拦截 push等的 ...
- 【js】Vue 2.5.1 源码学习 (八)响应式入口observe
大体思路(七) 本节内容: deps 依赖收集的数组对象 => Dep 构造函数 /** ==> observe() * var ob * ==> if --isObject * = ...
- 【js】vue 2.5.1 源码学习 (七) 初始化之 initState 响应式系统基本思路
大体思路(六) 本节内容: 一.生命周期的钩子函数的实现 ==> callHook(vm , 'beforeCreate') beforeCreate 实例创建之后 事件数据还未创建 二.初始化 ...
随机推荐
- UE4 Pak 相关知识总结
转载自:https://arcecho.github.io/2017/07/02/UE4-Pak-%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB ...
- 【JZOJ4929】【NOIP2017提高组模拟12.18】B
题目描述 在两个n*m的网格上染色,每个网格中被染色的格子必须是一个四联通块(没有任何格子被染色也可以),四联通块是指所有染了色的格子可以通过网格的边联通,现在给出哪些格子在两个网格上都被染色了,保证 ...
- utf8mb4 使用注意
数据库的表的定义如果是utf8mb4的富文本时,关联的字段必须指定为非utf8,否则 跟其他的表关联的时候,会非常慢,以至于索引都不能使用. 也就是必须的字段才可以使用这个 utf8mb4 ,否则检索 ...
- phonegap支付宝2.0移动快捷支付插件IOS版
坑爹的支付宝,一两年都没有更新sdk了,这两天突然更新sdk,而且更新的变化特别大,所以只能对之前的支付宝快捷支付插件重新写了一遍. 这样既顺应了支付宝的更新,同时也支持了ios8. 废话少说,集成过 ...
- 比较全面的一个PHP缓存类解析
转自:http://www.blhere.com/1164.html 一.引论 PHP,一门最近几年兴起的web设计脚本语言,由于它的强大和可伸缩性,近几年来得到长足的发展,php相比传统的asp网站 ...
- 【JZOJ4884】【NOIP2016提高A组集训第12场11.10】图的半径
题目描述 mhy12345学习了树的直径,于是开始研究图的半径,具体来说,我们需要在图中选定一个地方作为中心,其中这个中心有可能在路径上. 而这个中心的选址需要能够使得所有节点达到这个中心的最短路里面 ...
- 开窗函数over()中partition by关键字解析
partition by关键字是分析性函数的一部分,它和聚合函数不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录,partition by用于给结果集分组,如果没 ...
- MaxCompute 图计算用户手册(下)
示例程序 强连通分量 在有向图中,如果从任意一个顶点出发,都能通过图中的边到达图中的每一个顶点,则称之为强连通图.一张有向图的顶点数极大的强连通子图称为强连通分量.此算法示例基于 parallel C ...
- 新xcode的literal syntax是什么
New Objective-C Literal Syntax for NSArray, NSDictionary 是以@字符开始的方式简单地创建数组.字典.NSNumber常量. 代码如下: NSNu ...
- oralce CUBE
select id,area,stu_type,sum(score) score from students group by cube(id,area,stu_type) order by id,a ...