自己写的数字最大最小值numvalue-check指令

本文深入探讨AngularJS指令的实现细节,包括自定义指令的编写、常用属性的应用、DOM操作及指令间交互等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       产品要求:输入框输入数据之后,失去焦点后就进行最大最小值校验,以及错误提示。但是angular自带指令max,min,在封装后,要点击确认按钮,form-submit之后才会提示错误。

所以干脆自己写了一个。因为后面又说可以为空,所以就把不能为空这个注释掉了。

备注:

(1)调试时,在html中加上下面这个可以提示是否捕获到了定义的error。{{formValidator.transferCount.$error}}{{item.transferCount}}
 

(2)Html中引用的时候,记得中间加-。

原因:因为HTML对大小写不敏感,而JavaScript对大小写敏感。为了保证HTMLJavaScript都能按原有模式正常工作,AngularJS提出了解决方法:Directive的命名使用驼峰语法,也就是从第二个单词开始,每个单词的首字母大写,并且不使用连接符号HTML代码中,使用连接符的形式。

<input  type="number" ng-maxnum=100 ng-minnum=0 ng-model="subItem.waitVerifyRate" numvalue-check>

(3)因为组内指令都是在formvalidator指令基础上。所以form这里面的类名都要,而且必须是在form中。。

<form class="formform-horizontal form-group"name="formValidator"form-Validator=""novalidate>

novalidate属性是不走h5验证。

(4)其中错误提示,依赖了组内封装的validator服务(formvalidator.js)中定义的validator.showError、validator.removeError、validator.getErrorMessage方法。这3个方法,是统一定制了错误提示的提示形式,并加入了自定义错误提示语句。

(5)而$setValidity(validationErrorKey,isValid)用于改变验证状态,以及在控制变化的验证标准时通知。 validationErrorKey是不通过原因,后面true表示通过,false表示不通过。这个方法应该由一个验证器来调用。例如,一个解析器或者格式化函数。

 (6)对输入框的校验:

除了bind blur事件,然后destroy,用下面的scope.watch也可以。还有$parsers主动识别也可以。

    1.可以用elem.bind,给元素绑定blur事件,并设置blur事件的作用域,ctrl.$viewValue就是当前输入的值。最后用scope.$on('$destroy',解除blur事件的绑定。
    2.也可以用scope.$watch,通过newValue, oldvalue的对比,和newValue的判断,来进行验证。
    3.formSubmit和formRepeat的实现用了$parse。作用:将一个AngularJS表达式转换成一个函数.
 

angular.module('adminApp')
    .directive('numvalueCheck', ['common', 'validator', function (Common, validator) {
        return {
            restrict: "A",
            replace: true,
            require: "?ngModel",
            link: function (scope, elem, attrs, ctrl) {
                var max = scope.$eval(attrs.ngMaxnum);
                var min = scope.$eval(attrs.ngMinnum);
                elem.bind("blur.numvalueCheck", function () {
                    // if (Common.isEmpty(ctrl.$viewValue)) {
                    //     ctrl.$setValidity('required', false);
                    //     validator.showError(elem, validator.getErrorMessages(elem, ctrl.$error));
                    //     return;
                    // } else {
                    //     ctrl.$setValidity('required', true);
                    //     validator.removeError(elem);
                    // };
                    if (ctrl.$viewValue > max || ctrl.$viewValue < min) {
                        ctrl.$setValidity("numvalueCheck", false);
                        validator.showError(elem, validator.getErrorMessages(elem, ctrl.$error));
                        return;
                    } else {
                        ctrl.$setValidity("numvalueCheck", true);
                        validator.removeError(elem);
                    }
                });
                scope.$on('$destroy', function () {
                    elem.unbind("blur.numvalueCheck");
                });

                //  scope.$watch(attrs.ngModel, function (newValue, oldvalue) {
                //     console.log("=====", newValue, oldvalue);
                //     if (!Common.isEmpty(newValue) && (newValue > max || newValue < min)) {
                //         ctrl.$setValidity("numvalueCheck", false);
                //          validator.showError(elem, validator.getErrorMessages(elem, ctrl.$error));
                //         return;
                //     }
                //     else {
                //         ctrl.$setValidity("numvalueCheck", true);
                //          validator.removeError(elem);
                //     }
                // }, true);
            }
        }
    }]);



指令常用的几个属性总结:


1.   restrict [string]-规定指令使用形式

     主要是用来规定指令在HTML代码中可以使用什么表现形式。实际情况中我们一般使用AE这两种方式。

'E': 表示元素,例如<hello></hello>

'A':表示属性,例如<div hello=""></div>

'C'表示类名,样式,例如<divclass=hello:""></div>

'M'表示注释,<!-- directive: hello-->

例子:

1.  <html ng-app="testModule">  

2.  <head>  

3.      <meta charset="utf-8">  

4.      <title>My HTML File</title>  

5.      <link rel="stylesheet" href="css/app.css">  

6.      <link rel="stylesheet" href="css/bootstrap.css">  

7.      <script src="lib/angular/angular.js"></script>  

8.  </head>  

9.  <body ng-controller="testController">  

10.     <input type="text" ng-model="person">  

11.     <hello person="person">  

12.     <div>  

13.         {{person}}  

14.     </div>  

15.     </hello>  

16. <p>{{a}}</p>  

17. <script>  

18.     var testModule=angular.module('testModule',[]);  

19.     testModule.controller('testController',function($scope){  

20.         $scope.person="Tony";  

21.     });  

22.     testModule.directive('hello',function(){  

23.     return{  

24.             restrict: 'E',  

25.             transclude: true,  

26.             scope: {  

27.                'personName''=person'  

28.             },  

29.             template:'<div ng-transclude></div><input type="button" value="click" ng-click="toggle()"><div ng-show="isShow">{{personName}} say hello to us</div>',  

30.             link:function(scope,element,attrs){  

31.                 scope.toggle=function toggle(){  

32.                     scope.isShow=!scope.isShow;  

33.             }  

34.         }  

35.     };  

36.     });  

37. </script>  

38. </body>  

39. </html>  

 

2.   template与templateUrl-引入新的html代码或文件。
template

d放置新的html文本,也可以为文件路径。template[string or function]这个属性,规定了指令被Angular编译和链接(link)后生成的HTML标记,这个属性可以简单到只有一个HTML文本在里面,也可以特别复杂,当该属性的值为function的时候,那么该方法返回的就是代表模板的字符串,同时也可以在里面使用{{}}这个表达式。

 

templateUrl获取模板

 

1templateUrl:"part.html"

有些时候,Directive中的模板template会变得很大,如果仍然放置在定义中,那么可能会造成阅读和修改不方便的情况。

针对这种情况,我们可以将template替换为templateUrl,通过引入外部文件的形式来调用布局。

 

var App = angular.module("App", []);
 
App.directive("formDirective", function () {
    return {
        restrict: "A",
        scope: {
        },
        templateUrl:"part.html"
    }
});
 
App.controller("FirstCtrl", function ($scope) {
 
});
<!DOCTYPE html>
<htmllang="zh"ng-app="App">
<head>
    <metacharset="UTF-8">
    <title>{{"学习AngularJS 1.x"}}</title>
    <linkhref="css/style.css"rel="stylesheet">
</head>
<body>
 
<divng-controller="FirstCtrl">
    <divform-directive></div>
</div>
 
 
<scripttype="text/javascript"src="components/angular/angular.js"></script>
<scripttype="text/javascript"src="js/app.js"></script>
</body>
</html>

,我们还要加入一个新的html文档,命名part.html:

<h1>part.html</h1>
<p>这里是part.html中的内容</p>

 

2ng-template

除了直接将HTML部件存储为独立的文件,我们也可以直接使用AngularJS提供的ng-template功能。这点在第四章中也有提到,这里是一个新的示例,帮助您对比物理文件和ng-template文件的优先级。

 

<scripttype="text/ng-template"id="part.html">
    <h1>通过ng-template封装的part.html</h1>
    <p>这里是part.html中的内容</p>
</script>

 

    要使用这个功能,我们需要在<script>标签中,首先声明type="text/ng-template",并给这段代码进行命名,示例代码中的id="part.html"即是这部分HTML代码片段的命名。使用时,直接调用part.html即可,不需要额外存储一个part.html文件。

     这样进行封装,与函数封装调用的概念类似。当默认HTML进行展示时,是不会显示这段代码的。而通过id调用后,又可以直接展示出来。

注意:通示例我可以看到,文档中的part.html高于独立的HTML文件。

 

(3)使用函数获取templateUrl

templateUrl的特性与我在第四章学ng-include类似,也支持通过函数来获取最终的url地址。

App.directive("formDirective", function () {
    return {
        restrict: "A",
        scope: {},
        templateUrl: function () {
            return"part.html";
        }
    }
});

 


其中,配置路由的时候,用template会走缓存。用template,通过字符串形式引入文件,不走缓存。

            .state('order', {

               url:"/order?rnd",

                templateUrl:"views/order/order.html?rnd=",

               controller:'orderCtrl'

           })

 

           .state('pages-exception-detail', {

                    url:'/pages-exception-detail?id',

                    template:require('./detail/detail.html'),

                    controller:'app.pages.exceptionDetailCtrl',

                    permission:'pages-exception-detail'

               })

 


所以上次那个bug: 一个有权限的人登录成功退出后,无权限的人登录后,本该跳到无权限页,却跳到订单页。后面对403做了判断,重定向到无权限页后,再进行同样的操作,却先跳到订单页,再跳到无权限页。


本地有index的缓存,就不向后端请求index页面了,他就没办法直接拦截请求重定向了。而前端也会走订单页发ajax请求这个流程了,这样就是ajax请求进行的403后的重定向,所以会闪屏。


后面解决办法是给login的回调参数的index.html链接,加了时间戳。

callback = getUrlParam( 'callback') || '/index.html?rnd=' + Date. now();

index.html文件是入口文件,不让走缓存的,可以通过meta设置,或者后端设置http头信息。

< meta http-equiv= "Cache-Control" content= "no-cache, no-store, must-revalidate" >
< meta http-equiv= "Pragma" content= "no-cache" >
< meta http-equiv= "Expires" content= "0" >


index.html页是html写的,order.html页是js写的,给index头部加不缓存,order页却有缓存,因为order页是用templateUrl引入的,会去查缓存。order页加rnd,是在路由点击的时候,页面上信息会刷新。并不是解决缓存问题。所以要用template就好了。


3.   replace[boolean]属性-是否替换定义此指令的HTML元素

这个属性用来规定template生成的HTML内容,是否会替换掉定义此指令的HTML元素。当我们把该属性的值设为true的时候,打开控制台发现这个指令生成的元素, 如果template中的div有name属性,包含这个标签的div也有name属性,name会有变化。

可以AngularJS用替的模式Directive。具体的效果,是会去除掉<people> </people>这对标签

 

App.directive("people", function(){
    return {
        restrict : "E",
        replace : true,
        template : "<p>姓名:{{data.name}}</p><p>性别:{{data.sex}}</p>"
    }
});

4.     require[string or string[]]参数-声明对指令controller实例的引用

声明对controller实例的引用。让父子指令或者兄弟指令的controller之间搭建一个桥梁。也就是说父指令里的controller中的数据能分享给子指令的controller。其中link第四个参数的值是父指令的controller对象的作用域上下文。

require有两个修饰符号:”?”、”^”

? : 如果require没有找到相应的指令避免报错,还能确保程序的正常执行

^ : 表示往父级查找

 

Require: 字符串前可加?、^、 或不加

例子

require: 'ngModel',表示必须有ngModel

require: '?ngModel',表示可以没有ngModel,依赖变为可选项

require:'^he',表示使用he指令的controller

 

require - 请求另外的controller,传入当前directive的link function中。require需要传入一个directive controller的名称。如果找不到这个名称对应的controller,那么将会抛出一个error。名称可以加入以下前缀:

? - 不要抛出异常。这使这个依赖变为一个可选项。

^ - 允许查找父元素的controller

5.   link[function]属性-操作dom的函数

link函数主要是用来添加对DOM元素的事件监听、监视模型属性变化、以及更新DOM的。link函数的执行时机为angular编译此模板之后。它里面4个参数:link:function($scope,elm,attr,controller){}。

(1)scope参数,当前directive的作用域,是否独立由scope参数决定在我们没有为指令定义scope属性的时候,那么他代表的就是父controller的scope。

(2)element参数,指令所在的元素。就是指令的jQLite(jQuery的子集)包装DOM元素。如果你在引入AngularJS之前引入了jQuery,那么这个元素就是jQuery元素,而不是jQLite元素。由于这个元素已经被jQuery/jQLite包装了,所以我们就在进行DOM操作的时候就不需要再使用 $()来进行包装。

elementjQuery的关系:

 

1)在Directive中,我们不免需要对页面元素进行操作。为了提供这项功能,AngularJS几乎原版搬运了jQuery操作元素的功能,他们称之为"jQuery Lite"(jqLite)AngularJS通过jqLite的调用方法angular.element,实现了jQuery中的大部分常用功能。也就是,我们可以在获取了element参数后,调用jQuery常用的语法,如bind(),addClass(),removeClass()等来直接对元素进行操作,实现我们期望的功能。

2)同时,如果你希望在AngularJS中直接使用完整的jQuery也是非常容易的。只需要安装jQuery,并在index.html中,保证在angular.js引入之前引入jQuery.jsAngularJS会自动将angular.element绑定到jQuery上。也就是,在Directive,会自动使用jQuery来解析界面元素,我们获取的element会自动变为jQuery对象。

 

实际体验element的功能:

 

我们在引入jQuery后,可以通过如下代码查看效果:

这里需要注意的是,使用jqLite的方法和以下代码中使用的方法是不一样的,因为jqLite不支持通过标签方式获取子元素。

App.directive("formDirective", function () {
    return {
        restrict: "A",
        template:"<h1>标题</h1><p>这里是段落文字</p>",
        link: function(scope, element, attrs){
            element.children("h1").addClass("strike");
        }
    }
});
<divng-controller="FirstCtrl">
    <divform-directive></div>
</div>

 

 

element上绑定鼠标移入移出时的变化效果

App.directive("formDirective", function () {
    return {
        restrict: "A",
        template:"<h1>标题</h1><p>这里是段落文字</p>",
        link: function(scope, element, attrs){
            element.children("h1").bind("mouseenter", function(){
                element.children("h1").addClass("strike");
                element.children("h1").text("鼠标移过来了");
            });
 
            element.children("h1").bind("mouseleave", function(){
                element.children("h1").removeClass("strike");
                element.children("h1").text("鼠标移开了");
            })
        }
    }
});

运行时,当鼠标移动到标题上,则标题文字会变化成"鼠标移过来了",并加上删除线效果;当鼠标移开,则文字会变为"鼠标移开了"

 

 

(3)attrs参数,directive对应元素的属性,它包含了该指令所在元素的属性的标准化参数对象。

举例的话

<demo attrribute='some attrribute ></demo>

attrs. attrribute就是'some attrribute是写死的,如果想绑定的话必须独立作用域。

 

(4)controller:require里面require的那个参数。

 

提供require进来的directive所提供的方法,如果require了多个,controller将会是一个数或者是require参数中的ngModel

6. scope[boolean or object]属性-传入数据

该属性是用来定义指令的scope的范围,默认情况下是false,也就是说该指令继承了父controller的scope,可以随意的使用父controller的scope里的属性,但是这样的话就会污染到父scope里的属性,这样是不可取的。所以我们可以让scope取以下两个值:true和{}。

当为true的时候,表示让Angular给指令创建一个继承于父scope的scope。

scope:{

    name1:'=name1',

    name2:'@name2',

    name3:'&name3'

}

'=name1':,name1为取标签中的属性名为name1的值对于$scope;若name1为空,即‘=’,则取同名属性的值的$scope,且实现了双向绑定。

'@name2':取标签中name2属性值,若<helloname2="nname22"></hello>,则取的值为nname22

'&name3':name3controller中的$scope同名方法。

(1)用法

在控制器ng-controller的使用过程中,我们使用了$scope功能。$scope用于提供对接HTML和JavaScript对应模块的功能。

    而Directive在默认情况下,是没有自动绑定一个$scope的。也就是说,在默认情况下,Directive无法在JavaScript中接收传入的数据(因为缺少一个存储信息的载体),形成我们期望的效果。但是,Directive提供了非常简单的定义一个scope的功能:

App.directive("people", function(){
    return {
        restrict: "A",
        scope:{
            info: "="
        },
        template : "<p>姓名:{{info.name}}</p><p>性别:{{info.sex}}</p>"
    }
});
 
App.controller("FirstCtrl", function ($scope) {
    $scope.harry = {
        name: "Harry",
        sex : ""
    };
});

 

    注意,这里我将restrict从"E"(element元素)改变成为了"A"(attribute属性),这样它的使用方法有了一些变化:

<divng-controller="FirstCtrl">
    <divpeopleinfo="harry"></div>
</div>

在HTML代码里,我们为div元素配置了一个people的属性和一个info属性;并将FirstCtrl的$scope.harry传入给了info。

 

(2)  scope中的配置:

 

可以看到,在上方的JavaSciprt文件中,我们对scope的定义使用了如下结构:

scope:{
    info: "="
}

首先,scope:{}是告诉这个Directive它需要自己存储信息(类似于建立一个基于这个Directive$scope)

info: "=" 这段配置,告诉DirectiveHTML标签中,获取名为info的属性,并将它的值存储在scope.info中。这样,我们就达到了存储数据的效果。

 

(3)在一个ng-ontroller中放入多个相同的Directive:

下面,我们在FirstCtrl中增加几个人的数据,并将它们通过Directive显示出来:

//FirstCtrl中加入如下代码
 
$scope.anotherPerson = {
    name : "张三",
    sex : ""
};
App.directive("people", function(){
    return {
        restrict: "A",
        scope:{
            info: "="
        },
        template : "<p>姓名:{{info.name}}</p><p>性别:{{info.sex}}</p>"
    }
});
 
<divng-controller="FirstCtrl">
    <divpeopleinfo="harry"></div>
    <divpeopleinfo="anotherPerson"></div>
</div>

 

(4)通过ng-repeat和directive一起显示数据

 

知道了如何传入数据,那么我们就可以将Directive的使用和ng-repeat结合起来,实现列表显示数据的效果。

我们先将FirstCtrl的数据变化为一个array

App.controller("FirstCtrl", function ($scope) {
    $scope. peopleList = [
        {
            name: "Harry",
            sex: ""
        },
        {
            name: "张三",
            sex: ""
        }
    ];
});
App.directive("people", function(){
    return {
        restrict: "A",
        scope:{
            info: "="
        },
        template : "<p>姓名:{{info.name}}</p><p>性别:{{info.sex}}</p>"
    }
});
 
<divng-controller="FirstCtrl">
    <spanng-repeat="person in peopleList">
        <divpeopleinfo="person"></div>
    </span>
</div>

 

(5)在Directive中修改控制器中的数据

方法:将template中原先显示的数据的部分,替换为input即可

App.directive("people", function () {
    return {
        restrict: "A",
        scope: {
            info: "="
        },
        template: "<input type='text' ng-model='info.name'><p>性别:{{info.sex}}</p>"
    }
});
<divng-controller="FirstCtrl">
    {{ peopleList | json}} <!--显示一下其中的数据变化-->
    <spanng-repeat="person in peopleList">
        <divpeopleinfo="person"></div>
    </span>
</div>

 

(6) 以只读的方式传入数据

除了以等号=直接传入对象之外,Directive也支持直接传入字符串文本,使用@符号。

 

App.directive("people", function () {
    return {
        restrict: "A",
        scope: {
            name: "@",
            sex : "@"
        },
        template: "<input type='text' ng-model='name'><p>性别:{{sex}}</p>"
    }
});
<divng-controller="FirstCtrl">
    {{ peopleList | json}}
    <spanng-repeat="person in peopleList">
        <!-- 注意此处的数据传入方法 -->
        <divpeoplename="{{person.name}}"sex="{{person.sex}}"></div>
    </span>
</div>

可以看到,我Directive入的数据行的数据修改,并未反FirstCtrl中。所以是只的方式。

 

 

(7)在Directive中进行函数回调

上面我们介绍了等号=@符号的使用方法,它们分别对应传入对象和文本。但是,如果我们期望传入一个回调函数呢?这样我们就可以实现如封装一个按钮为一个Directive,然后让它在点击后实现我们期望的功能的效果。

这就需要使用到&符号,下面我们来看看实际的例子:

var App = angular.module("App", []);
 
App.directive("formDirective", function () {
    return {
        restrict: "A",
        scope: {
            //这里使用&符号来接受传入的函数
            btnClick: "&"
            //注意:这里没有加入下方的value模型
        },
        template:
        //一个用于输入文字的输入框,绑定到value
        "<input type='text' ng-model='value'><br>" +
            //提交的按钮,绑定上方scopebtnClick方法
            //注意传入参数的方式和HTML中具体使用的方式
        "<input type='button' value='提交'  ng-click='btnClick({message:value})'>"
    }
});
 
App.controller("FirstCtrl", function ($scope) {
    $scope.clickBtnCallback = function (msg) {
        alert("点击了按钮!信息是:" + msg);
    }
});

对应的HTML代码:

<!DOCTYPE html>
<htmllang="zh"ng-app="App">
<head>
    <metacharset="UTF-8">
    <title>{{"学习AngularJS 1.x"}}</title>
    <linktype="text/css"rel="stylesheet"href="css/style.css">
</head>
<body>
<divng-controller="FirstCtrl">
        <!-- 注意这里绑定btn-click/btnClick中传入的参数的命名 -->
        <divform-directivebtn-click="clickBtnCallback(message)"></div>
</div>
 
<scripttype="text/javascript"src="components/angular/angular.js"></script>
<scripttype="text/javascript"src="js/app.js"></script>
</body>
</html>

 

 

 

7. controller[string or function]-指令之间交互

当我们想要允许其他的指令和你的指令发生交互时,我们就需要使用 controller 函数。当另一个指令想要交互时,它需要声明它对你的指令 controller 实例的引用(require)。

例如:

.directive('hello', function() {

   return{

    scope:{},

    require:'^he',

    compile: function (element,attrs){

     return function (scope,elements,attrs,cntIns){

      cntIns.fn()

     };

    }

   }

  })

  .directive('he', function () {

   return{

    restrict:'AE',

    scope:{},

    controller: function ($scope,$compile, $http) {

     this.fn= function () {

      alert('hello');

     };

    }

   }

  })

 

<he>

 <hello color="color"sayhello="sayhello()"></hello>

</he>

 

 

 

8. transclude[boolean]属性-把指令变为一个容器

这个属性用来让我们规定指令是否可以包含任意内容.

 

在前面我们使用到的Directive,都会将包含有Directive的元素整体替换为template中的内容。这样,就让Directive的用途缩减为只能封装最低级别的元素。

但是我们使用的ng-app,ng-controller等,也同样都是Directive,而我们可以在这些元素中,直接填入HTML代码。这是如何实现的呢?这就要应用到Directivetransclude属性。

App.directive("formDirective", function () {
    return {
        restrict: "A",        
        //通过transclude标签将Directive变为一个容器
        transclude: true,
        //注意template中的ng-transclude,这里是放置原有代码的地方。
        template: "<h1>标题</h1><p>这里是段落文字</p><div ng-transclude></div>"
    }
});
<divng-controller="FirstCtrl">
    <divform-directive>
        <p>这段文字是放置在Directive中间的。</p>
    </div>
</div>

 

9. priority[number]属性-规定自定义的指令的优先级

这个属性是来规定自定义的指令的优先级的,当一个DOM元素上面有一个以上的指令的时候,就需要去比较指令的优先级了,优先级高的指令先执行。这个优先级就是用来在执行指令的compile函数前,先排序的。

10. terminal[boolean]属性-否停止当前元素上比本指令优先级低的指令

该参数用来定义是否停止当前元素上比本指令优先级低的指令,如果值为true,就是正常情况,按照优先级高低的顺序来执行,如果设置为false,就不会执行当前元素上比本指令优先级低的指令。

 

11. compile[function]参数-改变原始的dom,在ng创建原始dom实例以及创建scope实例之前使用

该方法有两个参数element,attrs,第一个参数element指指令所在的元素,第二个attrs指元素上赋予的参数的标准化列表。这里我们也有个地方需要注意:compile 函数不能访问 scope,并且必须返回一个 link 函数。但是如果没有设置 compile 函数,你可以正常地配置 link 函数,(有了compile,就不能用link,link函数由compile返回)。

ng-repeat就是一个最好的例子,它就在是compile函数阶段改变原始的dom生成多个原始dom节点,然后每个又生成element实例.

 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值