前言
本文基于 Cocos Creator 2.4.5 撰写。
🎉 普天同庆
来了来了,《源码解读》系列文章终于又来了!
👾 温馨提醒
本文包含大段引擎源码,使用大屏设备阅读体验更佳!
Hi There!
节点(cc.Node)作为 Cocos Creator 引擎中最基本的单位,所有组件都需要依附在节点上。
同时节点也是我们日常开发中接触最频繁的东西。
我们经常会需要「改变节点的排序」来完成一些效果(如图像的遮挡)。
A Question?
😕 你有没有想过:
节点的排序是如何实现的?
Oops!
🤯 我在分析了源码后发现:
节点的排序并没有想象中那么简单!
😹 渣皮语录
听皮皮一句劝,zIndex 的水太深,你把握不住!
正文
节点顺序 (Node Order)
🤔 如何修改节点的顺序?
首先,在 Cocos Creator 编辑器中的「层级管理器」中,我们可以随意拖动节点来改变节点的顺序。
🤨 但是,在代码中我们要怎么做呢?
我最先想到的是节点的 setSiblingIndex
函数,然后是节点的 zIndex
属性。
我猜大多数人都不清楚这两个方案有什么区别。
那么接下来就让我们深入源码,一探究竟!
siblingIndex
「siblingIndex」即「同级索引」,意为「同一父节点下的兄弟节点间的位置」。
siblingIndex 越小的节点排越前,索引最小值为 0
,也就是第一个节点的索引值。
需要注意的是,实际上节点并没有 siblingIndex 属性,只有 getSiblingIndex
和 setSiblingIndex
这两个相关函数。
注:本文统一使用 siblingIndex 来代指 getSiblingIndex
和 setSiblingIndex
函数。
另外,getSiblingIndex
和 setSiblingIndex
函数是由 cc._BaseNode
实现的。
💡 cc._BaseNode
大家对这个类可能会比较陌生,简单来说
cc._BaseNode
是cc.Node
的基类。此类「定义了节点的基础属性和函数」,包括但不仅限于
setParent
、addChild
和getComponent
等常用函数…
📝 源码节选:
函数:cc._BaseNode.prototype.getSiblingIndex
getSiblingIndex() {
if (this._parent) {
return this._parent._children.indexOf(this);
} else {
return 0;
}
},
函数:cc._BaseNode.prototype.setSiblingIndex
setSiblingIndex(index) {
if (!this._parent) {
return;
}
if (this._parent._objFlags & Deactivating) {
return;
}
var siblings = this._parent._children;
index = index !== -1 ? index : siblings.length - 1;
var oldIndex = siblings.indexOf(this);
if (index !== oldIndex) {
siblings.splice(oldIndex, 1);
if (index < siblings.length) {
siblings.splice(index, 0, this);
} else {
siblings.push(this);
}
this._onSiblingIndexChanged && this._onSiblingIndexChanged(index);
}
},
[源码] base-node.js#L514: https://github.com/cocos-creator/engine/blob/2.4.5/cocos2d/core/utils/base-node.js#L514
🕵️ 做了什么?
扒拉源码后发现,siblingIndex 的本质其实很简单。
那就是「当前节点在父节点的 _children
属性中的下标(位置)」。
getSiblingIndex
函数返回的是「当前节点在父节点的 _children
属性中的下标(位置)」。
setSiblingIndex
函数则是设置「当前节点在父节点的 _children
属性中的下标(位置)」。
💡
cc._BaseNode.prototype._children
节点的
_children
属性其实就是节点的children
属性。而
children
属性是一个getter
,返回的是自身的_children
属性。另外
children
属性没有实现setter
,所以你直接给children
属性赋值是无效的。