在用creator开发中,经常会遇到小功能或者一些小界面,比如说简单的排行榜Item,只有头像Sprite和几个Label。我们当然可以新建个预制和Component来单独处理它们,但这些往往只有几行代码的js多了后我们经常会不想新建文件,而是内嵌在父节点中,比如以下代码,Item单独拿出来只有三行代码
//RankListLayer.js
updateList: function(rankData) {
for(let i = 0; i < rankData.length; i++) {
let itemData = rankData[i]
let rankItem = cc.instantiate(this.rankItemPre)
rankItem.parent = this.listContent
rankItem.getChildByName("rank").getComponent(cc.Label).string = itemData.rank
rankItem.getChildByName("name").getComponent(cc.Label).string = itemData.name
rankItem.getComponentInChildren(cc.Sprite).spriteFrame = itemData.iconFrame
//item单独拿出的话
//rankItem.getComponent("RankItem").updateView(itemData)
}
}
内嵌在父节点中的话,getChildByName和getComponentInChildren这种就跟creator中的节点树和节点名耦合性略高了。下面的代码就是要分享的解耦这部分的功能
//为节点添加属性
let NodeAttrStruct = cc.Class({
name: "NodeAttrStruct",
properties: {
keyName: {
default: "",
tooltip: "字段名包含Btn,Label,Spr会转为相应的组件,否则为Node"
},
valNode: cc.Node,
}
})
cc.Class({
extends: cc.Component,
properties: {
attrStruct: [NodeAttrStruct],
},
onLoad: function() {
let attrData = {}
for(let i = 0; i < this.attrStruct.length; i++) {
let itemStruct = this.attrStruct[i]
let keyName = itemStruct.keyName
let valNode = itemStruct.valNode
if(!valNode) {
continue
}
if(keyName.indexOf("Btn") != -1) {
attrData[keyName] = valNode.getComponent(cc.Button)
} else if(keyName.indexOf("Label") != -1) {
attrData[keyName] = valNode.getComponent(cc.Label)
} else if(keyName.indexOf("Spr") != -1) {
attrData[keyName] = valNode.getComponent(cc.Sprite)
} else {
attrData[keyName] = valNode
}
}
//使用attr为节点附加属性
this.node.attr(attrData)
}
})
以最初的代码为例,挂载此脚本到Rankitem上,添加三个属性值,拖对应节点上去

然后代码就可以变为
updateList: function(rankData) {
for(let i = 0; i < rankData.length; i++) {
let itemData = rankData[i]
let rankItem = cc.instantiate(this.rankItemPre)
rankItem.parent = this.listContent //要先添加到节点树触发onLoad
rankItem.rankLabel.string = itemData.rank //字段名为挂载的组件上定义的
rankItem.nameLabel.string = itemData.name
rankItem.iconSpr.spriteFrame = itemData.iconFrame
//rankItem.getChildByName("rank").getComponent(cc.Label).string = itemData.rank
//rankItem.getChildByName("name").getComponent(cc.Label).string = itemData.name
//rankItem.getComponentInChildren(cc.Sprite).spriteFrame = itemData.iconFrame
//item单独拿出的话
//rankItem.getComponent("RankItem").updateView(itemData)
}
}
其实这样还是有关联,但是字段名相比于节点树结构和节点名来说,几乎可以算是不会修改。算是解耦一半吧。