[Init]Init commit
This commit is contained in:
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
|
||||
export interface IDisposer {
|
||||
(): void
|
||||
}
|
||||
import { LocalEmitter } from "../external/LocalEmitter";
|
||||
|
||||
const { ccclass, property } = cc._decorator;
|
||||
|
||||
@ccclass
|
||||
export default class BaseComp extends cc.Component {
|
||||
|
||||
_comp_id_: number = LocalEmitter.newCompId();
|
||||
|
||||
protected _pool: Array<IDisposer> = []
|
||||
|
||||
_frameCount = 0;
|
||||
_frameLimit = 3;
|
||||
|
||||
canUpdate(){
|
||||
this._frameCount++;
|
||||
if(this._frameCount < this._frameLimit){
|
||||
return false;
|
||||
}
|
||||
|
||||
this._frameCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
getCompId() {
|
||||
return this._comp_id_;
|
||||
}
|
||||
|
||||
//注册监听
|
||||
on(event: string, fn: Function) {
|
||||
LocalEmitter.inst.on(this.getCompId(), event, fn);
|
||||
}
|
||||
|
||||
//移除监听
|
||||
off(event: string = null, fn: Function = null) {
|
||||
LocalEmitter.inst.off(this.getCompId(), event, fn);
|
||||
}
|
||||
|
||||
// 发送事件
|
||||
emit(event: string = null, obj: any = null, obj2: any = null) {
|
||||
LocalEmitter.inst.emit(event, obj, obj2);
|
||||
}
|
||||
|
||||
initListener(config:{[key:string]:number}){
|
||||
for(let key in config){
|
||||
this.on(config[key].toString(), this[key].bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.removeAllListeners();
|
||||
}
|
||||
|
||||
removeAllListeners(){
|
||||
LocalEmitter.inst.off(this.getCompId());
|
||||
}
|
||||
|
||||
showPopWait(msg: string = "Vui lòng chờ..."): void {
|
||||
LocalEmitter.inst.emit("showPopWait",{prompt:msg})
|
||||
}
|
||||
|
||||
hidePopWait(): void {
|
||||
LocalEmitter.inst.emit("hidePopWait")
|
||||
}
|
||||
|
||||
mute(){
|
||||
this._pool && this._pool.forEach((d) => d())
|
||||
this._pool = [];
|
||||
}
|
||||
|
||||
onDisable(){
|
||||
this.mute();
|
||||
|
||||
}
|
||||
|
||||
onEnable(){
|
||||
this.mute();
|
||||
}
|
||||
|
||||
//加载图片资源
|
||||
loadSpriteFrame(PrefabUrl, fun: Function): void {
|
||||
cc.resources.load(PrefabUrl, cc.SpriteFrame, function (err, res) {
|
||||
//检查资源加载
|
||||
if (err) {
|
||||
return
|
||||
}
|
||||
|
||||
if (fun) {
|
||||
fun(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "a03bb1c4-40fd-4523-98d8-56698a9cd3cb",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @packageDocumentation
|
||||
* @module ui
|
||||
*/
|
||||
|
||||
import { CustomToggle } from './CustomToggleItem'
|
||||
|
||||
const { property, ccclass, help, executeInEditMode, executionOrder, menu } = cc._decorator
|
||||
|
||||
/**
|
||||
* @en
|
||||
* ToggleContainer is not a visible UI component but a way to modify the behavior of a set of Toggles. <br/>
|
||||
* Toggles that belong to the same group could only have one of them to be switched on at a time.<br/>
|
||||
* Note: All the first layer child node containing the toggle component will auto be added to the container.
|
||||
*
|
||||
* @zh
|
||||
* ToggleGroup 不是一个可见的 UI 组件,它可以用来修改一组 Toggle 组件的行为。当一组 Toggle 属于同一个 ToggleGroup 的时候,<br/>
|
||||
* 任何时候只能有一个 Toggle 处于选中状态。
|
||||
*/
|
||||
|
||||
@ccclass
|
||||
@executionOrder(110)
|
||||
@menu('UI/CustomToggleGroup')
|
||||
@executeInEditMode
|
||||
export class CustomToggleGroup extends cc.Component {
|
||||
@property(cc.Boolean)
|
||||
protected _allowSwitchOff = false
|
||||
/**
|
||||
* @en
|
||||
* If this setting is true, a toggle could be switched off and on when pressed.
|
||||
* If it is false, it will make sure there is always only one toggle could be switched on
|
||||
* and the already switched on toggle can't be switched off.
|
||||
*
|
||||
* @zh
|
||||
* 如果这个设置为 true,那么 toggle 按钮在被点击的时候可以反复地被选中和未选中。
|
||||
*/
|
||||
|
||||
@property({ tooltip: 'i18n:toggle_group.allowSwitchOff' })
|
||||
get allowSwitchOff() {
|
||||
return this._allowSwitchOff
|
||||
}
|
||||
|
||||
set allowSwitchOff(value) {
|
||||
this._allowSwitchOff = value
|
||||
}
|
||||
|
||||
/**
|
||||
* @en
|
||||
* If Toggle is clicked, it will trigger event's handler.
|
||||
*
|
||||
* @zh
|
||||
* Toggle 按钮的点击事件列表。
|
||||
*/
|
||||
@property({ type: [cc.Component.EventHandler], tooltip: 'i18n:toggle_group.check_events' })
|
||||
public checkEvents: cc.Component.EventHandler[] = []
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Read only property, return the toggle items array reference managed by ToggleContainer.
|
||||
*
|
||||
* @zh
|
||||
* 只读属性,返回 toggleContainer 管理的 toggle 数组引用。
|
||||
*/
|
||||
get toggleItems() {
|
||||
return this.node.children
|
||||
.map((item) => {
|
||||
const toggle = item.getComponent(CustomToggle)
|
||||
if (toggle && toggle.enabled) {
|
||||
return toggle
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
public onEnable() {
|
||||
this.ensureValidState()
|
||||
this.node.on(cc.Node.EventType.CHILD_ADDED, this.ensureValidState, this)
|
||||
this.node.on(cc.Node.EventType.CHILD_REMOVED, this.ensureValidState, this)
|
||||
}
|
||||
|
||||
public onDisable() {
|
||||
this.node.off(cc.Node.EventType.CHILD_ADDED, this.ensureValidState, this)
|
||||
this.node.off(cc.Node.EventType.CHILD_REMOVED, this.ensureValidState, this)
|
||||
}
|
||||
|
||||
public activeToggles() {
|
||||
return this.toggleItems.filter((x) => x!.isChecked)
|
||||
}
|
||||
|
||||
public anyTogglesChecked() {
|
||||
return !!this.toggleItems.find((x) => x!.isChecked)
|
||||
}
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Refresh the state of the managed toggles.
|
||||
*
|
||||
* @zh
|
||||
* 刷新管理的 toggle 状态。
|
||||
*
|
||||
* @param toggle - 需要被更新的 toggle。
|
||||
* @param emitEvent - 是否需要触发事件
|
||||
*/
|
||||
public notifyToggleCheck(toggle: CustomToggle, emitEvent = true) {
|
||||
if (!this.enabledInHierarchy) {
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.toggleItems.length; i++) {
|
||||
const item = this.toggleItems[i]!
|
||||
if (item === toggle) {
|
||||
continue
|
||||
}
|
||||
if (emitEvent) {
|
||||
item.isChecked = false
|
||||
} else {
|
||||
item.setIsCheckedWithoutNotify(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.checkEvents) {
|
||||
cc.Component.EventHandler.emitEvents(this.checkEvents, toggle)
|
||||
}
|
||||
}
|
||||
|
||||
public ensureValidState() {
|
||||
|
||||
const toggles = this.toggleItems
|
||||
if (!this._allowSwitchOff && !this.anyTogglesChecked() && toggles.length !== 0) {
|
||||
const toggle = toggles[0]!
|
||||
toggle.isChecked = true
|
||||
this.notifyToggleCheck(toggle)
|
||||
}
|
||||
|
||||
const activeToggles = this.activeToggles()
|
||||
if (activeToggles.length > 1) {
|
||||
const firstToggle = activeToggles[0]
|
||||
for (let i = 0; i < activeToggles.length; ++i) {
|
||||
const toggle = activeToggles[i]
|
||||
if (toggle === firstToggle) {
|
||||
continue
|
||||
}
|
||||
toggle!.isChecked = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "9e433cb7-86b6-4361-8b44-5e13446638fc",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @packageDocumentation
|
||||
* @module ui
|
||||
*/
|
||||
|
||||
import { CustomToggleGroup } from "./CustomToggleGroup"
|
||||
|
||||
|
||||
|
||||
const { property, ccclass, requireComponent, executionOrder, menu } = cc._decorator
|
||||
|
||||
export enum ToggleSwitchType {
|
||||
active,
|
||||
animation
|
||||
}
|
||||
|
||||
/**
|
||||
* @en
|
||||
* The toggle component is a CheckBox, when it used together with a ToggleGroup,
|
||||
* it could be treated as a RadioButton.
|
||||
*
|
||||
* @zh
|
||||
* Toggle 是一个 CheckBox,当它和 ToggleGroup 一起使用的时候,可以变成 RadioButton。
|
||||
*/
|
||||
@ccclass
|
||||
@executionOrder(110)
|
||||
@menu('UI/CustomToggle')
|
||||
export class CustomToggle extends cc.Component {
|
||||
/**
|
||||
* @en
|
||||
* When this value is true, the check mark component will be enabled,
|
||||
* otherwise the check mark component will be disabled.
|
||||
*
|
||||
* @zh
|
||||
* 如果这个设置为 true,则 check mark 组件会处于 enabled 状态,否则处于 disabled 状态。
|
||||
*/
|
||||
@property
|
||||
get isChecked() {
|
||||
return this._isChecked
|
||||
}
|
||||
|
||||
set isChecked(value) {
|
||||
this._set(value)
|
||||
}
|
||||
|
||||
set _resizeToTarget(value: boolean) {
|
||||
// if (value) {
|
||||
// this._resizeNodeToTargetNode();
|
||||
// }
|
||||
}
|
||||
|
||||
get _toggleContainer() {
|
||||
const parent = this.node.parent!
|
||||
if (parent instanceof cc.Node) {
|
||||
return parent.getComponent(CustomToggleGroup)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @en
|
||||
* If Toggle is clicked, it will trigger event's handler.
|
||||
*
|
||||
* @zh
|
||||
* Toggle 按钮的点击事件列表。
|
||||
*/
|
||||
@property({ type: [cc.Component.EventHandler], tooltip: 'i18n:toggle.check_events' })
|
||||
public checkEvents: cc.Component.EventHandler[] = []
|
||||
@property(cc.Boolean)
|
||||
protected _isChecked = true
|
||||
@property([cc.Node])
|
||||
protected onNodeList: cc.Node[] = []
|
||||
@property([cc.Node])
|
||||
protected offNodeList: cc.Node[] = []
|
||||
@property({ type: cc.Enum(ToggleSwitchType) })
|
||||
toggleSwitchType: ToggleSwitchType = ToggleSwitchType.active
|
||||
//是否關閉點擊事件
|
||||
@property(cc.Boolean)
|
||||
isDoNotEmitToggle = false
|
||||
|
||||
private toggleEventMap: Map<ToggleSwitchType, Function> = new Map([
|
||||
[ToggleSwitchType.active, this.switchByActive.bind(this)],
|
||||
[ToggleSwitchType.animation, this.switchByAnimation.bind(this)]
|
||||
])
|
||||
|
||||
protected _internalToggle() {
|
||||
if (this.isDoNotEmitToggle) {
|
||||
return
|
||||
}
|
||||
this.isChecked = !this.isChecked
|
||||
}
|
||||
|
||||
protected _set(value: boolean, emitEvent = true) {
|
||||
if (this._isChecked == value) return
|
||||
|
||||
this._isChecked = value
|
||||
|
||||
const group = this._toggleContainer
|
||||
if (group && group.enabled && this.enabled) {
|
||||
if (value || (!group.anyTogglesChecked() && !group.allowSwitchOff)) {
|
||||
this._isChecked = true
|
||||
group.notifyToggleCheck(this as any, emitEvent)
|
||||
}
|
||||
}
|
||||
|
||||
this.playEffect()
|
||||
if (emitEvent) {
|
||||
this._emitToggleEvents()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
public playEffect() {
|
||||
this.toggleEventMap.get(this.toggleSwitchType)()
|
||||
}
|
||||
|
||||
switchByActive() {
|
||||
this.onNodeList.forEach((node) => {
|
||||
node.active = this._isChecked
|
||||
})
|
||||
this.offNodeList.forEach((node) => {
|
||||
node.active = !this._isChecked
|
||||
})
|
||||
}
|
||||
|
||||
switchByAnimation() { }
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Set isChecked without invoking checkEvents.
|
||||
*
|
||||
* @zh
|
||||
* 设置 isChecked 而不调用 checkEvents 回调。
|
||||
*
|
||||
* @param value - 是否被按下
|
||||
*/
|
||||
public setIsCheckedWithoutNotify(value: boolean) {
|
||||
this._set(value, false)
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.playEffect()
|
||||
if (!CC_EDITOR || CC_PREVIEW) {
|
||||
this.node.on(cc.Node.EventType.TOUCH_END, this._internalToggle, this)
|
||||
}
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
if (!CC_EDITOR || CC_PREVIEW) {
|
||||
this.node.off(cc.Node.EventType.TOUCH_END, this._internalToggle, this)
|
||||
}
|
||||
}
|
||||
|
||||
public OnDestroy() {
|
||||
const group = this._toggleContainer
|
||||
if (group) {
|
||||
group.ensureValidState()
|
||||
}
|
||||
}
|
||||
|
||||
protected _emitToggleEvents() {
|
||||
this.node.emit("toggle", this)
|
||||
if (this.checkEvents) {
|
||||
cc.Component.EventHandler.emitEvents(this.checkEvents, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Note: This event is emitted from the node to which the component belongs.
|
||||
*
|
||||
* @zh
|
||||
* 注意:此事件是从该组件所属的 Node 上面派发出来的,需要用 node.on 来监听。
|
||||
* @event toggle
|
||||
* @param {Event.EventCustom} event
|
||||
* @param {Toggle} toggle - The Toggle component.
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "c9005f79-10ad-41fb-8a54-3db4fd21e6c6",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { LocalEmitter } from "./LocalEmitter";
|
||||
|
||||
const { ccclass, property } = cc._decorator;
|
||||
|
||||
|
||||
@ccclass
|
||||
export default class EmitterBase {
|
||||
|
||||
_comp_id_: number = LocalEmitter.newCompId();
|
||||
|
||||
getCompId() {
|
||||
return this._comp_id_;
|
||||
}
|
||||
|
||||
//注册监听
|
||||
on(event: string, fn: Function) {
|
||||
LocalEmitter.inst.on(this.getCompId(), event, fn);
|
||||
}
|
||||
|
||||
//移除监听
|
||||
off(event: string = null, fn: Function = null) {
|
||||
LocalEmitter.inst.off(this.getCompId(), event, fn);
|
||||
}
|
||||
|
||||
// 发送事件
|
||||
emit(event: string = null, obj: any = null) {
|
||||
LocalEmitter.inst.emit(event, obj);
|
||||
}
|
||||
|
||||
removeAllListeners() {
|
||||
LocalEmitter.inst.off(this.getCompId());
|
||||
}
|
||||
|
||||
initListener(config:{[key:string]:number}){
|
||||
for(let key in config){
|
||||
this.on(config[key].toString(), this[key].bind(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "88513ced-6c4a-41d1-a9b2-30b61f99e0a9",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
|
||||
/**
|
||||
* class Emitter.
|
||||
*
|
||||
*/
|
||||
export class LocalEmitter {
|
||||
public static _instance: LocalEmitter = null;
|
||||
public static get inst() {
|
||||
if (LocalEmitter._instance == null) {
|
||||
LocalEmitter._instance = new LocalEmitter();
|
||||
}
|
||||
|
||||
return LocalEmitter._instance;
|
||||
}
|
||||
|
||||
private static _g_comp_id: number = 1;
|
||||
|
||||
public static newCompId() {
|
||||
return LocalEmitter._g_comp_id++;
|
||||
}
|
||||
/**
|
||||
* callbacks for event.
|
||||
*/
|
||||
_callbacks = {};
|
||||
_onceCallbacks = {};
|
||||
|
||||
/**
|
||||
* Listen on the given `event` with `fn`.
|
||||
*/
|
||||
on(tag: number, event: string, fn: Function) {
|
||||
let callbacks = this._callbacks[event];
|
||||
if (null == callbacks) {
|
||||
callbacks = this._callbacks[event] = {};
|
||||
}
|
||||
let calls = callbacks[tag];
|
||||
if (null == calls) {
|
||||
calls = callbacks[tag] = [];
|
||||
}
|
||||
calls.push(fn);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
once(event: string, fn: Function) {
|
||||
if(event == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._onceCallbacks[event] == null){
|
||||
this._onceCallbacks[event] = [];
|
||||
}
|
||||
|
||||
this._onceCallbacks[event].push(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given callback for `event` or all
|
||||
* registered callbacks.
|
||||
*/
|
||||
off(tag: number = null, event: string = null, fn: Function = null) {
|
||||
// all
|
||||
if (null == tag) {
|
||||
this._callbacks = {};
|
||||
return this;
|
||||
}
|
||||
|
||||
if (null == event) {
|
||||
for (let event in this._callbacks) {
|
||||
delete this._callbacks[event][tag];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
if (null == fn) {
|
||||
if (null != this._callbacks[event]) {
|
||||
delete this._callbacks[event][tag];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// specific event
|
||||
let callbacks = this._callbacks[event];
|
||||
if (!callbacks) return this;
|
||||
|
||||
let calls = callbacks[tag];
|
||||
if (!calls) return this;
|
||||
|
||||
// remove specific handler
|
||||
let i = calls.indexOf(fn);
|
||||
if (~i) calls.splice(i, 1);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit `event` with the given args.
|
||||
*
|
||||
*/
|
||||
emit(event: string, obj: any = null, obj2: any = null) {
|
||||
|
||||
let callbacks = this._callbacks[event];
|
||||
let onceCallback = this._onceCallbacks[event];
|
||||
|
||||
if (null != callbacks) {
|
||||
for (let id in callbacks) {
|
||||
let calls = callbacks[id];
|
||||
for (let i = 0, len = calls.length; i < len; ++i) {
|
||||
calls[i].call(this, obj, obj2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onceCallback != null) {
|
||||
onceCallback.filter((callback)=>{
|
||||
callback(null, obj, obj2);
|
||||
})
|
||||
|
||||
delete this._onceCallbacks[event];
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "1f410cf5-01b4-48a2-af1c-5504f2293207",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
Vendored
+467
@@ -0,0 +1,467 @@
|
||||
const oneMinuteSeconds = 60
|
||||
const onehourSeconds = oneMinuteSeconds * 60
|
||||
const oneDaySeconds = onehourSeconds * 24
|
||||
|
||||
let forbiddenWords: string[] = undefined
|
||||
|
||||
export class Utils {
|
||||
|
||||
//是否空值
|
||||
public static isNull(o: any): boolean {
|
||||
let type = Object.prototype.toString.call(o);
|
||||
return ("[object Null]" === type || "[object Undefined]" === type);
|
||||
}
|
||||
|
||||
//是否字符串
|
||||
public static isString(o: any): boolean {
|
||||
return ("[object String]" === Object.prototype.toString.call(o));
|
||||
}
|
||||
|
||||
//是否数字
|
||||
public static isNumber(o: any): boolean {
|
||||
return ("[object Number]" === Object.prototype.toString.call(o));
|
||||
}
|
||||
|
||||
//是否数组
|
||||
public static isArray(o: any): boolean {
|
||||
return ("[object Array]" === Object.prototype.toString.call(o));
|
||||
}
|
||||
|
||||
//是否字典
|
||||
public static isObject(o: any): boolean {
|
||||
return ("[object Object]" === Object.prototype.toString.call(o));
|
||||
}
|
||||
|
||||
//是否方法
|
||||
public static isFunction(o: any): boolean {
|
||||
return ("[object Function]" === Object.prototype.toString.call(o));
|
||||
}
|
||||
|
||||
//继承
|
||||
public static inherit(base: Function, obj: Function) {
|
||||
for (let key in base.prototype) {
|
||||
obj.prototype[key] = base.prototype[key];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
//继承
|
||||
public static queryUrl(url: string) {
|
||||
let querys = {};
|
||||
let index = url.indexOf("?")
|
||||
cc.log(index)
|
||||
if (index >= 0) {
|
||||
let strs = url.substr(index + 1).split("&")
|
||||
for (let i = 0, len = strs.length; i < len; i++) {
|
||||
if (strs[i].indexOf("=") > 0) {
|
||||
let params = strs[i].split("=");
|
||||
if (params[0].trim() != "") {
|
||||
querys[params[0]] = params[1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return querys;
|
||||
}
|
||||
|
||||
// 将base64字符串转换成图片
|
||||
public static getSpritFrameFromBase64(base64: string): cc.SpriteFrame {
|
||||
base64 = "data:image/jpeg;base64," + base64;
|
||||
let img = new Image();
|
||||
img.src = base64;
|
||||
let texture = new cc.Texture2D();
|
||||
texture.initWithElement(img);
|
||||
texture.handleLoadedTexture();
|
||||
return new cc.SpriteFrame(texture);
|
||||
}
|
||||
|
||||
//生成uuid
|
||||
public static uuid(length: number) {
|
||||
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
||||
let uuid = [], i = 0;
|
||||
let radix = chars.length;
|
||||
|
||||
if (length > 0) {
|
||||
// Compact form
|
||||
for (i = 0; i < length; i++) uuid[i] = chars[0 | Math.random() * radix];
|
||||
} else {
|
||||
// rfc4122, version 4 form
|
||||
let r: number = 0;
|
||||
|
||||
// rfc4122 requires these characters
|
||||
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
|
||||
uuid[14] = '4';
|
||||
|
||||
// Fill in random data. At i==19 set the high bits of clock sequence as
|
||||
// per rfc4122, sec. 4.1.5
|
||||
for (i = 0; i < 36; i++) {
|
||||
if (!uuid[i]) {
|
||||
r = 0 | Math.random() * 16;
|
||||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uuid.join('');
|
||||
}
|
||||
|
||||
//复制文本
|
||||
public static onCopyText(copyText: string): boolean {
|
||||
if (cc.sys.isBrowser) {
|
||||
let input = document.createElement("input");
|
||||
input.setAttribute("readonly", "readonly");
|
||||
input.setAttribute("value", copyText);
|
||||
|
||||
input.style.position = "absolute";
|
||||
input.style.left = "-9999px";
|
||||
input.style.fontSize = "12pt"; // Prevent zooming on iOS
|
||||
|
||||
document.body.appendChild(input);
|
||||
|
||||
input.select();
|
||||
input.setSelectionRange(0, 128);
|
||||
|
||||
let success = false;
|
||||
try {
|
||||
if (document.execCommand("Copy")) {
|
||||
success = true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
document.body.removeChild(input);
|
||||
|
||||
return success;
|
||||
} else {
|
||||
// if (Common.OpenFunction.COPYTEXT) {
|
||||
// if (cc.sys.os == cc.sys.OS_ANDROID) {
|
||||
// jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "JavaCopy", "(Ljava/lang/String;)V", copyText);
|
||||
// return true
|
||||
// }
|
||||
// else if (cc.sys.os == cc.sys.OS_IOS) {
|
||||
// let IOS_API = "AppController";
|
||||
// jsb.reflection.callStaticMethod(IOS_API, "JavaCopy:", copyText);
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//复制文本
|
||||
public static getCopyText(): string {
|
||||
let copyText = ""
|
||||
|
||||
// if (Common.OpenFunction.COPYTEXT) {
|
||||
// if (cc.sys.os == cc.sys.OS_ANDROID) {
|
||||
// copyText = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getDuplicateContent", "()Ljava/lang/String;");
|
||||
// }
|
||||
// else if (cc.sys.os == cc.sys.OS_IOS) {
|
||||
// let IOS_API = "AppController";
|
||||
// copyText = jsb.reflection.callStaticMethod(IOS_API, "getDuplicateContent:", "");
|
||||
// }
|
||||
// }
|
||||
return copyText
|
||||
}
|
||||
|
||||
/**
|
||||
* 尋找當前scrollView滑動百分比
|
||||
* @param scrollView
|
||||
*/
|
||||
public static judgeScrollPercent(scrollView: cc.ScrollView) {
|
||||
const offset = scrollView.getScrollOffset()
|
||||
const maxOffset = scrollView.getMaxScrollOffset()
|
||||
const offsetArray = [offset.x, offset.y]
|
||||
const maxOffsetArray = [maxOffset.x, maxOffset.y, maxOffset.y]
|
||||
const index = maxOffsetArray.indexOf(Math.max(...maxOffsetArray))
|
||||
offsetArray[index] = Math.abs(offsetArray[index])
|
||||
offsetArray[index] = offsetArray[index] < 0 ? 0 : offsetArray[index]
|
||||
offsetArray[index] = offsetArray[index] > maxOffsetArray[index] ? maxOffsetArray[index] : offsetArray[index]
|
||||
return offsetArray[index] / maxOffsetArray[index]
|
||||
}
|
||||
|
||||
/**
|
||||
* 轉換錢幣
|
||||
*/
|
||||
public static moneyUnitConvert(money: number) {
|
||||
if (money < 1000) {
|
||||
return money + ''
|
||||
} else {
|
||||
return money / 1000 + 'K'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 三位一撇
|
||||
*/
|
||||
public static numberWithCommas(number: number) {
|
||||
let parts = number.toFixed(2).split('.')
|
||||
let decimal = parts[1].slice();
|
||||
|
||||
for (let i = parts[1].length - 1; i >= 0; i--) {
|
||||
if (parts[1][i] != '0') {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
decimal = decimal.substr(0, i);
|
||||
}
|
||||
}
|
||||
parts[1] = decimal;
|
||||
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (parts[1] ? '.' + parts[1] : '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 無條件捨去
|
||||
*/
|
||||
public static roundDown(number: number) {
|
||||
return Number(String(number).split(".")[0])
|
||||
}
|
||||
|
||||
public static deepClone(data: any) {
|
||||
if (data === undefined || data === null) {
|
||||
return data
|
||||
}
|
||||
return JSON.parse(JSON.stringify(data || {}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 閃爍動畫
|
||||
* @param node 閃爍節點
|
||||
* @param duration 間隔
|
||||
* @param repeat 重複次數(-1為無限)
|
||||
* @param callBack 回調函式
|
||||
*/
|
||||
public static blink(node: cc.Node, duration: number, repeat = 0, endShow: boolean = true, callBack?: Function) {
|
||||
// cc.log(`blick duration:${duration} repeat:${repeat}`);
|
||||
node.active = true
|
||||
cc.Tween.stopAllByTarget(node)
|
||||
|
||||
node.opacity = 0;
|
||||
const show = endShow ? 255 : 0;
|
||||
let action = cc.tween()
|
||||
.to(duration, { opacity: 0 }, { easing: 'quadIn' })
|
||||
.to(duration, { opacity: 255 }, { easing: 'quadOut' })
|
||||
|
||||
cc.tween(node).repeat(repeat, action).call(() => { node.opacity = show; callBack && callBack() }).start();
|
||||
}
|
||||
|
||||
public static currencyFilter(value: number) {
|
||||
if (value < 1000) {
|
||||
return `${value}`
|
||||
}
|
||||
value = value - (value % 100)
|
||||
return `${value / 1000}K`
|
||||
}
|
||||
|
||||
public static getCanvasInParent(node: cc.Node): cc.Canvas {
|
||||
if (!node) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let canvas = undefined
|
||||
let parent = node.parent
|
||||
while (!canvas) {
|
||||
if (!parent) {
|
||||
break
|
||||
}
|
||||
|
||||
canvas = parent.getComponent(cc.Canvas)
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
return canvas
|
||||
}
|
||||
|
||||
public static clamp(val: number, min: number, max: number): number {
|
||||
return val < min ? min : (val > max ? max : val)
|
||||
}
|
||||
|
||||
public static copyString(str: string) {
|
||||
const el = document.createElement('textarea')
|
||||
el.value = str
|
||||
el.setAttribute('readonly', '')
|
||||
// el.style.contain = 'strict';
|
||||
el.style.position = 'absolute'
|
||||
el.style.left = '-9999px'
|
||||
el.style.fontSize = '12pt' // Prevent zooming on iOS
|
||||
|
||||
const selection = getSelection()
|
||||
let originalRange = null
|
||||
if (selection.rangeCount > 0) {
|
||||
originalRange = selection.getRangeAt(0)
|
||||
}
|
||||
document.body.appendChild(el)
|
||||
el.select()
|
||||
el.selectionStart = 0
|
||||
el.selectionEnd = str.length
|
||||
|
||||
let success = false
|
||||
try {
|
||||
success = document.execCommand('copy')
|
||||
} catch (err) { }
|
||||
|
||||
document.body.removeChild(el)
|
||||
|
||||
if (originalRange) {
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(originalRange)
|
||||
}
|
||||
if (success) {
|
||||
console.log('复制成功')
|
||||
} else {
|
||||
console.log('复制失败')
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
public static setButtonInteractable(button: cc.Button, value: boolean) {
|
||||
if (!button) {
|
||||
return
|
||||
}
|
||||
|
||||
button.interactable = value
|
||||
}
|
||||
|
||||
public static changeNodeParent(node, parent) {
|
||||
if (!node) {
|
||||
cc.error("changeNodeParent node is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parent) {
|
||||
cc.error("changeNodeParent parent is null");
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = node.parent.convertToWorldSpaceAR(node.getPosition());
|
||||
let changePos = parent.convertToNodeSpaceAR(pos);
|
||||
node.parent = parent;
|
||||
node.setPosition(changePos);
|
||||
}
|
||||
|
||||
public static tweenNumberLabel(label: cc.Label, num: number, suffix: string = '') {
|
||||
const currentNum = Number(label.string.replace(/,/g, '').replace(suffix, ''))
|
||||
if (!Utils.isNumber(currentNum)) {
|
||||
console.warn('label is not number:', label.string)
|
||||
return
|
||||
}
|
||||
if (currentNum >= num) {
|
||||
label.string = Utils.numberWithCommas(num) + suffix
|
||||
return
|
||||
}
|
||||
const plusNum = num - currentNum
|
||||
const betweenTime = 0.01
|
||||
const count = 80
|
||||
let currentCount = 0
|
||||
label.unscheduleAllCallbacks()
|
||||
label.schedule(
|
||||
() => {
|
||||
if (!label) {
|
||||
return
|
||||
}
|
||||
currentCount += 1
|
||||
label.string = Utils.numberWithCommas(Math.round(currentNum + (plusNum / count) * currentCount)) + suffix
|
||||
if (currentCount === count) {
|
||||
label.string = Utils.numberWithCommas(num) + suffix
|
||||
}
|
||||
},
|
||||
betweenTime,
|
||||
count - 1
|
||||
)
|
||||
}
|
||||
|
||||
public static tweenSpriteFillrange(sprite: cc.Sprite, percent: number) {
|
||||
// cc.log("tweenSpriteFillrange ", percent)
|
||||
let changeTotal = percent - sprite.fillRange;
|
||||
const count = 80;
|
||||
const betweenTime = 0.01
|
||||
let per = changeTotal / count;
|
||||
let curRange = sprite.fillRange;
|
||||
sprite.unscheduleAllCallbacks();
|
||||
sprite.schedule(() => {
|
||||
curRange += per;
|
||||
sprite.fillRange = curRange;
|
||||
}, betweenTime, count - 1);
|
||||
}
|
||||
|
||||
// 計算字符長度 (英文數字當成1 其他當成2)
|
||||
public static countMultiLangStrLength(str: string): number {
|
||||
const originalSize = str.length
|
||||
const digitNLetter = str.replace(/[^a-zA-Z0-9]/g, '')
|
||||
const englishSize = digitNLetter.length
|
||||
const otherLength = (originalSize - digitNLetter.length) * 2
|
||||
return englishSize + otherLength
|
||||
}
|
||||
|
||||
public static formatNickname(str: string, maxLen = 6) {
|
||||
let len = Utils.countMultiLangStrLength(str);
|
||||
let subLen = len;
|
||||
while (subLen > maxLen) {
|
||||
str = str.substr(0, str.length - 1);
|
||||
subLen = Utils.countMultiLangStrLength(str);
|
||||
}
|
||||
|
||||
return len > 6 ? (str + "...") : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 數字換行(奇數上排數字大於下排, 偶數對半)
|
||||
* @param numStr 欲轉換數字
|
||||
* @param limitNum 幾位後要換行
|
||||
*/
|
||||
|
||||
public static convertChipStr(numStr: string, limitNum: number = 3) {
|
||||
const len = numStr.length
|
||||
if (len > limitNum) {
|
||||
const sliceLen = Math.ceil(len * 0.5)
|
||||
return `${numStr.slice(0, sliceLen)}\n${numStr.slice(sliceLen)}`
|
||||
} else {
|
||||
return numStr
|
||||
}
|
||||
}
|
||||
|
||||
/** 發送訊息提示 */
|
||||
public static showSendLog(eventName: string, message?: any) {
|
||||
if (CC_DEBUG) {
|
||||
message = message || {};
|
||||
const time = this.convertTimestamp(new Date().getTime());
|
||||
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
|
||||
console.log("%s %c %s", time, "background: Green; color: White;", "發送 " + eventName + " ", data);
|
||||
}
|
||||
}
|
||||
|
||||
/** 回傳訊息提示 */
|
||||
public static showResponseLog(eventName: string, message?: any) {
|
||||
if (CC_DEBUG) {
|
||||
message = message || {};
|
||||
const time = this.convertTimestamp(new Date().getTime());
|
||||
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
|
||||
console.log("%s %c %s", time, "background: Green; color: White;", "回應 " + eventName + " ", data);
|
||||
}
|
||||
}
|
||||
|
||||
/** 廣播訊息提示 */
|
||||
public static showPushLog(eventName: string, message: any) {
|
||||
if (CC_DEBUG) {
|
||||
message = message || {};
|
||||
const time = this.convertTimestamp(new Date().getTime());
|
||||
let data = JSON.parse(JSON.stringify(message)); // Deep Copy
|
||||
console.log("%s %c %s", time, "background: Blue; color: White;", "廣播 " + eventName + " ", data);
|
||||
}
|
||||
}
|
||||
|
||||
private static convertTimestamp(value: number): string {
|
||||
const t = new Date(value);
|
||||
// const yyyy = t.getFullYear();
|
||||
// const MM = t.getMonth() < 9 ? "0" + (t.getMonth()+1):t.getMonth()+1;
|
||||
// const DD = t.getDate() < 10 ? "0" + t.getDate() : t.getDate();
|
||||
const hh = t.getHours() < 10 ? "0" + t.getHours() : t.getHours();
|
||||
const mm = t.getMinutes() < 10 ? "0" + t.getMinutes() : t.getMinutes()
|
||||
const ss = t.getSeconds() < 10 ? "0" + t.getSeconds() : t.getSeconds()
|
||||
return `${hh}:${mm}:${ss}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.8",
|
||||
"uuid": "85b3afaa-64ef-46e6-9e0d-54055039a8a6",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
Reference in New Issue
Block a user