如何优雅的获取脚本组件?

难道只能用node.getComponent(‘scriptName’) 这种硬代码吗?有没有什么更好的方案呢?

3赞

属性声明也可以这样写
scriptName:require(‘scriptName’)

this.scriptName.fun();

关键是动态加载prefab的时候,需要获取到script来初始化prefab,这种写法没有用

老实说,我觉得可以强烈建议开发组,把获取脚本组件写的更方便一点,比如:我相信绝大多数情况下99%,node上面应该都只绑定了一个脚本,那引擎组能不能提供一个接口,node.getXX()或者直接.xxx直接返回第一个脚本组件呢,如果想要要返回指定的组件,再传参数也行啊,说真的好多时候,写这个梗我也觉得好蛋疼
获取其他组件倒还好,因为同类型组件只有一个,还不算显得特别烦,但是脚本组件我真的不关心这个名字

3赞

建议用typescript.

这个是一个自定义组件:

声明属性后可以在IDE里直接拖拽绑定组件(这点javascript应该也能做到?),这个是从官方组件里启发到的,既然都是Component那么自己写的应该也可以拖拽过去。。

用代码获取的话,感觉比js优雅多了,这样子:

直接使用类名获取就行,重构方便多了。

我没用过js写,一开始就用的ts,只能说提示、重构什么的很方便。

1赞

你这个写法应该不行,不可能每个界面你都去创建一个单独的类来处理吧,没有实际意义啊。 你这里的CardComponent实际上跟cc.Lable,cc.Sprite这些是一样的 就跟楼上说的,很多时候我不关心这个script的名字,我只是需要获取他来执行初始化而已

你试试看这样写

//some.js 

cc.class({
        properties: {
             //..........
        },

       onLoad: function(){
        
       },

       init: function(){

       }
       onEnable: function(){
               this.node.a = this;
       }

})

然后把some.js挂载的prefab,然后实例化prefab,在把实例化后的prefab添加到某一节点的时候会执行onEnable,需要注意的是每次修改节点的active = true时都会调用onEnable,如果只需要调用一次初始化方法,则把onEnable的代码放在onLoad或者start阶段,并且,我这样做需要先把实例化后的节点添加到某一个节点才会执行onLoad或者onEnable,如果你需要在添加之前就进行初始化则我这个办法行不通

 var node = cc.instantiate(prefab);
 parentNode.addChild(node);
 node.a.init();

这种方案倒是不错,把脚本实例挂到node上,类似于this.component.node的写法
不过这样会导致互相引用,无法销毁吧?

不知道诶:joy:

你看下这是你想要的方案么
http://forum.cocos.com/t/uikiller/51008

你这个拖拽感觉没啥意义,我们现在都是import 把想关的类导进来,getComponent的时候为了方便提示在前面标注了下,现在是这个getComponent(xxx)比较恶心,很多时候我们只想要其中的一个脚本,但是却要我传类名,这有点蹩脚

1赞

拖拽是我现在最反感的操作,我估计你没看完

刚看了下,应该不是。你这里的绑定其实类似于简写,在你这里还是要变成node.$scriptName
其实类似3L说的, 加载一个node(prefab)的时候上面一般会挂一个脚本用来处理Node的相关设置,
一般的做法就是
var node = cc.instantiate(prefab);
var script = node.getComponent(‘scrpitName’);
script.init(xxx);
这样来处理
先说下为什么这样处理,因为有些时候你需要传参数进去,而onLoad() 这些引擎自带的生命周期函数是无法传参数的
但是这样就会导致你的代码里面会有很多的scriptName 这种硬代码,当然你可以用宏来处理,
我现在是想有没有什么方案能更方便的处理这种情况

1赞

你可以尝试向node发消息,在component中监听处理,这样就不会有你说的硬编码了
不过你需要先把prefab节点给addChild,不然无机会监听节点事件

cc.Class({
...
    onLoad() {
        this.node.on('init', (event) =>  this.init(event.detail) );
    } 
})
--------------------------------------
var node = cc.instantiate(prefab);
this.node.addChild(node);
node.emit('init', xxx) //不会再有你的硬编码了

这样能解决你的问题了吗?

如果你想再懒一点,给node做一个init函数

cc.Node.prototype.init = function(xxx) {
    this.emit('init', xxx);
}

var node = cc.instantiate(prefab);
this.node.addChild(node);
node.init();

这种方式确实不错,利用事件来处理,受教了,多谢

不客气,相互学习, 你的这种需求也启发了我!

楼主的这种思路非常好的

  1. 外部调用统一,代码整洁
  2. 减少require,减少模块之间的引用
    少敲一个字就可以早一点下班!用多的时间来论坛聊天,我要下班了!

如果不关心组件类型,this.getComponent(cc.Component)就可以获得第一个组件。不管它是什么组件,肯定继承cc.Component。如果需要执行上面的init,则:

let comp = this.getComponent(cc.Component);
if (comp && comp.init) {
    comp.init();
}
2赞

这才是我想要的答案…
另外,我想说官方例子真的不是个好例子,一直都是“className"来取,否则也不会有这种疑惑

真的是办法比问题多:relaxed: