IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue高级 -> 正文阅读

[JavaScript知识库]Vue高级

插槽-Slot

  • 默认插槽:子组件用来slot标签确定渲染的位置,标签内可以正常写dom结构,当时父组件没有往插槽中插入内容时默认展示slot标签内的内容
    Vue.component('button-counter', {
     template: '<div> <slot>我是默认内容</slot></div>'
    })
    
    new Vue({
     el: '#app',
     template: '<button-counter><span>我是slot传?内容</span></button-counter>',
     components:{buttonCounter}
    })
    
  • 具名插槽:子组件在使用slot标签时定义了slot标签的name属性,在父组件使用的时候就可以根据插槽的名字往具体插槽插入内容
    Vue.component('button-counter', {
     template:
      '<div> 
     	<slot>我是默认内容</slot>
     	<slot name='center'>我是默认中间内容</slot>
     	<slot name='buttom'>我是默认底部内容</slot>
       </div>'
    })
    
    new Vue({
     el: '#app',
     template: '<button-counter><span slot='bottom'>我是slot传?的底部内容</span></button-counter>',
     components:{buttonCounter}
    })
    
  • 插槽的实现原理:
    slot本质上是返回VNode的函数,?般情况下,Vue中的组件要渲染到??上需要经过template -> render function -> VNode DOM 过程。
    ?如?个带slot的组件
    Vue.component('button-counter', {
     template: '<div> <slot>我是默认内容</slot></div>'
    })
    new Vue({
     el: '#app',
     template: '<button-counter><span>我是slot传?内容</span></button-counter>',
     components:{buttonCounter}
    })
    

经过vue编译, 组件渲染函数会变成这样

(function anonymous( ) {
	with(this){return _c('div',[_t("default",[_v("我是默认内容")])],2)}
})

?这个_t就是slot渲染函数:

function renderSlot (name, fallback, props, bindObject) {
	 // 得到渲染插槽内容的函数 
	 var scopedSlotFn = this.$scopedSlots[name];
	 var nodes;
	 // 如果存在插槽渲染函数,则执?插槽渲染函数,?成nodes节点返回
	 // 否则使?默认值
	 nodes = scopedSlotFn(props) || fallback;
	 return nodes;
}

?scopedSlots其实就是递归解析各个节点, 获取slot:

function resolveSlots(children,context) {
	if (!children || !children.length) {
		return {}
	}
	var slots = {};
	for (var i = 0, l = children.length; i < l; i++) {
		var child = children[i];
		var data = child.data;
		// remove slot attribute if the node is resolved as a Vue slot node
		if (data && data.attrs && data.attrs.slot) {
			delete data.attrs.slot;
		}
		// named slots should only be respected if the vnode was rendered in the
		// same context.
		if ((child.context === context || child.fnContext === context) &&
			data && data.slot != null
		) {
			// 如果slot存在(slot="header") 则拿对应的值作为key
			var name = data.slot;
			var slot = (slots[name] || (slots[name] = []));
			// 如果是tempalte元素 则把template的children添加进数组中,这也就是为什么你写的
			//template标签并不会渲染成另?个标签到??
			if (child.tag === 'template') {
				slot.push.apply(slot, child.children || []);
			} else {
				slot.push(child);
			}
		} else {
			// 如果没有就默认是default
			(slots.default || (slots.default = [])).push(child);
		}
	}
	// ignore slots that contains only whitespace
	for (var name$1 in slots) {
		if (slots[name$1].every(isWhitespace)) {
			delete slots[name$1];
		}
	}
	return slots
}

Vue插槽实现原理

混入-Mixin

本质其实就是?个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等
Tips

  • 当组件存在与mixin对象相同的数据的时候,进?递归合并的时候组件的数据会覆盖mixin的数据
  • 如果相同数据为?命周期钩?的时候,会合并成?个数组,先执?mixin的钩?,再执?组件的钩?

mixin的实现原理

  • 优先递归处理 mixins
  • 先遍历合并parent 中的key,调?mergeField?法进?合并,然后保存在变量options
  • 再遍历 child,合并补上 parent 中没有的key,调?mergeField?法进?合并,保存在变量
    options
  • 通过 mergeField 函数进?了合并
export function mergeOptions(parent: Object, child: Object, vm?: Component): Object {
   if (child.mixins) { // 判断有没有mixin 也就是mixin??挂mixin的情况 有的话递归进?合并
      for (let i = 0, l = child.mixins.length; i < l; i++) {
         parent = mergeOptions(parent, child.mixins[i], vm)
      }
   }
   const options = {}
   let key
   for (key in parent) {
      mergeField(key) // 先遍历parent的key 调对应的strats[XXX]?法进?合并
   }
   for (key in child) {
      if (!hasOwn(parent, key)) { // 如果parent已经处理过某个key 就不处理了
         mergeField(key) // 处理child中的key 也就parent中没有处理过的key
      }
   }
   function mergeField(key) {
      const strat = strats[key] || defaultStrat
      options[key] = strat(parent[key], child[key], vm, key) // 根据不同类型的options调?strats中不同的?法进?合并
   }
   return options
}

其实主要的逻辑就是合并mixin和当前组件的各种数据, 细分为四种策略:

  • 替换型策略 - 同名的props、methods、inject、computed会被后来者代替
strats.props =
   strats.methods =
   strats.inject =
   strats.computed = function (
      parentVal: ?Object,
      childVal: ?Object,
      vm?: Component,
      key: string
   ): ?Object {
      if (!parentVal) return childVal // 如果parentVal没有值,直接返回childVal
      const ret = Object.create(null) // 创建?个第三?对象 ret
      extend(ret, parentVal) // extend?法实际是把parentVal的属性复制到ret中
      if (childVal) extend(ret, childVal) // 把childVal的属性复制到ret中
      return ret
   }
  • 合并型策略 - data, 通过set?法进?合并和重新赋值
strats.data = function (parentVal, childVal, vm) {
	return mergeDataOrFn(
		parentVal, childVal, vm
	)
};
function mergeDataOrFn(parentVal, childVal, vm) {
	return function mergedInstanceDataFn() {
		var childData = childVal.call(vm, vm) // 执?data挂的函数得到对象
		var parentData = parentVal.call(vm, vm)
		if (childData) {
			return mergeData(childData, parentData) // 将2个对象进?合并 
		} else {
			return parentData // 如果没有childData 直接返回parentData
		}
	}
}
function mergeData(to, from) {
	if (!from) return to
	var key, toVal, fromVal;
	var keys = Object.keys(from);
	for (var i = 0; i < keys.length; i++) {
		key = keys[i];
		toVal = to[key];
		fromVal = from[key];
		// 如果不存在这个属性,就重新设置
		if (!to.hasOwnProperty(key)) {
			set(to, key, fromVal);
		}
		// 存在相同属性,合并对象
		else if (typeof toVal == "object" && typeof fromVal == "object") {
			mergeData(toVal, fromVal);
		}
	}
	return to
}
  • 队列型策略 - ?命周期函数和watch,原理是将函数存??个数组,然后正序遍历依次执?
function mergeHook(
	parentVal: ?Array<Function>,
	childVal: ?Function | ?Array<Function>
): ?Array<Function> {
	return childVal
		? parentVal
			? parentVal.concat(childVal)
			: Array.isArray(childVal)
				? childVal
				: [childVal]
		: parentVal
}
LIFECYCLE_HOOKS.forEach(hook => {
	strats[hook] = mergeHook
})
  • 叠加型策略 - component、directives、filters,通过原型链进?层层的叠加
strats.components=
strats.directives=
strats.filters = function mergeAssets(
 parentVal, childVal, vm, key
) { 
 var res = Object.create(parentVal || null); 
 if (childVal) {
 for (var key in childVal) {
 res[key] = childVal[key];
 } 
 }
 return res
}

插件-Plugin

插件就是指对Vue的功能的增强或补充

  1. 什么是插件? 如何编写?个插件?
MyPlugin.install = function (Vue, options) {
	// 1. 添加全局?法或 property
	Vue.myGlobalMethod = function () {
		// 逻辑...
	}
	// 2. 添加全局资源
	Vue.directive('my-directive', {
		bind(el, binding, vnode, oldVnode) {
			// 逻辑...
		}
	...
	})
	// 3. 注?组件选项
	Vue.mixin({
		created: function () {
			// 逻辑...
		}
	...
	})
	// 4. 添加实例?法
	Vue.prototype.$myMethod = function (methodOptions) {
		// 逻辑...
	}
}
Vue.use(plugin, options);
  1. Vue.use做了什么?
    判断当前插件是否已经安装过, 防?重复安装
    处理参数, 调?插件的install?法, 第?个参数是Vue实例
import { toArray } from '../util/index'
export function initUse(Vue: GlobalAPI) {
	Vue.use = function (plugin: Function | Object) {
		const installedPlugins = (this._installedPlugins || (this._installedPlugins
			= []))
		if (installedPlugins.indexOf(plugin) > -1) {
			return this
		}
		// additional parameters
		const args = toArray(arguments, 1)
		args.unshift(this)
		if (typeof plugin.install === 'function') {
			plugin.install.apply(plugin, args)
		} else if (typeof plugin === 'function') {
			plugin.apply(null, args)
		}
		installedPlugins.push(plugin)
		return this
	}
}
``
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-08 13:54:34  更:2022-01-08 13:56:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:00:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码