JavaScript面向对象编程[一] 构造函数


    //类的定义
   
    //方法一:类的一般定义方法
    function player1(_name)
    {
        this.name = _name;
        this.say = function() {alert(this.name);};
    }
   
    var p1 = new player1('llinzzi1');
    p1.say();
   
   
    //方法二:prototype定义方法
    var player2 = function() {}
    player2.prototype = {
        name:'',
        say:function(){
            alert(this.name);
        }
    }
   
    var p2 = new player2();
    p2.name = 'llinzzi2';
    p2.say();
   
   
    //方法三:上面的方法结构美观,便捷,但构建函数不能带参数,修改方法
    var player3 = function() {
        this.init.apply(this, arguments);
    }
    player3.prototype = {
        init:function(_name){
            this.name = _name;
        },
        say:function(){
            alert(this.name);
        }
    }
   
    var p3 = new player3('llinzzi3');
    p3.say();
   
    //类的继承
   
    //方法一
    var player4 = function(){
        this.init.apply(this, arguments);
    }
    player4.prototype = new player3;
    player4.prototype.shout = function(){
        alert(this.name.toUpperCase());
    }
   
    var p4 = new player4('llinzzi4');
    p4.shout();
   
   
    //方法二 上面的方法不能采用{}的方法,修改方法
    Object.extend = function(destination, source) {
      for (var property in source)
        destination[property] = source[property];
      return destination;
    };
   
    var player5 = function(){
        this.init.apply(this, arguments);
    }
    Object.extend(Object.extend(player5.prototype,player3.prototype),{
        shout:function(){
            alert(this.name.toUpperCase());
        }
   
    });
   
    var p5 = new player5('llinzzi5');
    p5.shout();
   
   
   
   
    //再从prototype.js抄一端浏览器判断代码

    Browser = {
        IE:     !!(window.attachEvent && !window.opera),
        Opera:  !!window.opera,
        WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
        Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
        MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
    }
   
    alert(Browser.MobileSafari);

/
JavaScript面向对象编程[二] 事件处理


如果采用上篇文章的方法构建的类,如果要处理事件按通常的写法会造成回调函数作用域丢失。


程序代码


        var foo = function(){ this.init.apply(this,arguments);};
        
        foo.prototype = {
            init:function(_name){
                 this.name = _name;
                 this.addEvent('click',document,this.say);
            },
            say:function(_ev){
                alert(this.name);
                this.stop();
            },
            stop:function(){
                 this.removeEvent('click',document,this.say);
          },
            addEvent:function(_event,_element,_fn){
                if (_element.addEventListener) {
                    _element.addEventListener(_event, _fn, false);
                } else if (_element.attachEvent) {
                    _element.attachEvent("on" +_event,_fn);
                }
            },
            removeEvent:function(_event,_element,_fn){
                if (_element.removeEventListener) {
                    _element.removeEventListener(_event, _fn, false);
                } else if (_element.detachEvent) {
                    _element.detachEvent("on" +_event, _fn);
                }
            }
        }

        var a = new foo('llinzzi');




以上代码可以观察到this.say的alert方法已经调用,但内部的this.name已经不存在了,因为找不到this了。并且如果要像say里面传值似乎也比较麻烦。


解决this丢失和传值问题的代码,并解决传this后不能注销事件的问题。


程序代码

        var foo = function(){ this.init.apply(this,arguments);};
        
        foo.prototype = {
            init:function(_name){
                 this.name = _name;
                 this.addEvent('click',document,this.say,this,'hello world!');
            },
            say:function(_ev,_word){
                alert(this.name +':' +_word);
                this.stop();
            },
            stop:function(){
                 this.removeEvent('click',document,this.say);
          },
            addEvent:function(_event,_element,_fn,_scope,_args){
                var args = this._toArray(arguments),
                    ev = args.shift(),
                    element = args.shift(),
                    fn = args.shift(),
                    scope = args.length>0?args.shift():window;
                element['e'+ev+fn] =  function(_ev){
                    _ev == _ev || window.event;
                    args.unshift(_ev);
                    fn.apply(scope,args);
                };
                if (element.addEventListener) {
                    element.addEventListener(ev, element['e'+ev+fn], false);
                } else if (element.attachEvent) {
                    element.attachEvent("on" +ev, element['e'+ev+fn]);
                }
            },
            removeEvent:function(_event,_element,_fn){
                if (_element.removeEventListener) {
                    _element.removeEventListener(_event, _element['e'+_event+_fn], false);
                } else if (_element.detachEvent) {
                    _element.detachEvent("on" +_event, _element['e'+_event+_fn]);
                }
                try {
                    delete _element['e'+_event+_fn];
                }catch(_ex){
                    _element['e'+_event+_fn] = null;
                }
            },
            _toArray:function(iterable){
                if (!iterable) return [];
                if (iterable.toArray) return iterable.toArray();
                var length = iterable.length || 0, results = new Array(length);
                while (length--) results[length] = iterable[length];
                return results;
            }
        }


        var a = new foo('llinzzi');




下一次会分享一下在用面向对象编程过程中的一些心得,有关设计模式的一些整理。
/
JavaScript面向对象编程[三] 自定义事件


上一篇给foo类增加了
addEvent和removeEvent方便事件的注册与注销

这次总结下自定义事件的几种方法


程序代码


    <script type="text/javascript">
        <!--

    var foo = function(){ this.init.apply(this,arguments);};

    foo.prototype = {
        init:function(_name){
            this.name = _name;
            this.addEvent('click',document,this.say,this,'hello world!');
        },
        say:function(_ev,_word){
            alert(this.name +':' +_word);
            this.stop();
            this.onSay(_word);
        },
        stop:function(){
            this.removeEvent('click',document,this.say);
        },
        addEvent:function(_event,_element,_fn,_scope,_args){
            var args = Array.prototype.slice.call(arguments, 0);  
            ev = args.shift(),
            element = args.shift(),
            fn = args.shift(),
            scope = args.length>0?args.shift():window;
            element['e'+ev+fn] =  function(_ev){
                _ev == _ev || window.event;
                args.unshift(_ev);
                fn.apply(scope,args);
            };
            if (element.addEventListener) {
                element.addEventListener(ev, element['e'+ev+fn], false);
            } else if (element.attachEvent) {
                element.attachEvent("on" +ev, element['e'+ev+fn]);
            }
        },
        removeEvent:function(_event,_element,_fn){
            if (_element.removeEventListener) {
                _element.removeEventListener(_event, _element['e'+_event+_fn], false);
            } else if (_element.detachEvent) {
                _element.detachEvent("on" +_event, _element['e'+_event+_fn]);
            }
            try {
                delete _element['e'+_event+_fn];
            }catch(_ex){
                _element['e'+_event+_fn] = null;
            }
        },
        onSay:function(){}

    }


var a = new foo('llinzzi');
a.onSay = function(_word){
    alert('事件:'+this.name +'刚说了'+ _word);
}





HTML代码
<html>
<head>
<title>自定义事件</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
<meta name="keywords" content="" >
<meta name="description" content="" >
</head>
<body>



<script type="text/javascript">
<!--

var foo = function(){ this.init.apply(this,arguments);};

foo.prototype = {
init:function(_name){
this.name = _name;
this.addEvent('click',document,this.say,this,'hello world!');
},
say:function(_ev,_word){
alert(this.name +':' +_word);
this.stop();
this.onSay(_word);
},
stop:function(){
this.removeEvent('click',document,this.say);
},
addEvent:function(_event,_element,_fn,_scope,_args){
var args = Array.prototype.slice.call(arguments, 0);  
ev = args.shift(),
element = args.shift(),
fn = args.shift(),
scope = args.length>0?args.shift():window;
element['e'+ev+fn] =  function(_ev){
_ev == _ev || window.event;
args.unshift(_ev);
fn.apply(scope,args);
};
if (element.addEventListener) {
element.addEventListener(ev, element['e'+ev+fn], false);
} else if (element.attachEvent) {
element.attachEvent("on" +ev, element['e'+ev+fn]);
}
},
removeEvent:function(_event,_element,_fn){
if (_element.removeEventListener) {
_element.removeEventListener(_event, _element['e'+_event+_fn], false);
} else if (_element.detachEvent) {
_element.detachEvent("on" +_event, _element['e'+_event+_fn]);
}
try {
delete _element['e'+_event+_fn];
}catch(_ex){
_element['e'+_event+_fn] = null;
}
},
onSay:function(){}

}


var a = new foo('llinzzi');
a.onSay = function(_word){
alert('事件:'+this.name +'刚说了'+ _word);
}

// -->
</script>
</body>
</html>

  
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]


增加了个onSay的事件,在类定义的时候只定义成空函数,然后在需要的时候调用,定义具体的方法是在类实例化后,给实例中的onSay

缺点是只能定义一次的onSay的回调,如果多次定义后面的会把前面的覆盖掉,修改一下。

程序代码


    var foo = function(){ this.init.apply(this,arguments);};

    foo.prototype = {
        init:function(_name){
            this.name = _name;
            this.addEvent('click',document,this.say,this,'hello world!');
        },
        say:function(_ev,_word){
            alert(this.name +':' +_word);
            this.stop();
            this._onSay(_word);
        },
        stop:function(){
            this.removeEvent('click',document,this.say);
        },
        addEvent:function(_event,_element,_fn,_scope,_args){
            var args = Array.prototype.slice.call(arguments, 0);  
            ev = args.shift(),
            element = args.shift(),
            fn = args.shift(),
            scope = args.length>0?args.shift():window;
            element['e'+ev+fn] =  function(_ev){
                _ev == _ev || window.event;
                args.unshift(_ev);
                fn.apply(scope,args);
            };
            if (element.addEventListener) {
                element.addEventListener(ev, element['e'+ev+fn], false);
            } else if (element.attachEvent) {
                element.attachEvent("on" +ev, element['e'+ev+fn]);
            }
        },
        removeEvent:function(_event,_element,_fn){
            if (_element.removeEventListener) {
                _element.removeEventListener(_event, _element['e'+_event+_fn], false);
            } else if (_element.detachEvent) {
                _element.detachEvent("on" +_event, _element['e'+_event+_fn]);
            }
            try {
                delete _element['e'+_event+_fn];
            }catch(_ex){
                _element['e'+_event+_fn] = null;
            }
        },
        _onSay:function(){
            if(!this._onSayArray) return;   
            for(var i=0; i<this._onSayArray.length; i++){
                this._onSayArray[i].apply(this,arguments);
            }
        },
        addOnSay:function(_fn){
            if(!this._onSayArray) this._onSayArray = new Array();
            this._onSayArray.push(_fn);
        }
    }


var a = new foo('llinzzi');
a.addOnSay(function(_word){
    alert('事件1:'+this.name +'刚说了'+ _word);
});
a.addOnSay(function(_word){
    alert('事件2:'+this.name +'刚说了'+ _word);
});





HTML代码
<html>
<head>
<title>自定义事件</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
<meta name="keywords" content="" >
<meta name="description" content="" >
</head>
<body>



<script type="text/javascript">
<!--

var foo = function(){ this.init.apply(this,arguments);};

foo.prototype = {
init:function(_name){
this.name = _name;
this.addEvent('click',document,this.say,this,'hello world!');
},
say:function(_ev,_word){
alert(this.name +':' +_word);
this.stop();
this._onSay(_word);
},
stop:function(){
this.removeEvent('click',document,this.say);
},
addEvent:function(_event,_element,_fn,_scope,_args){
var args = Array.prototype.slice.call(arguments, 0);  
ev = args.shift(),
element = args.shift(),
fn = args.shift(),
scope = args.length>0?args.shift():window;
element['e'+ev+fn] =  function(_ev){
_ev == _ev || window.event;
args.unshift(_ev);
fn.apply(scope,args);
};
if (element.addEventListener) {
element.addEventListener(ev, element['e'+ev+fn], false);
} else if (element.attachEvent) {
element.attachEvent("on" +ev, element['e'+ev+fn]);
}
},
removeEvent:function(_event,_element,_fn){
if (_element.removeEventListener) {
_element.removeEventListener(_event, _element['e'+_event+_fn], false);
} else if (_element.detachEvent) {
_element.detachEvent("on" +_event, _element['e'+_event+_fn]);
}
try {
delete _element['e'+_event+_fn];
}catch(_ex){
_element['e'+_event+_fn] = null;
}
},
_onSay:function(){
if(!this._onSayArray) return;
for(var i=0; i<this._onSayArray.length; i++){
this._onSayArray[i].apply(this,arguments);
}
},
addOnSay:function(_fn){
if(!this._onSayArray) this._onSayArray = new Array();
this._onSayArray.push(_fn);
}
}


var a = new foo('llinzzi');
a.addOnSay(function(_word){
alert('事件1:'+this.name +'刚说了'+ _word);
});
a.addOnSay(function(_word){
alert('事件2:'+this.name +'刚说了'+ _word);
});

// -->
</script>
</body>
</html>

  
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]


实例通过addOnSay方法来增加事件响应,可以增加多个。

缺点,代码繁琐,如果要增加addOnSayAfter addOnSayBefore 就要增加很多代码。

再修改一下


程序代码


    var foo = function(){ this.init.apply(this,arguments);};

    foo.prototype = {
        init:function(_name){
            this.name = _name;
            this.addEvent('click',document,this.say,this,'hello world!');
        },
        say:function(_ev,_word){
            this.fireEvent('saybefore',_word);
            alert(this.name +':' +_word);
            this.stop();
            this.fireEvent('sayafter',_word);
        },
        stop:function(){
            this.removeEvent('click',document,this.say);
        },
        addEvent:function(_event,_element,_fn,_scope,_args){
            var args = Array.prototype.slice.call(arguments, 0);  
            ev = args.shift(),
            element = args.shift(),
            fn = args.shift(),
            scope = args.length>0?args.shift():window;
            element['e'+ev+fn] =  function(_ev){
                _ev == _ev || window.event;
                args.unshift(_ev);
                fn.apply(scope,args);
            };
            if (element.addEventListener) {
                element.addEventListener(ev, element['e'+ev+fn], false);
            } else if (element.attachEvent) {
                element.attachEvent("on" +ev, element['e'+ev+fn]);
            }
        },
        removeEvent:function(_event,_element,_fn){
            if (_element.removeEventListener) {
                _element.removeEventListener(_event, _element['e'+_event+_fn], false);
            } else if (_element.detachEvent) {
                _element.detachEvent("on" +_event, _element['e'+_event+_fn]);
            }
            try {
                delete _element['e'+_event+_fn];
            }catch(_ex){
                _element['e'+_event+_fn] = null;
            }
        },
        fireEvent:function(){
            var args = Array.prototype.slice.call(arguments, 0);  
            var _event = args.shift();
            if(!this.cusEvents) return;
            if(!this.cusEvents[_event]) return;
            for(var i=0; i<this.cusEvents[_event].length; i++){
                this.cusEvents[_event][i].apply(this,args);
            }
        },
        catchEvent:function(_event,_fn){
            if(!this.cusEvents) this.cusEvents = {}
            if(!this.cusEvents[_event]) this.cusEvents[_event] = new Array();
            this.cusEvents[_event].push(_fn);
        }
    }


var a = new foo('llinzzi');

a.catchEvent('saybefore',function(_word){
    alert('事件1:'+this.name +'想说'+ _word);
});

a.catchEvent('sayafter',function(_word){
    alert('事件2:'+this.name +'刚说了'+ _word);
});





HTML代码
<html>
<head>
<title>自定义事件</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
<meta name="keywords" content="" >
<meta name="description" content="" >
</head>
<body>



<script type="text/javascript">
<!--

var foo = function(){ this.init.apply(this,arguments);};

foo.prototype = {
init:function(_name){
this.name = _name;
this.addEvent('click',document,this.say,this,'hello world!');
},
say:function(_ev,_word){
this.fireEvent('saybefore',_word);
alert(this.name +':' +_word);
this.stop();
this.fireEvent('sayafter',_word);
},
stop:function(){
this.removeEvent('click',document,this.say);
},
addEvent:function(_event,_element,_fn,_scope,_args){
var args = Array.prototype.slice.call(arguments, 0);  
ev = args.shift(),
element = args.shift(),
fn = args.shift(),
scope = args.length>0?args.shift():window;
element['e'+ev+fn] =  function(_ev){
_ev == _ev || window.event;
args.unshift(_ev);
fn.apply(scope,args);
};
if (element.addEventListener) {
element.addEventListener(ev, element['e'+ev+fn], false);
} else if (element.attachEvent) {
element.attachEvent("on" +ev, element['e'+ev+fn]);
}
},
removeEvent:function(_event,_element,_fn){
if (_element.removeEventListener) {
_element.removeEventListener(_event, _element['e'+_event+_fn], false);
} else if (_element.detachEvent) {
_element.detachEvent("on" +_event, _element['e'+_event+_fn]);
}
try {
delete _element['e'+_event+_fn];
}catch(_ex){
_element['e'+_event+_fn] = null;
}
},
fireEvent:function(){
var args = Array.prototype.slice.call(arguments, 0);  
var _event = args.shift();
if(!this.cusEvents) return;
if(!this.cusEvents[_event]) return;
for(var i=0; i<this.cusEvents[_event].length; i++){
this.cusEvents[_event][i].apply(this,args);
}
},
catchEvent:function(_event,_fn){
if(!this.cusEvents) this.cusEvents = {}
if(!this.cusEvents[_event]) this.cusEvents[_event] = new Array();
this.cusEvents[_event].push(_fn);
}
}


var a = new foo('llinzzi');

a.catchEvent('saybefore',function(_word){
alert('事件1:'+this.name +'想说'+ _word);
});

a.catchEvent('sayafter',function(_word){
alert('事件2:'+this.name +'刚说了'+ _word);
});

// -->
</script>
</body>
</html>


  
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]


最后如果将catchEvent fireEvent addEvent removeEvent 单独放在一个类.EventHeloper
将addEvent和catchEvent整合
EventHeloper.addEvent(element/object,dom event/custom event,callback) 这样还是很方便的。


程序代码


    EventHelper = {
        Events:{Dom:{},Custom:{}},
        addEvent:function(_object,_event,_fn,_scope,_args){
            var args = Array.prototype.slice.call(arguments, 0),  
                obj = args.shift(),
                ev = args.shift(),
                fn = args.shift(),
                scope = args.length>0?args.shift():window;
            var eType = obj.nodeType?'Dom':'Custom';
            var fun;
            if(eType=='Dom'){
                sfn = function(_ev){
                    _ev == _ev || window.event;
                    args.unshift(_ev);
                    fn.apply(scope,args);
                }
                if (obj.addEventListener) {
                    obj.addEventListener(ev,sfn, false);
                } else if (obj.attachEvent) {
                    obj.attachEvent("on" +ev,sfn);
                }
            }else {
                sfn = function(){
                    var __sargs = Array.prototype.slice.call(arguments, 0);
                    var _sargs = __sargs.concat(args);
                    fn.apply(scope,_sargs);
                }   
            }
            fun = { fn:fn,sfn:sfn };
            this.Events[eType][obj] = this.Events[eType][obj] || {};
            this.Events[eType][obj][ev] = this.Events[eType][obj][ev] || new Array();
            this.Events[eType][obj][ev].push(fun);
        },
        removeEvent:function(_object,_event,_fn){
            var obj = _object,
                ev = _event,
                fn = _fn;
            var eType = obj.nodeType?'Dom':'Custom';
            if(!this.Events[eType][obj]) return;

            var fun;
            for( var i=0; i<this.Events[eType][obj][ev].length;i++){
                if(fn == this.Events[eType][obj][ev][i].fn){
                    fun = this.Events[eType][obj][ev][i].sfn;
                    this.Events[eType][obj][ev].splice(i,1);
                    break;
                }
            }
            if(eType=='Dom'){
                if (obj.removeEventListener) {
                    obj.removeEventListener(ev, fun, false);
                } else if (obj.detachEvent) {
                    obj.detachEvent("on" + ev, fun);
                }
            }

        },
        fireEvent:function(_object,_event){
            var args = Array.prototype.slice.call(arguments, 0),  
                obj = args.shift(),
                ev = args.shift();
            var eType = 'Custom';
            if((!this.Events[eType][obj]) || (!this.Events[eType][obj][ev])) return;
            for(var i=0; i<this.Events[eType][obj][ev].length; i++){
                this.Events[eType][obj][ev][i].sfn.apply(window,args);
            }
        }
    }





修改一下演示的例子

HTML代码
<html>
<head>
<title>自定义事件</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
<meta name="keywords" content="" >
<meta name="description" content="" >
</head>
<body>



<script type="text/javascript">
<!--

EventHelper = {
Events:{Dom:{},Custom:{}},
addEvent:function(_object,_event,_fn,_scope,_args){
var args = Array.prototype.slice.call(arguments, 0),  
obj = args.shift(),
ev = args.shift(),
fn = args.shift(),
scope = args.length>0?args.shift():window;
var eType = obj.nodeType?'Dom':'Custom';
var fun;
if(eType=='Dom'){
sfn = function(_ev){
_ev == _ev || window.event;
args.unshift(_ev);
fn.apply(scope,args);
}
if (obj.addEventListener) {
obj.addEventListener(ev,sfn, false);
} else if (obj.attachEvent) {
obj.attachEvent("on" +ev,sfn);
}
}else {
sfn = function(){
var __sargs = Array.prototype.slice.call(arguments, 0);
var _sargs = __sargs.concat(args);
fn.apply(scope,_sargs);
}
}
fun = { fn:fn,sfn:sfn };
this.Events[eType][obj] = this.Events[eType][obj] || {};
this.Events[eType][obj][ev] = this.Events[eType][obj][ev] || new Array();
this.Events[eType][obj][ev].push(fun);
},
removeEvent:function(_object,_event,_fn){
var obj = _object,
ev = _event,
fn = _fn;
var eType = obj.nodeType?'Dom':'Custom';
if(!this.Events[eType][obj]) return;

var fun;
for( var i=0; i<this.Events[eType][obj][ev].length;i++){
if(fn == this.Events[eType][obj][ev][i].fn){
fun = this.Events[eType][obj][ev][i].sfn;
this.Events[eType][obj][ev].splice(i,1);
break;
}
}
if(eType=='Dom'){
if (obj.removeEventListener) {
obj.removeEventListener(ev, fun, false);
} else if (obj.detachEvent) {
obj.detachEvent("on" + ev, fun);
}
}

},
fireEvent:function(_object,_event){
var args = Array.prototype.slice.call(arguments, 0),  
obj = args.shift(),
ev = args.shift();
var eType = 'Custom';
if((!this.Events[eType][obj]) || (!this.Events[eType][obj][ev])) return;
for(var i=0; i<this.Events[eType][obj][ev].length; i++){
this.Events[eType][obj][ev][i].sfn.apply(window,args);
}
}
}



var foo = function(){ this.init.apply(this,arguments);};

foo.prototype = {
init:function(_name){
this.name = _name;
EventHelper.addEvent(document,'click',this.say,this,'hello world!');
},
say:function(_ev,_word){
EventHelper.fireEvent(this,'saybefore',_word);
alert(this.name +':' +_word);
this.stop();
EventHelper.fireEvent(this,'sayafter',_word);
},
stop:function(){
EventHelper.removeEvent(document,'click',this.say);
}
}


var a = new foo('llinzzi');

function sayBefore(_word,_word2){
alert('事件1:'+this.name +'想说'+ _word+_word2);
}
function sayAfter(_word){
alert('事件2:'+this.name +'刚说了'+ _word);
}

EventHelper.addEvent(a,'saybefore',sayBefore,a,'外部的数据');
//EventHelper.removeEvent(a,'saybefore',sayBefore);
EventHelper.addEvent(a,'sayafter',sayBefore,a);



// -->
</script>
</body>
</html>



  
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]


上面例子的 EventHelper.addEvent方法可以增加自定义事件或者原生的事件
EventHelper.addEvent(document,'click',function(){alert('hello');}); // 原生事件
EventHelper.addEvent(foo,'say',function(){alert('hello');}); // 自定义时间

对应的EventHelper.removeEvent也可以移除自定义事件。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值