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

你可以尝试向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:

这里第一个组件有可能是ui组件,这就有一些规则限定了,在多人开发的时候会带来一些成本

这就错了,一般这种脚本是不会被require的,都是挂到节点上的

你可以定义一个组件 Script,项目里所有需要快速获取的组件,都继承自这个组件,这个组件注册为插件脚本,保证全局变量会被先注册

window.Script = cc.Class({
  extends: cc.Component
});
cc.js.get(cc.Node.prototype, 'script', function () {
  return this.getComponent(Script);
});

然后把项目里继承自 cc.Component 的地方全部改成 Script。(为了让你避免获取到 UI 组件)


需要获取组件时,

var node = cc.instantiate(prefab);
node.script.init();

这样就行啦,零 require,零所谓的硬代码

我十分认同 @zxh19821 的 uikiller 这类封装,但是不太赞同把这种封装这么早集成到引擎里。 正如大家所回复的,JS 是门十分灵活的语言,一千个人可能有一千种封装,封装的越抽象可能副作用越大,大家各取所需即可。如果社区将来摸索出了一套统一的,经受住时间考验的框架(类似 jQuery),那引擎也是会欢迎作者提交 PR 集成进来的。

4赞

赞同这个,没有统一的标准,弄的太乱,让新手更摸不着头脑

更喜欢这样的代码,动态语言的优雅。

刚测试了下,可行,原理其实就是把getComponent函数注册到node上,通过这种方式来快速获取脚本组件,这种方案目前来看确实是最优的

这个方法只能获得一个脚本。局限性比较大。其实方法还有很多,大家可以自己变通。

1赞

上面说的方法只能获得一个脚本,主要是满足了这个同学的需要,局限性比较大。其实方法还有很多,大家可以自己变通。

当然,程序员如果真的能假定节点上只有一个脚本,那允许 node.getComponent() 直接返回第一个组件似乎也没问题。
不过如果太依赖这种写法,似乎又容易自己坑到自己(谁知道场景会不会被其它人玩坏),所以还是像 @toddlxt 推荐的那样显式传入一个 node.getComponent(cc.Component) 吧。多写点难看的代码一般人会比较清楚自己在做什么。

2赞

这样的写法遇到一个bug,1.6.1,macOS Sierra 10.12.5

//NodeExtend.js
window._nodeExtendMath = {
    // 随机一个int [min, max]
    randomInt: function (min, max) {
        if (min === max) return min;
        return min + Math.floor(Math.abs(Math.random() * (max + 1 - min)));
    }
};
cc.js.get(cc.Node.prototype, 'math', function () {
    return _nodeExtendMath;
});
// console error
2017-09-15T03:41:16.886Z - normal: connected!
2017-09-15T03:41:20.986Z - normal: 1.6.1
2017-09-15T03:41:42.737Z - error: TypeError: Cannot redefine property: math
    at Object.js.get (/Applications/CocosCreator.app/Contents/Resources/engine/cocos2d/core/platform/js.js:280:12)
    at disable-commonjs:///Users/webb/Desktop/selfDoc/never-touch/assets/script/NodeExtend.js?002:8:7
    at disable-commonjs:///Users/webb/Desktop/selfDoc/never-touch/assets/script/NodeExtend.js?002:11:3

问题是这样出现的,NodeExtend.js 勾选 导入为插件允许web允许浏览器允许Native
第一次打开creator不会有问题。当我修改_NodeExtend.js_ 再回到creator 必现这个报错。

不要允许 creator 即可,或者 cc.js.get(…, ‘math’, function () {…}, false, true);

我可以这样理解吗?这样动态添加属性到cc.Node上会影响编辑器的属性检查器?还是别的原因?

因为Creator是经常刷新的,比如你改了点代码,它就刷新一下,然后你的插件脚本就又执行了一次。估计cc.js.get内部使用Object.defineProperty定义你的math属性的时候,默认把configurable设置成了false(不能再次定义)。所以一旦Creator刷新,再次执行插件重新定义math,就会报错。@jare老师让你在cc.js.get后面多传一个false,true,应该就是设置configurable为true的意思。跟属性检查器没啥关系。你也可以把cc.js.get自己写成:

Object.defineProperty(cc.Node.prototype, 'math', {
  get: function(){
    return _nodeExtendMath;
  },
  configurable: true
});
1赞