刷官方中文angularJs手册例子

Hello World

<!doctype html>
<html ng-app>
    <head>
        <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    </head>
    <body>
        Hello {{'World'}}!
    </body>
</html>
  1. 注意事项:
    • ng-app 标记ng-app告诉AngularJS处理整个HTML页并引导应用
    • 载入AngularJs脚本 <‘script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    • Hello {{‘World’}}! {{}}用于绑定的表达式

Hello AngularJS World!

<!doctype html>
<html ng-app>
    <head>
        <script src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
    </head>
    <body>
        Your name: <input type="text" ng-model="yourname" placeholder="World">
        <hr>
        Hello {{yourname || 'World'}}!
    </body>
</html>
  1. 注意事项:
    • 文本输入指令<input ng-model="yourname" />绑定到一个叫yourname的模型变量
    • 双大括号标记将yourname模型变量添加到问候语文本。
    • 在输入框中输入将会在问候语文本出立即更新显示,这就是AngularJS双向数据绑定的概念
    • 输入框的任何更改会立即反映到模型变量(一个方向),模型变量的任何更改都会立即反映到问候语文本中(另一方向)

AngularJS应用的解析

模板(Templates)

  1. 注意事项:
    • 模板就是展示应用的视图

应用程序逻辑(Logic)和行为(Behavior)

  1. 注意事项:
    • 应用程序逻辑和行为是您用JavaScript定义的控制器。AngularJS与标准AJAX应用程序不同,您不需要另外编写侦听器或DOM控制器,因为它们已经内置到AngularJS中了

模型数据(Data)

  1. 注意事项:
    • 模型是从AngularJS作用域对象的属性引申的。
    • 模型中的数据可能是Javascript对象、数组或基本类型,这都不重要,重要的是,他们都属于AngularJS作用域对象。
    • AngularJS通过作用域来保持数据模型与视图界面UI的双向同步。一旦模型状态发生改变,AngularJS会立即刷新反映在视图界面中,反之亦然。

此外,AngularJS还提供了一些非常有用的服务特性:

  1. 注意事项:
    • 底层服务包括依赖注入,XHR、缓存、URL路由和浏览器抽象服务。
    • 您还可以扩展和添加自己特定的应用服务。
    • 这些服务可以让您非常方便的编写WEB应用。

搭建学习环境

需要安装Node.js和Testacular来运行本项目

安装Node.js后运行

node --version

安装Testacular运行以下代码

npm install -g testacular

安装Git工具 clone项目

git clone git://github.com/angular/angular-phonecat.git

app/index.html

<!doctype html>
<html lang="en" ng-app>
<head>
    <meta charset="utf-8">
    <title>My HTML File</title>
    <link rel="stylesheet" href="css/app.css">
    <link rel="stylesheet" href="css/bootstrap.css">
    <script src="lib/angular/angular.js"></script>
</head>
<body>
<p>Nothing here {{'yet' + '!'}}</p>
</body>
</html>
  1. 注意事项:
    • ng-app指令:标记了AngularJS脚本的作用域在<html>中添加ng-app属性即说明整个<html>都是AngularJS脚本作用域
    • AngularJS脚本标签:即 <’script src=“lib/angular/angular.js”>载入angular.js,页面加载完成后,angular.js会寻找ng-app标签,该标签就是angularjs的作用域
    • 双大括号绑定的表达式:AngularJS模板的核心功能——绑定,这里的是绑定大括号{{}}与表达式'yet' + '!'组成
    • AngularJS表达式仅在AngularJS的作用域中运行,而不是在整个DOM中运行。

引导AngularJS应用

  1. AngularJS应用引导过程有3个重要点:
    • 注入器(injector)将用于创建此应用程序的依赖注入(dependency injection)
    • 注入器将会创建[根作用域]作为我们应用模型的范围;
    • AngularJS将会链接根作用域中的DOM,从用ngApp标记的HTML标签开始,逐步处理DOM中指令和绑定。
    • 一旦AngularJS应用引导完毕,它将继续侦听浏览器的HTML触发事件,如鼠标点击事件、按键事件、HTTP传入响应等改变DOM模型的事件。这类事件一旦发生,AngularJS将会自动检测变化,并作出相应的处理及更新。

更改表达式内容

<p>1 + 2 = {{ 1 + 2 }}</p>

结果
在这里插入图片描述

AngularJS模板

<html ng-app>
<head>
  ...
  <script src="lib/angular/angular.js"></script>
  <script src="js/controllers.js"></script>
</head>
<body ng-controller="PhoneListCtrl">

  <ul>
    <li ng-repeat="phone in phones">
      {{phone.name}}
    <p>{{phone.snippet}}</p>
    </li>
  </ul>
</body>
</html>
  1. 注意事项:
    • 一个视图是模型通过HTML模板渲染之后的映射,这意味着,不论模型什么时候发生变化,AngularJS会实时更新结合点,随之更新视图。
    • ng-repeat是angularjs的迭代器
    • <li>标签里面的ng-repeat="phone in phones"语句是一个AngularJS迭代器。这个迭代器告诉AngularJS用第一个<li>标签作为模板为列表中的每一部手机创建一个<li>元素。
    • 包裹在phone.namephone.snippet周围的花括号标识着数据绑定。和常量计算不同的是,这里的表达式实际上是我们应用的一个数据模型引用,这些我们在PhoneListCtrl控制器里面都设置好了。

模型和控制器

PhoneListCtrl控制器里面初始化了数据模型

app/js/controller.js

function PhoneListCtrl($scope) {
  $scope.phones = [
    {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S."},
    {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet."},
    {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet."}
  ];
}
  1. 注意事项:
    • 控制器允许我们建立模型和视图之间的数据绑定。我们是这样把表现层,数据和逻辑部件联系在一起的
    • PhoneListCtrl——控制器方法的名字(在JS文件controllers.js中)和<body>标签里面的[ngController][]指令的值相匹配。
    • 手机的数据此时与注入到我们控制器函数的作用域$scope)相关联。当应用启动之后,会有一个根作用域被创建出来,而控制器的作用域是根作用域的一个典型后继。这个控制器的作用域对所有<body ng-controller="PhoneListCtrl">标记内部的数据绑定有效。
    • AngularJS的作用域理论非常重要:一个作用域可以视作模板、模型和控制器协同工作的粘接器

测试

test/unit/controllersSpec.js:

describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){

    it('should create "phones" model with 3 phones', function() {
      var scope = {},
      ctrl = new PhoneListCtrl(scope);

      expect(scope.phones.length).toBe(3);
    });
  });
});
  1. 注意事项:
    • AngularJS的开发者倾向于使用Jasmine行为驱动开发(BBD)框架中的语法
    • 基于AngularJS的项目被预先配置为使用[JsTestDriver]来运行单元测

没看懂······没找到./scripts/test.sh或者bat文件·····

迭代器

<div class="container-fluid">
  <div class="row-fluid">
    <div class="span2">
      <!--Sidebar content-->

      Search: <input ng-model="query">
      <h1>Google Phone Gallery: {{query}}</h1>
    </div>
    <div class="span10">
      <!--Body content-->

      <ul class="phones">
        <li ng-repeat="phone in phones | filter:query">
          {{phone.name}}
        <p>{{phone.snippet}}</p>
        </li>
      </ul>

   	</div>
  </div>
</div>

使用AngularJS的[$filter]函数来处理[ngRepeat]指令的输入
这样允许用户输入一个搜索条件,立刻就能看到对电话列表的搜索结果

  1. 注意事项:
    • 数据绑定:当页面加载的时候,AngularJS会根据输入框的属性值名字,将其与数据模型中相同名字的变量绑定在一起,以确保两者的同步性。
    • 用户在输入框中输入的数据名字称作query,会立刻作为列表迭代器(phone in phones | filter:query`)其过滤器的输入。当数据模型引起迭代器输入变化的时候,迭代器可以高效得更新DOM将数据模型最新的状态反映出来。
    • 使用filter过滤器:[filter][]函数使用query的值来创建一个只包含匹配query记录的新数组。

test
index.html模板中添加一个{{query}}绑定来实时显示query模型的当前值
在这里插入图片描述

页面正加载的时候它们已经显示给用户看了。一个更好的解决方案是使用[ngBind]或者[ngBindTemplate]指令,它们在页面加载时对用户是不可见的
没看懂。。。。。

双向绑定

模板

  <body ng-controller="PhoneListController">
  Search: <input ng-model="query">
  Sort by:
  <select ng-model="orderProp">
      <option value="name">Alphabetical</option>
      <option value="age">Newest</option>
  </select>
  <ul class="phones">
      <li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
          {{phone.name}}
          <p>{{phone.snippet}}</p>
          <p>{{phone.age}}</p>
      </li>
  </ul>
  </body>

控制器

phonecatApp.controller('PhoneListController', function PhoneListController($scope) {
  $scope.phones = [
    {"name": "Nexus S",
      "snippet": "Fast just got faster with Nexus S.",
      "age": 2},
    {"name": "Motorola XOOM™ with Wi-Fi",
      "snippet": "The Next, Next Generation tablet.",
      "age": 1},
    {"name": "MOTOROLA XOOM™",
      "snippet": "The Next, Next Generation tablet.",
      "age": 3}
  ];
  $scope.orderProp = 'age';
});
  1. 注意事项:
    • 增加了一个叫做orderProp<select>标签,这样我们的用户就可以选择我们提供的两种排序方法
    • filter过滤器后面添加一个[orderBy]过滤器用其来处理进入迭代器的数据。orderBy过滤器以一个数组作为输入,复制一份副本,然后把副本重排序再输出到迭代器。
    • 我们在控制器代码里加了一行让orderProp的默认值为age.如果我们不设置默认值,这个模型会在我们的用户在下拉菜单选择一个顺序之前一直处于未初始化状态。

XHR和依赖注入

app/js/controllers.js

function PhoneListCtrl($scope, $http) {
  $http.get('phones/phones.json').success(function(data) {
    $scope.phones = data;
  });

  $scope.orderProp = 'age';
}

//PhoneListCtrl.$inject = ['$scope', '$http'];

为了使用AngularJS的服务,你只需要在控制器的构造函数里面作为参数声明出所需服务的名字

function PhoneListCtrl($scope, $http) {...}

参数名字非常重要,因为注入器会用他们去寻找相应的依赖。

’$'前缀命名习惯

AngularJS内建服务,作用域方法,以及一些其他的AngularJS API都在名字前面使用一个‘ ’ 前 缀 。 不 要 使 用 ‘ ’前缀。不要使用‘ 使’前缀来命名你自己的服务和模型,否则可能会产生名字冲突。

angular.
  module('phoneList').
  component('phoneList', {
    templateUrl: 'phone-list/phone-list.template.html',
    controller: ['$http', function PhoneListController($http) {
      var self = this;
      self.orderProp = 'age';

      $http.get('phones/phones.json').then(function(response) {
        self.phones = response.data;
      });
    }]
  });

链接与图片模板

json片段

[
 {
  ...
  "id": "motorola-defy-with-motoblur",
  "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg",
  "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
  ...
 },
...
]

app/index.html

        <ul class="phones">
          <li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
            <a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
            <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
            <p>{{phone.snippet}}</p>
          </li>
        </ul>
  1. 注意事项:
    • 这些链接将来会指向每一部电话的详细信息页,我们在href属性里面使用我们早已熟悉的双括号数据绑定
    • 同样为每条记录添加手机图片,只需要使用[ngSrc]指令代替<img>src属性标签就可以了
    • 如果我们仅仅用一个正常src属性来进行绑定(<img class="diagram" src="{{phone.imageUrl}}">),浏览器会把AngularJS的{{ 表达式 }}标记直接进行字面解释,并且发起一个向非法urlhttp://localhost:8000/app/{{phone.imageUrl}}的请求
    • 因为浏览器载入页面时,同时也会请求载入图片,AngularJS在页面载入完毕时才开始编译

路由与多视图

多视图,路由和布局模板

布局模板

  • 为了增加详细信息视图,我们可以拓展index.html来同时包含两个视图的模板代码,但是这样会很快给我们带来巨大的麻烦。相反,我们要把index.html模板转变成“布局模板”。即所有画面通用的模板,其他的“局部布局模板”随后根据当前的路由被充填入,从而形成一个完整视图展示给用户。

路由

  • AngularJS中应用的路由通过[$routeProvider]来声明,它是[$route]服务的提供者。

关于依赖注入(DI),注入器(Injector)和服务提供者(Providers)

  1. 注意事项:
    • 当应用引导时,AngularJS会创建一个注入器,我们应用后面所有依赖注入的服务都会需要它
    • 注入器唯一的职责是载入指定的服务模块,在这些模块中注册所有定义的服务提供者,并且当需要时给一个指定的函数注入依赖(服务)这些依赖通过它们的提供者“懒惰式”(需要时才加载)实例化。
    • 提供者是提供(创建)服务实例并且对外提供API接口的对象,它可以被用来控制一个服务的创建和运行时行为。对于$route服务来说,$routeProvider对外提供了API接口,通过API接口允许你为你的应用定义路由规则。
    • AngularJS模块解决了从应用中删除全局状态和提供方法来配置注入器这两个问题

APP的路由规则

angular.module('phonecat', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/phones', {templateUrl: 'partials/phone-list.html',   controller: PhoneListCtrl}).
      when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
      otherwise({redirectTo: '/phones'});
}]);

PhoneListCtrl控制器

angular.
  module('phoneList').
  component('phoneList', {
    templateUrl: 'phone-list/phone-list.template.html',
    controller: ['$http', function PhoneListController($http) {
      var self = this;
      self.orderProp = 'age';

      $http.get('phones/phones.json').then(function(response) {
        self.phones = response.data;
      });
    }]
  });

PhoneDetailCtrl控制器

function PhoneDetailCtrl($scope, $routeParams) {
  $scope.phoneId = $routeParams.phoneId;
}

路由规则如下

  • 当URL 映射段为/phones时,手机列表视图会被显示出来。为了构造这个视图,AngularJS会使用phone-list.html模板和PhoneListCtrl控制器。
  • 当URL 映射段为/phone/:phoneId时,手机详细信息视图被显示出来。这里:phoneId是URL的变量部分。为了构造手机详细视图,AngularJS会使用phone-detail.html模板和PhoneDetailCtrl控制器。
angular.
  module('phonecatApp').
  config(['$routeProvider',
    function config($routeProvider) {
      $routeProvider.
        when('/phones', {
          template: '<phone-list></phone-list>'
        }).
        when('/phones/:phoneId', {
          template: '<phone-detail></phone-detail>'
        }).
        otherwise('/phones');
    }
  ]);

创建phonecatApp模块注入$routeProvider服务提供配置路由规则

  • $route.otherwise({redirectTo: '/phones'})语句使得当浏览器地址不能匹配我们任何一个路由规则时,触发重定向到/phones
  • :phoneId参数的使用$route服务使用路由声明/phones/:phoneId作为一个匹配当前URL的模板。所有以:符号声明的变量(此处变量为phones)都会被提取,然后存放在[$routeParams]对象中
  1. 注意事项:
    • 为了给我们的应用配置路由,我们需要给应用创建一个模块。我们管这个模块叫做phonecat,并且通过使用configAPI,我们请求把$routeProvider注入到我们的配置函数并且使用$routeProvider.whenAPI来定义我们的路由规则。

为了让我们的应用引导我们新创建的模块,我们同时需要在[ngApp]指令的值上指明模块的名字
app/index.html

<!doctype html>
<html lang="en" ng-app="phonecat">
...

模板
$route服务通常和[ngView]指令一起使用。ngView指令的角色是为当前路由把对应的视图模板载入到布局模板中
如下所示

<html lang="en" ng-app="phonecat">
<head>
...
  <script src="lib/angular/angular.js"></script>
  <script src="js/app.js"></script>
  <script src="js/controllers.js"></script>
</head>
<body>

  <div ng-view></div>

</body>
</html>

删除的模板放置在phone-list.html中

<div class="container-fluid">
  <div class="row-fluid">
    <div class="span2">
      <!--Sidebar content-->

      Search: <input ng-model="query">
      Sort by:
      <select ng-model="orderProp">
        <option value="name">Alphabetical</option>
        <option value="age">Newest</option>
      </select>

    </div>
    <div class="span10">
      <!--Body content-->

      <ul class="phones">
        <li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
          <a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
          <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
          <p>{{phone.snippet}}</p>
        </li>
      </ul>

    </div>
  </div>
</div>

同时我们为手机详细信息视图添加一个占位模板。
phone-detail.html

TBD: detail view for {{phoneId}}

注意到我们的布局模板中没再添加PhoneListCtrlPhoneDetailCtrl控制器属性!

更多模板

app/phones/nexus-s.json(样例片段)

{
  "additionalFeatures": "Contour Display, Near Field Communications (NFC),...",
  "android": {
      "os": "Android 2.3",
      "ui": "Android"
  },
  ...
  "images": [
      "img/phones/nexus-s.0.jpg",
      "img/phones/nexus-s.1.jpg",
      "img/phones/nexus-s.2.jpg",
      "img/phones/nexus-s.3.jpg"
  ],
  "storage": {
      "flash": "16384MB",
      "ram": "512MB"
  }
}

一部手机的具体信息
控制器
使用$http服务获取数据,以此来拓展PhoneListCtrl
为了构造HTTP请求的URL,我们需要$route服务提供的当前路由中抽取$routeParams.phoneId

function PhoneDetailCtrl($scope, $routeParams, $http) {
      function PhoneDetailController($http, $routeParams) {
        var self = this;
        $http.get('phones/' + $routeParams.phoneId + '.json').then(function(response) {
          self.phone = response.data;
        });
      }
}

模板
phone-detail.html文件中原有的TBD占位行已经被列表和构成手机详细信息的绑定替换掉了
这里我们使用AngularJS的{{表达式}}标记和ngRepeat来在视图中渲染数据模型
app/partials/phone-detail.html

<img ng-src="{{phone.images[0]}}" class="phone">

<h1>{{phone.name}}</h1>

<p>{{phone.description}}</p>

<ul class="phone-thumbs">
  <li ng-repeat="img in phone.images">
    <img ng-src="{{img}}">
  </li>
</ul>

<ul class="specs">
  <li>
    <span>Availability and Networks</span>
    <dl>
      <dt>Availability</dt>
      <dd ng-repeat="availability in phone.availability">{{availability}}</dd>
    </dl>
  </li>
    ...
  </li>
    <span>Additional Features</span>
    <dd>{{phone.additionalFeatures}}</dd>
  </li>
</ul>

过滤器

配置过滤器命名为checkmark它的输入要么是true,要么是false

angular.module('phonecatFilters', []).filter('checkmark', function() {
  return function(input) {
    return input ? '\u2713' : '\u2718';
  };
});

现在我们的过滤器准备好了,我们需要将我们的phonecatFilters模块作为一个依赖注册到我们的主模块phonecat上。

index添加依赖

 <script src="js/controllers.js"></script>
 <script src="js/filters.js"></script>

在AngularJS模板中使用过滤器的语法是:

{{ expression | filter }}

我们把过滤器应用到手机详细信息模板中:phone-detail.html

    <dl>
      <dt>Infrared</dt>
      <dd>{{phone.connectivity.infrared | checkmark}}</dd>
      <dt>GPS</dt>
      <dd>{{phone.connectivity.gps | checkmark}}</dd>
    </dl>

事件处理器

控制层方法

function PhoneDetailCtrl($scope, $routeParams, $http) {
  $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
    $scope.phone = data;
    $scope.mainImageUrl = data.images[0];
  });

 $scope.setImage = function(imageUrl) {
    $scope.mainImageUrl = imageUrl;
  }
}

phone-detail.html

<img ng-src="{{mainImageUrl}}" class="phone">

...

<ul class="phone-thumbs">
  <li ng-repeat="img in phone.images">
    <img ng-src="{{img}}" ng-click="setImage(img)">
  </li>
</ul>
...

把大图片的ngSrc指令绑定到mainImageUrl属性上。
同时我们注册一个[ngClick]处理器到缩略图上
当一个用户点击缩略图的任意一个时,这个处理器会使用setImage事件处理函数来把mainImageUrl属性设置成选定缩略图的URL。

REST和定制服务

需要在布局模板中引入这个文件
也要加载angularjs-resource.js这个文件,它包含了ngResource模块以及其中的$resource服务

...
  <script src="js/services.js"></script>
  <script src="lib/angular/angular-resource.js"></script>
...

services.js

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
      return $resource('phones/:phoneId.json', {}, {
        query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
      });
    });

使用模块API通过一个工厂方法注册了一个定制服务。我们传入服务的名字Phone和工厂函数。工厂函数和控制器构造函数差不多,它们都通过函数参数声明依赖服务。Phone服务声明了它依赖于$resource服务。

[$resource]服务使得用短短的几行代码就可以创建一个[RESTful]客户端。我们的应用使用这个客户端来代替底层的[$http]服务。
app/js/app.js

angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).

我们需要把phonecatServices添加到phonecat的依赖数组里。

控制器

通过重构掉底层的[$http]服务,把它放在一个新的服务Phone中,我们可以大大简化子控制器(PhoneListCtrlPhoneDetailCtrl)。AngularJS的[$resource]相比于$http更加适合于与RESTful数据源交互。而且现在我们更容易理解控制器这些代码在干什么了。

app/js/controllers.js

...

function PhoneListCtrl($scope, Phone) {
  $scope.phones = Phone.query();
  $scope.orderProp = 'age';
}

//PhoneListCtrl.$inject = ['$scope', 'Phone'];



function PhoneDetailCtrl($scope, $routeParams, Phone) {
  $scope.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) {
    $scope.mainImageUrl = phone.images[0];
  });

  $scope.setImage = function(imageUrl) {
    $scope.mainImageUrl = imageUrl;
  }
}

//PhoneDetailCtrl.$inject = ['$scope', '$routeParams', 'Phone'];

注意到,在PhoneListCtrl里我们把:

$http.get('phones/phones.json').success(function(data) {
  $scope.phones = data;
});

换成了:

$scope.phones = Phone.query();

我们通过这条简单的语句来查询所有的手机。

另一个非常需要注意的是,在上面的代码里面,当调用Phone服务的方法是我们并没有传递任何回调函数。尽管这看起来结果是同步返回的,其实根本就不是。被同步返回的是一个“future”——一个对象,当XHR相应返回的时候会填充进数据。鉴于AngularJS的数据绑定,我们可以使用future并且把它绑定到我们的模板上。然后,当数据到达时,我们的视图会自动更新。

有的时候,单单依赖future对象和数据绑定不足以满足我们的需求,所以在这些情况下,我们需要添加一个回调函数来处理服务器的响应。PhoneDetailCtrl控制器通过在一个回调函数中设置mainImageUrl就是一个解释。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值