A very good indexdb blog

from here:http://blog.csdn.net/wjb820728252/article/details/71246522?locationNum=1&fps=1


最近做一个webapp,需要将webview的数据存储到本地数据库,鉴于Android和webview传递大量数据比较麻烦,所以干脆直接存储在webview内置的本地数据库算了。
LocalStore
没有时间限制的本地存储,是上面三种存储方式中浏览器默认存储的容量最小的,也是最容易使用的,直接一句话完成存储过程。
存储数据:

localStorage.XXX=YYY
  
  
  • 1

XXX可以随便命名,YYY是要存储的数据,可以是任何数据类型。
例如:

localStorage.status=true
  
  
  • 1

localstore适合做少量数据的存储,一般用来存储网站某个变量的状态之类的

清除数据,有两种方式:
1) 删除一条数据

localStorage.removeItem(“key”);
  
  
  • 1

Key对应上面的XXX
2)批量删除数据

localStorage.clear();
  
  
  • 1

在浏览器可以看到其存储的数据,例如Google Chrome:
按F12查看开发者工具,然后点击上面的Application
这里写图片描述
重点来了,localStore在webview怎么用不了!!
原因是webView默认没有启动localStore功能的服务,需要我们自己手动去开启服务:

WebSettings settings = webview.getSettings();
settings.setDomStorageEnabled(true);
  
  
  • 1
  • 2

localStore用法比较简单,就介绍到这里,下面讨论一下websql的使用:

Websql
是当前最多浏览器支持的本地数据库,可以说目前主流的浏览器都支持了,手机的WebView 也不例外(WebView使用Websql也需要开启服务,这点我们下面再说)。
Websql是一个轻量级的本地数据库,存储量达到几百万条数据以上,使用起来也是相当简单的,支持原生的sql语句(SELECT、INSERT、DELETE、UPDATE),下面简单介绍用法:

1)、打开websql数据库用函数openDatabase();

db = openDatabase(“数据库名”, "版本号", "数据库的描述信息", 数据库的大小);
  
  
  • 1

一个完整的例子:

var db = null;
try {
    if (window.openDatabase) {
        db = openDatabase(“myDB”, "1.0", "Database example", 10*1024*1024);
} catch(err) {
    db = null;
    alert("打开数据库失败");
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2)、创建表(注意,一切对表的操作都要使用事务),并且使用executeSql 函数

//executeSql函数有四个参数(第一个参数必填,后三个可以不写),函数原型如下:
void executeSql(in DOMString sqlStatement, in optional ObjectArray arguments, in optional SQLStatementCallback callback, in optional SQLStatementErrorCallback errorCallback);
  
  
  • 1
  • 2

参数意义分别:
sqlStatement:是原生的sql语句。

例如:CREATE TABLE test (id, name)
  
  
  • 1

ObjectArray:上一句sql语句中的占位符“?”所对应的参数,空则写“[]”

例如:select name from student where id=?,[001]
  
  
  • 1

callback:本次sql操作成功后的回调接口,数据会被返回
errorCallback:本次sql操作失败后的回调接口,失败信息会被返回

创建一张test表:

db.transaction(function(tx) {
    tx.executeSql('CREATE TABLE test (id, name)');
});
  
  
  • 1
  • 2
  • 3

3)、插入(INSERT)操作

db.transaction(function (tx){
     tx.executeSql("INSERT INTO test (id, name) VALUES ( ?, ?)", [001, “Biao”]);
});
  
  
  • 1
  • 2
  • 3

4)、查询(SELECT)操作

db.transaction(function(tx) {
        tx.executeSql("SELECT * FROM test ", [], function(tx, result) {
           // result就是查询到的结果
        }, function(tx, error) {
            alert('查询失败 ' + error.message);
            return;
        });
});
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5)、更新(UPDATE)操作

db.transaction(function (tx){
    tx.executeSql("UPDATE test SET name = ? WHERE id = ?", [“wu”, 001]);
});
  
  
  • 1
  • 2
  • 3

6)、删除(DELETE)操作

db.transaction(function(tx){
tx.executeSql("DELETE FROM test WHERE id = ?", [001]);});
  
  
  • 1
  • 2

表创建成功之后同样也可以在web浏览器的开发者工具上看到数据(例如:谷歌浏览器)

这里写图片描述

以上就是Websql的四个主要操作了。

那么问题又来了,怎么Android Webview用不了Websql呢?

这里写图片描述

刚才已经说了,Websql是目前浏览器支持最为广泛的一个内置的本地数据库,没有之一,并且Android的Webview也已经支持了,但是,Webview默认是没有开启这个服务的,还是得我们自己开启,操作步骤如下:

WebSettings settings = webview.getSettings();
//设置与Js交互的权限
settings.setJavaScriptEnabled(true);
//设置数据库可用
settings.setDatabaseEnabled(true);
String dbPath = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabasePath(dbPath);

//然后
webview.setWebChromeClient(new MyChromeViewClient());

class MyChromeViewClient extends WebChromeClient {
//重写这个方法就OK 了
@Override
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater){
    //设置数据库存储大小
    quotaUpdater.updateQuota(estimatedSize * 2);
    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

现在就可以在Webview上使用websql了

websql对数据的操作尽然不比localStore存储方便,但是这两个是没法比的,Websql存储数据是以一张张表的形式存在,存储量比localStore大多了。而且它对数据的操作还是我们相当熟悉的SQL语句。总而言之,方便好用。

但是!!大家有没有发现,我们再看看对数据的操作,全部得手写原生SQL语句!!SELECT INSERT UPDATE DELETE,当数据表的字段非常多的时候,所有字段都得我们自己去写入。不知道大家会不会觉得烦,反正我是烦了。

幸亏有IndexDB
indexDB 支持本地存储大量对象,并使用健壮的数据访问机制检索数据。插入数据支持直接使用JSON数据,关键的是它不需要我们手写原生SQL语句来对数据进行查增删改。

下面简单介绍其用法
创建或者打开数据库

window.indexedDB.open(dbName, 1);
  
  
  • 1

参数意义:
dbName:数据库的名称
1:版本号

1)、创建表

db.createObjectStore(tbName,{"keyPath":"keyID", autoIncrement:true});  
  
  
  • 1

参数意义:
tbName:表名称
{“keyPath”:”keyID”, autoIncrement:true}:设置字段keyid为主键,并且设置自动自增属性
可以添加字段,例如,添加name 字段
objectStore.createIndex(“name”, “name”,{unique:false});
参数意义:
“name”:字段名
“name”:设置字段name为索引,设置为索引后在查询的时候可以以name字段进行查询,加快查询速度。
{unique:false}:设置属性:不唯一。换句话说就是可以存在相同名字的数据

2)、插入数据(INSERT):

INDEXDB 和 WebSQL一样,对数据处理的时候要使用到事务

//获取事务
var transaction = database.transaction([tableName], model);
//参数意义:
//tableName:要操作的表名
//model:模式,有两种,readwrite(可读可写) 和readonly(只读)

//获取表
var objectStore = transaction.objectStore(tableName);

var request = objectStore.put(date);
request.onerror = function(event) {
     alert("发生错误:" + request.error);
};
request.onsuccess = function(event) {
     alert("数据保存成功");
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

大家可以看到,上面没有出现字段名就完成对数据的插入了,上面的date是一个JS对象,只要把数据转换为JS对象数据就可以利用函数objectStore.put(date);插入数据了,其实也可以利用函数objectStore.add(date);插入数据。
如果是JSON 数据 可以利用$.parseJSON(data)来将JSON数据转成JS对象,然后对数据进行插入操作
这里写图片描述

put和add方法的区别在于,put插入数据的话

如果主键存在表中,那么就把旧数据更新
如果主键不存在表中,就插入一条新的数据。

add插入数据的话

如果主键存在表中,那么就会报错
如果主键不存在表中,就插入一条新的数据。

3)、查询数据(SELECT):

3.1)获取一条数据用函数get(key);

var transaction = database.transaction([tableName], model);
var objectStore = transaction.objectStore(tableName);
//key是主键的某一个值
var request = objectStore.get(key);
request.onerror=function(e){
    alert("发生错误:" + request.error);
};
request.onsuccess=function(e){
    var result=e.target.result;
    console.log("获取数据成功");
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.2)获取所有数据用函数getAll();

var transaction = database.transaction([tableName], model);
var objectStore = transaction.objectStore(tableName);
var request = objectStore.getAll();
request.onerror=function(e){
    alert("发生错误:" + request.error);
};
request.onsuccess=function(e){
    var result=e.target.result;
    console.log("获取数据成功");
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

但是getAll()函数不推荐使用,貌似已经废弃了,反正我在平板Android4.4.2的webview上面不能使用

3.3)推荐使用openCursor()利用游标的方式来进行查询多条数据,功能非常强大, 可以利用索引加快查询速度,还可以指定搜索的范围。

var transaction = database.transaction([tableName], model);
var objectStore = transaction.objectStore(tableName);
objectStore.openCursor().onsuccess = function(event) {  
        var cursor = event.target.result;  
        if (cursor) {  
            var rowData = cursor.value;  
            for (var Key in rowData){
                console.log("查询的数据"+Key[0]);          
            }
            cursor.continue();  
            console.log(“1”);  
        }else{
        console.log(“2”);  
    }  
}  
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

cursor.continue(); 表示,查询到了继续向前走,直至查询到所有结果截止。
注意,它和JAVA里面for循环的continue不一样,java的continue不会执行continue以后的语句,但是,cursor.continue();还是会执行以后的代码,例如上面的console.log(“1”);会一直被执行到。

但是!!

console.log(“2”);只会被执行一次,因为当cursor为空的时候,代表语句查询到所有结果了。

3.4)利用索引加快查询速度index(‘name’) name字段必须在一开始添加字段的时候给它设置为索引,如下:

objectStore.createIndex(“name”, “name”,{unique:false});

var transaction = database.transaction([tableName], model);
var objectStore = transaction.objectStore(tableName);
objectStore.index(‘name’).openCursor().onsuccess = function(event) {  
        var cursor = event.target.result;  
        if (cursor) {  
            var rowData = cursor.value;  
            for (var Key in rowData){
                console.log("查询的数据"+Key[0]);          
            }
            cursor.continue();  
            console.log(“1”);  
        }else{
            console.log(“2”);  
    }  
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.5) 指定搜索的范围
使用到IDBKeyRange属性

Range           Code
//例如我上面指定主键是id , 意思就是查询id<=X的数据
//All keys ≤ x  IDBKeyRange.upperBound(x)
//查询id<X的数据
//All keys < x  IDBKeyRange.upperBound(x, true)
//查询id>=y的数据
//All keys ≥ y  IDBKeyRange.lowerBound(y)
//查询id>y的数据
//All keys > y  IDBKeyRange.lowerBound(y, true)
//All keys ≥ x && ≤ y   IDBKeyRange.bound(x, y)
//All keys > x &&< y    IDBKeyRange.bound(x, y, true, true)
//All keys > x && ≤ y   IDBKeyRange.bound(x, y, true, false)
//All keys ≥ x &&< y    IDBKeyRange.bound(x, y, false, true)
//查询id==z的数据
//The key = z   IDBKeyRange.only(z)
//查询id<=X的数据
var transaction = database.transaction([tableName], model);
var objectStore = transaction.objectStore(tableName);
objectStore.openCursor(IDBKeyRange.upperBound(x)).onsuccess = function(event) {  
    var cursor = event.target.result;  
        if (cursor) {  
            var rowData = cursor.value;  
            for (var Key in rowData){
                console.log("查询的数据"+Key[0]);          
            }
            cursor.continue();  
            console.log(“1”);  
        }else{
            console.log(“2”);  
    }  
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

3.6)删除数据《2017.7.10 更新》
删除数据,indexDB的操作很简单

/** 
 * 删除数据  
 * 
 */ 
function deleteData(tbName,value){
    var objectStore = initDB(tbName,"readwrite");
    var request=objectStore.delete(IDBKeyRange.only(parseInt(value)));
    request.onerror=function(e){
        alert("发生错误:" + request.error);
    };
    request.onsuccess=function(e){
        var result=e.target.result;
        alert("删除数据成功");
    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

注意:用delete()方法,传值一定得是创建表的index索引,否则删除失败,例如

objectStore = db.createObjectStore(personDoc,{"keyPath":"keyID", autoIncrement:true});  
  
  
  • 1

上面的代码是指在创建表中指定索引为keyID ,是一个自增值,整型,因此index索引是一个数值,IDBKeyRange.only(parseInt(value))这个就表示只删除索引值为value值的数据。

以上简单介绍了IndexDB的部分用法,总体来说,indexDB的学习成本不高,但其实用性和方便性很强。需要深入学习的朋友可以去MDN(链接)学习。

怎么在Android 的 webview上使用,可以参考websql的设置,他们两个是一样的,当然在浏览器上面也是可以看到indexDB数据库存储的数据的。例如:谷歌浏览器

这里写图片描述

最后贴上一份indexDB 的样例代码

$(function(){
    //全局数据库对象
    var database;
    //数据库的名称
    var dbName='HealDoc';
    //数据表
    var tbName='disease';
    //表字段
    var field="idcard/id/visitDate/visitWay/curSymptom/pressureH/pressureL/avoirdupois/bmi/arteriopalmus/smokeNum/drinkNum/trainingRate/trainingTime/rice/mentality/compiance/lastFbg/hgbde/hgbdedate/subCheck/dependence/sideEffects/effectsState/lowEffects/visitType/drugname/drugperday/drugpertime/drugname2/drugperday2/drugpertime2/drugname3/drugperday3/drugpertime3/insulin/insulinperday/insulinpertime/referralreason/referralagencies/nextDate/inputIdcard";
    //创建数据库
    var request = window.indexedDB.open(dbName, 1);
    request.onsuccess = function(event) {
        //让数据库 可在任何地方访问
        database = request.result;

    };
    request.onerror = function (event) {
        alert("发生错误:" + request.error);
    };
    request.onupgradeneeded = function(event) {
        alert("第一次创建数据库或者更新数据库。");
        db = request.result;  
        //创建表 
        var objectStore = db.createObjectStore(tbName,{"keyPath":"keyID", autoIncrement:true});  
        var fields=new Array();
        fields=field.split("/");
        for (var i = 0; i < fields.length; i++) {
            objectStore.createIndex(fields[i],fields[i],{unique:false});
        }
    }

    //对数据库处理得先初始化数据库
    //参数一:表名
    //参数二:操作数据库的模式 有两种:readwrite 和readonly
    function initDB(tableName,model){
        //获取事务
        var transaction = database.transaction([tableName], model);
        //获取表
        var objectStore = transaction.objectStore(tableName);
        return objectStore;
    }


    function insert(date){
        var objectStore=initDB("disease","readwrite");
        //add 或者put
        var request = objectStore.put(date);
            request.onerror = function(event) {
                alert("发生错误:" + request.error);
            };
            request.onsuccess = function(event) {
                alert("数据保存成功");
            };
    }
    function selectSingle(key){
        var objectStore=initDB("disease","readonly");
        var request=objectStore.get(key);
        request.onerror=function(e){
            alert("发生错误:" + request.error);
        };
        request.onsuccess=function(e){
            var result=e.target.result;
            console.log(result);
        }
    }
    function selectAll(){
        var objectStore = initDB("disease","readonly");
        var response="";
        // 打开游标,遍历customers中所有数据  
        objectStore.openCursor().onsuccess = function(event) {  
            var cursor = event.target.result;  
            if (cursor) {  
                var rowData = cursor.value;  
                for (var Key in rowData){
                    response =response+Key+":"+rowData[Key]+"\n";
                }
                response+="\n\n\n"
                cursor.continue();  
            }  
            $('#output').val(response);
        }  
    }
    $('#submitButton').click(function(){
        var date = {};
        var t = $('#yourformid').serializeArray();
       // var str="";
        $.each(t, function() {
          date[this.name] = this.value;
       // str+=this.name+"/"
        });
         insert(date);
        return false;
    });
    $('#close').click(function(){
        selectAll();
    });
});

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

最后的最后,小弟不才,只能简述到这里了,如果有错误,请不吝赐教,如果有帮助到您的话,请留下一个start,O(∩_∩)O谢谢!



thanks for the writer:http://blog.csdn.net/WuLex/article/details/51882222?locationNum=2&fps=1

IndexedDBtest.htm内容如下:

  1. <!DOCTYPE html>  
  2. <html >  
  3.     <head>  
  4.         <title></title>  
  5.         <script src="js/indexDb.js" type="text/javascript"></script>  
  6.         <script type="text/javascript">  
  7.             function init() {  
  8.                 var dbParams = new Object();  
  9.                 dbParams.db_name = "SISO";  
  10.                 dbParams.db_version = "2";  
  11.                 dbParams.db_store_name = "Test";  
  12.                 dbObject.init(dbParams);  
  13.             }  
  14.   
  15.             function Tinsert() {  
  16.                 // 填入初始值  
  17.                 dbObject.put({ title: "Quarry Memories", author: "Fred", isbn: 123456 }, 1);  
  18.                 dbObject.put({ title: "Water Buffaloes", author: "Fred", isbn: 234567 }, 2);  
  19.                 dbObject.put({ title: "Bedrock Nights", author: "Barney", isbn: 345678 }, 3);  
  20.             }  
  21.   
  22.             function Tselect() {  
  23.                 dbObject.select(3);  
  24.             }  
  25.   
  26.             function Tupdate() {  
  27.                 dbObject.put({ title: "Quarry wu", author: "lex", isbn: 123456 }, 1);  
  28.             }  
  29.   
  30.             function Tdelete() {  
  31.                 dbObject.delete(3);  
  32.             }  
  33.   
  34.             function Tclear() {  
  35.                 dbObject.clear();  
  36.             }  
  37.         </script>  
  38.     </head>  
  39.     <body onload=" init() ">  
  40.         <input type="button" value="新增几条数据" onclick=" Tinsert(); "/>  
  41.         <input type="button" value="查找一条记录" onclick=" Tselect(); "/>  
  42.         <input type="button" value="删除一条记录" onclick=" Tdelete(); "/>  
  43.         <input type="button" value="更新一条记录" onclick=" Tupdate(); "/>  
  44.         <input type="button" value="清除所有表数据" onclick=" Tclear(); "/>  
  45.     </body>  
  46. </html>  
indexDb.js内容如下:

[javascript] view plain copy
  1. (function(){  
  2.     var dbObject = {};   
  3.     dbObject.init = function(params){  
  4.         this.db_name = params.db_name;  
  5.         this.db_version = params.db_version;  
  6.         this.db_store_name = params.db_store_name;  
  7.         if (!window.indexedDB)   
  8.         {  
  9.             window.alert("你的浏览器不支持IndexDB,请更换浏览器");  
  10.         }  
  11.   
  12.         var request = indexedDB.open(this.db_name,this.db_version);  
  13.         //打开数据失败  
  14.         request.onerror = function(event)   
  15.         {   
  16.             alert("不能打开数据库,错误代码: " + event.target.errorCode);  
  17.         };  
  18.         request.onupgradeneeded = function(event)   
  19.         {  
  20.             this.db = event.target.result;   
  21.             this.db.createObjectStore(dbObject.db_store_name);  
  22.         };  
  23.         //打开数据库  
  24.         request.onsuccess = function(event)   
  25.         {  
  26.             //此处采用异步通知. 在使用curd的时候请通过事件触发  
  27.             dbObject.db = event.target.result;  
  28.         };  
  29.     };  
  30.     /** 
  31.      * 增加和编辑操作  
  32.      */  
  33.     dbObject.put = function(params,key)  
  34.     {  
  35.         //此处须显式声明事物  
  36.         var transaction = dbObject.db.transaction(dbObject.db_store_name, "readwrite");  
  37.         var store = transaction.objectStore(dbObject.db_store_name);  
  38.         var request = store.put(params,key);  
  39.         request.onsuccess = function(){  
  40.             alert('添加成功');  
  41.         };  
  42.         request.onerror = function(event){  
  43.             console.log(event);  
  44.         }  
  45.     };  
  46.     /** 
  47.      * 删除数据  
  48.      */  
  49.     dbObject.delete = function(id)  
  50.     {  
  51.         // dbObject.db.transaction.objectStore is not a function  
  52.         request = dbObject.db.transaction(dbObject.db_store_name, "readwrite").objectStore(dbObject.db_store_name).delete(id);  
  53.         request.onsuccess = function(){  
  54.             alert('删除成功');  
  55.         }  
  56.     };  
  57.   
  58.     /** 
  59.      * 查询操作  
  60.      */  
  61.     dbObject.select = function(key)  
  62.     {  
  63.         //第二个参数可以省略  
  64.         var transaction = dbObject.db.transaction(dbObject.db_store_name,"readwrite");  
  65.         var store = transaction.objectStore(dbObject.db_store_name);  
  66.         if(key)  
  67.             var request = store.get(key);  
  68.         else  
  69.             var request = store.getAll();  
  70.   
  71.         request.onsuccess = function () {  
  72.             console.log(request.result);  
  73.         }  
  74.     };  
  75.     /** 
  76.      * 清除整个对象存储(表) 
  77.      */  
  78.     dbObject.clear = function()  
  79.     {  
  80.         var request = dbObject.db.transaction(dbObject.db_store_name,"readwrite").objectStore(dbObject.db_store_name).clear();  
  81.         request.onsuccess = function(){  
  82.             alert('清除成功');  
  83.         }  
  84.     };   
  85.     window.dbObject = dbObject;  
  86. })();  

结果如下:

添加:

查询:

更新:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值