首页 > 代码库 > 离线应用和客户端存储

离线应用和客户端存储


    //region离线检测
    //判断设备是否能上网 navigator.onLine  window事件online offline
    //alert( navigator.onLine );

    //监测网络变化
    W.addHandler( window, "online", function () {
        alert( "online" );
    } );
    W.addHandler( window, "offline", function () {
        alert( "offline" );
    } );
    //endregion

 

    //region应用缓存 描述文件 manifest file P627

    //endregion

//region 数据存储

    //HTTP cookie
    //该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为相应的一部分,其中包括会话信息


    //1.限制
    //cookie在性质上是绑定在特定的域名下的。
    // 当设定了一个cookie后,再给创建他的域名发送请求时,都会包含这个cookie。
    // 这个限制确保了存储在cookie中的信息只能让批准的接受者访问,而无法被其他域访问
    //cookie在客户端计算机大小和数量都有限制 根据浏览器不同单个域下最多20-50个 整个cookie长度限制在2095b


    //2.cookie的构成  只有名值对儿才会被发送到服务器 其他参数都是服务器给浏览器的指示
    // 名称name  需要经过URL编码
    // 值value
    // 域domain
    // 路径path
    // 失效时间expires
    // 安全标志secure

    //设置了secure标志的cookie只能通过SSL加密连接才能传输

    //设置在HTTP头部分
    // HTTP/1.1 200 OK
    //Content-type:text/html
    //Set-Cookie:name-value;expires=Mon,22-Jan-07 07:10:24 GMT;domain=.wrox.com;path=/;secure
    //Other-header:other-header-value

    //3.JavaScript中的cookie
    var CookieUtil = {

        get : function ( name ) {
            var cookieName = encodeURIComponent( name ) + "=",
                    cookieStart = document.cookie.indexOf( cookieName ),
                    cookieValue = http://www.mamicode.com/null;

            if ( cookieStart > -1 ) {
                var cookieEnd = document.cookie.indexOf( ";", cookieStart );

                if ( cookieEnd == -1 ) {
                    cookieEnd = document.cookie.length;
                }

                cookieValue = http://www.mamicode.com/decodeURIComponent( document.cookie.substring( cookieStart + cookieName.length, cookieEnd ) );
            }

            return cookieValue;
        },

        set : function ( name, value, expires, path, domain, secure ) {
            var cookieText = encodeURIComponent( name ) + "=" + encodeURIComponent( value );

            if ( expires instanceof  Date ) {
                cookieText += ";expires=" + expires.toGMTString();
            }

            if ( path ) {
                cookieText += ";path=" + path;
            }

            if ( domain ) {
                cookieText += ";domain=" + domain;
            }

            if ( secure ) {
                cookieText += ";secure";
            }

            document.cookie = cookieText; //并不会覆盖原来的cookie 除非名称已经存在
        },

        unset : function ( name, path, domain, secure ) {
            this.set( name, "", new Date( 0 ), path, domain, secure );
        }
    };

    CookieUtil.set( "name", "zodiac", new Date( "January 1,2020" ) );

    //CookieUtil.unset("name");
    //alert( CookieUtil.get( "name" ) );


    //4.子cookie 为了绕开浏览器对单域名下的cookie的限制,使用子cookie name=name1=value1=&name2=value2 自由操作 但是这样会增加cookie的长度

    var SubCookieUtil = {

        get : function ( name, subName ) {
            var subCookies = this.getAll( name );
            if ( subCookies ) {
                return subCookies[subName];
            }
            else {
                return null;
            }
        },

        getAll : function ( name ) {
            var cookieName = encodeURIComponent( name ) + "=",
                    cookieStart = document.cookie.indexOf( cookieName ),
                    cookieValue = http://www.mamicode.com/null,
                    cookieEnd,
                    subCookies,
                    i,
                    parts,
                    result = {};
            if ( cookieStart > -1 ) {
                cookieEnd = document.cookie.indexOf( ";", cookieStart );

                if ( cookieEnd == -1 ) {
                    cookieEnd = document.cookie.length;
                }

                cookieValue = http://www.mamicode.com/document.cookie.substring( cookieStart + cookieName.length, cookieEnd );

                if ( cookieValue.length > 0 ) {
                    subCookies = cookieValue.split( "&" );

                    for ( i = 0, len = subCookies.length; i < len; i++ ) {
                        parts = subCookies[i].split( "=" );
                        result[decodeURIComponent( parts[0] )] = decodeURIComponent( parts[1] );
                    }

                    return result;
                }
            }
        },


        set : function ( name, subName, value, expires, path, domain, secure ) {

            var subCookies = this.getAll( name ) || {};
            subCookies[subName] = value;
            this.setAll( name, subCookies, expires, path, domain, secure );
        },

        setAll : function ( name, subCookies, expires, path, domain, secure ) {

            var cookieText = encodeURIComponent( name ) + "=",
                    subCookieParts = new Array(),
                    subName;

            for ( subName in subCookies ) {
                if ( subName.length > 0 && subCookies.hasOwnProperty( subName ) ) {
                    subCookieParts.push( encodeURIComponent( subName ) + "=" + encodeURIComponent( subCookies[subName] ) );
                }
            }

            if ( subCookieParts.length > 0 ) {
                cookieText += subCookieParts.join( "&" );

                if ( expires instanceof  Date ) {
                    cookieText += ";expires=" + expires.toGMTString();
                }

                if ( path ) {
                    cookieText += ";path=" + path;
                }

                if ( domain ) {
                    cookieText += ";domain=" + domain;
                }

                if ( secure ) {
                    cookieText += ";secure";
                }
            }
            else {
                cookieText += ";expires=" + (new Date( 0 )).toGMTString();
            }

            document.cookie = cookieText;
        },

        unset : function ( name, subName, path, domain, secure ) {
            var subCookies = this.getAll( name );

            if ( subCookies ) {
                delete subCookies[subName];
                this.setAll( name, subCookies, null, path, domain, secure );
            }
        },

        unsetAll : function ( name, path, domain, secure ) {
            this.setAll( name, null, new Date( 0 ), path, domain, secure );
        }

    };


    //endregion

    //region Web存储机制

    //Storage类型 HTML5 Storage类型都有公共方法setItem getItem removeItem key 大小限制根据浏览器2.5M--5M

    //1.sessionStorage保持到会话结束,即保存到浏览器关闭 合适会话类的小段数据

    sessionStorage.setItem( "name", "zodiac" );//使用方法存储数据
    sessionStorage.age = "22";//使用属性存储数据
    var name = sessionStorage.getItem( "name" );//使用方法获取数据
    var age = sessionStorage.age;//使用属性获取数据
    //sessionStorage.removeItem("name");
    //delete sessionStorage.age     使用delete删除一个值 在Webkit中无效
    // W.log( sessionStorage.key( 0 ) );//逆序获取指定位置上的名字


    //2.localStorage HTML5标准 老版本使用globalStorage 跨会话第存储数据,但有特定的访问限制
    // globalStorage需要指定那些域可以访问该数据
    // 要访问localStorage页面必须来自同一域名(子域名无效),同一协议,同一端口上。相当于globalStorage[location.host]
    //两者的数据都保存到通过JavaScript删除或者用户清除浏览器缓存为止

    //兼容
    function getLocalStorage() {
        if ( typeof localStorage == "object" ) {
            return localStorage;
        }
        else if ( typeof globalStorage == "object" ) {
            return globalStorage[location.host];
        }
        else {
            throw new Error( "Local Storage not available" );
        }
    }

    var localStorage = getLocalStorage();

    localStorage.setItem( "name", "zodiac" );
    //Storage事件 ie8和FireFox只实现了domain属性 WebKit不支持此事件
    // 为Storage对象进行任何修改,都会在文档上触发storage事件 set get remove delete等都会触发
    W.addHandler( document, "storage", function ( event ) {
        var domain = event.domain,
                key = event.key,
                newValue = http://www.mamicode.com/event.newValue,
                oldValue = http://www.mamicode.com/event.oldValue;
    } );


    //endregion


    //region IndexedDB

    //IndexedDB思想是创建一套API,方便保存和读取JavaScript对象,同时还支持查询及搜索
    //IndexedDB操作完全是异步的,大多数操作会以请求进行,但这些操作会在后期执行,如果成功则返回数据,失败则返回错误。
    //差不多每次IndexedDB操作都需要注册onerror和onsuccess事件处理程序,以确保适当地处理结果


    //1.数据库indexedDB本质是一个数据库 和传统数据库不同在于使用对象保存数据,而不是使用表来保存数据。
    //一个indexedDB数据库,就是一组位于相同命名空间下的对象的集合

    var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
    function closeDB( db ) {
        db.close();
    }
    function deleteDB( name ) {
        debugger;
        indexedDB.deleteDatabase( name );
    }

    function openDB( myDB, successHandler, upGradeHandler ) {
        var version = myDB.version || 1,
                request = indexedDB.open( myDB.name, version );

        request.onerror = function ( e ) {
            console.log( e.currentTarget.error.message );
        };
        request.onsuccess = function ( e ) {
            myDB.db = e.target.result;
            successHandler && successHandler();
        };
        request.onupgradeneeded = function ( e ) { //请求数据库版本变化句柄
            console.log( ‘DB version changed to ‘ + version );
            myDB.db = e.target.result;
            upGradeHandler && upGradeHandler();
        };
    }
    function addData( db, storeName, addData ) {
        var transaction = db.transaction( storeName, ‘readwrite‘ ),//打开一个事务,参数一可以为字符串或者数组, 参数二为访问数据的方式readony readwrite
                store = transaction.objectStore( storeName );

        for ( var i = 0; i < addData.length; i++ ) {
            store.add( addData[i] );
        }
    }
    function getDataByKey( db, storeName, value ) {
        var transaction = db.transaction( storeName, ‘readwrite‘ );
        var store = transaction.objectStore( storeName );
        var request = store.get( value );
        request.onsuccess = function ( e ) {
            var student = e.target.result;
            console.log( student.name );
        };
    }
    function updateDataByKey( db, storeName, value ) {
        var transaction = db.transaction( storeName, ‘readwrite‘ );
        var store = transaction.objectStore( storeName );
        var request = store.get( value );
        request.onsuccess = function ( e ) {
            var student = e.target.result;
            student.age = 35;
            store.put( student );
        };
    }
    function deleteDataByKey( db, storeName, value ) {
        var transaction = db.transaction( storeName, ‘readwrite‘ );
        var store = transaction.objectStore( storeName );
        store.delete( value );
    }
    function clearObjectStore( db, storeName ) {
        var transaction = db.transaction( storeName, ‘readwrite‘ );
        var store = transaction.objectStore( storeName );
        store.clear();
    }
    function deleteStore( db, storeName ) {
        db.objectStoreNames.contains( storeName ) && db.deleteObjectStore( storeName );
    }
    //索引是唯一的没问题,如果索引不唯一也只会取到第一个匹配值,要想得到所有符合条件的值就需要使用游标了
    function getDataByIndex( db, storeName, index ) {
        var transaction = db.transaction( storeName );
        var store = transaction.objectStore( storeName );
        var index = store.index( "nameIndex" );
        index.get( index ).onsuccess = function ( e ) {
            var student = e.target.result;
            console.log( student.id );
        }
    }

    //游标 cursor有属性direction key value primaryKey 方法update() delete() continue() advance()
    // cursor.continue(key)如果指定了key会移动打指定key值处 没有则会使游标下移直到没有数据返回undefined。cursor.advance(count)向前移动多少
    function fetchStoreByCursor( db, storeName ) {
        var transaction = db.transaction( storeName );
        var store = transaction.objectStore( storeName );
        var request = store.openCursor();
        request.onsuccess = function ( e ) {
            var cursor = e.target.result;
            if ( cursor ) {
                console.log( cursor.key );
                var currentStudent = cursor.value;
                console.log( currentStudent.name );
                cursor.continue();
            }
        };
    }
    //游标+索引
    function getMultipleData( db, storeName ) {
        var transaction = db.transaction( storeName );
        var store = transaction.objectStore( storeName );
        var index = store.index( "ageIndex" );
        var IDBKeyRange=window.IDBKeyRange||window.webkitIDBKeyRange;
        var request = index.openCursor( IDBKeyRange.only( 26 ));
//        index.openCursor()/index.openKeyCursor()方法在不传递参数的时候会获取object store所有记录,像上面例子一样我们可以对搜索进行筛选
//        可以使用key range 限制游标中值的范围,把它作为第一个参数传给 openCursor() 或是 openKeyCursor()
//         第二个可选参数表示游标方向默认是向后
// 有:IDBCursor.NEXT向后 IDBCursor.NEXT_NO_DUPLICATE跳过重复向后 IDBCursor.PREV向前 IDBCursor.PREV_NO_DUPLICATE跳过重复向前
//        IDBKeyRange.only(value):只获取指定数据
//        IDBKeyRange.lowerBound(value,isOpen):获取最小是value的数据,第二个参数用来指示是否排除value值本身,也就是数学中的是否是开区间
//        IDBKeyRange.upperBound(value,isOpen):和上面类似,用于获取最大值是value的数据
//        IDBKeyRange.bound(value1,value2,isOpen1,isOpen2):不用解释了吧
        request.onsuccess = function ( e ) {
            var cursor = e.target.result;
            if ( cursor ) {
                var student = cursor.value;
                console.log( student.id );
                cursor.continue();
            }
        }
    }
    function getMultipleData( db, storeName ) {
        var transaction = db.transaction( storeName );
        var store = transaction.objectStore( storeName );
        var index = store.index( "nameIndex" );
        var request = index.openCursor( IDBKeyRange.bound( ‘B‘, ‘F‘, false,
                true
        ) );
        request.onsuccess = function ( e ) {
            var cursor = e.target.result;
            if ( cursor ) {
                var student = cursor.value;
                console.log( student.name );
                cursor.continue();
            }
        }
    }
    var myDB = {
        name : "zodiac",
        version : 1,
        db : null
    };

    function successHandler() {

        //在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些object store。

        var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction,

                transaction = myDB.db.transaction( [‘students‘, ‘teacher‘], "readonly" ),


                objectStore = transaction.objectStore( ‘students‘ ); //获取students object store  objectStore相当于表

        //开启事务后插入数据
        addData( myDB.db, ‘students‘, students );
        addData( myDB.db, ‘teacher‘, teacher );
    }

    function upGradeHandler() {//跟新数据库 建表 必须在数据库版本变化后才能执行
        if ( !myDB.db.objectStoreNames.contains( ‘students‘ ) ) {
            var store = myDB.db.createObjectStore( ‘students‘, {keyPath : "id", autoIncrement : true} ); //keyPath主键 keyGenerator其他参数 autoIncrement默认为true
            store.createIndex( ‘ageIndex‘, ‘age‘, {unique : false} ); //创建索引 索引名称 索引属性字段名 索引属性值是否唯一
            store.createIndex( ‘nameIndex‘, ‘name‘, {unique : true} );
        }
        if ( !myDB.db.objectStoreNames.contains( ‘teacher‘ ) ) {
            myDB.db.createObjectStore( ‘teacher‘, {keyPath : "id", autoIncrement : true} );
        }
    }

    var students = [
        {
            id : 1001,
            name : "Byron",
            age : 24
        },
        {
            id : 1002,
            name : "Frank",
            age : 30
        },
        {
            id : 1003,
            name : "Aaron",
            age : 26
        }
    ];
    var teacher = [
        {
            id : 1,
            name : "aa",
            age : 44
        },
        {
            id : 2,
            name : "bb",
            age : 45
        },
        {
            id : 3,
            name : "cc",
            age : 46
        }
    ];

    openDB( myDB, null, upGradeHandler );
    openDB( myDB, successHandler );

    // deleteDB("zodiac");
    //endregion

离线应用和客户端存储