• Vue
  • 使用Vue构建Ionic混合APP (四):数据存储

    移动书包 2个月前 146次点击 来自 Vue

    大多数应用程序基本都需要保存一些在应用重新加载时需要的数据。我们经常使用用户设备上的本地存储来实现。当使用Ionic/Angular的时候,我们可以简单的使用Ionic内置的 Storage API ,并不需要知道背后的原理——Ionic会自动地选择最合适的存储方式。

    再说一次,在Vue里我们没有现成的东西可以用,是安装一个库还是自己搭建解决方案全决定于我们自己。

    在这篇教程,我们将扩展上篇教程里的Reddit应用,允许我们可以切换多个不同的subreddits方法。我们会存储用户的选择,当重新进入应用时会使用保存的数据。

    开始

    本教程紧跟 前面的教程。如果你想一步步走, 你应该先完成之前的教程。不过, 您可以轻松地将本教程中的概念应用于任何应用程序, 因此如果您不想完成前面的教程也无大碍。

    localForage 和 Ionic 存储模块
    进入代码之前我们先讨论一点理论知识。我们会在ionic-angular库的 Ionic Storage Module 代码的基础上进行。具体点说,我们会参考 the Storage class的代码。

    Ionic使用 localForage来和存储后台交互 。通过使用 localForage 我们可以有一些外部的API进行交互,不用管具体使用了哪个技术: Native SQLite storage, IndexedDB, WebSQL 或者是简单的浏览器的 local storage

    Ionic的存储模块封装了 localForage ,而且根据可用的选择,去自动的设置合适的方法。这意味着如果你使用**Cordova**搭建的应用而且安装了 SQLite 插件,那这个就会用于存储数据。如果 SQLite 不可用它会回头使用 IndexedDB 或者 WebSQL ,如果这些都不可用那么 local storage API 就是最后的选择 。

    我们想在Ionic/Vue应用里模拟这种行为,所以来看看Ionic是怎么做的。我们会专注于 storage.ts里最关键的部分:

    import LocalForage from 'localforage';
    import CordovaSQLiteDriver from 'localforage-cordovasqlitedriver';
    

    **localForage ** 库必须安装和导入,如果我们想支持使用 SQLite ,还需要安装 CordovaSQLiteDriver 。使用SQLite 的好处是我们不需要担心浏览器数据被系统清空。

    constructor(config: StorageConfig) {
      this._dbPromise = new Promise((resolve, reject) => {
        let db: LocalForage;
    
        const defaultConfig = getDefaultConfig();
        const actualConfig = Object.assign(defaultConfig, config || {});
    
        LocalForage.defineDriver(CordovaSQLiteDriver).then(() => {
          db = LocalForage.createInstance(actualConfig);
        })
          .then(() => db.setDriver(this._getDriverOrder(actualConfig.driverOrder)))
          .then(() => {
            this._driver = db.driver();
            resolve(db);
          })
          .catch(reason => reject(reason));
      });
    }
    

    在构造函数 constructor 里创建了一个实例化 localForagePromise 。我们先要定义 CordovaSQLiteDriver ,一旦完成我们可以用构造对象创建一个Local Forage实例。

    默认的Ionic Storage API 的构造是这样的:

    {
      name: '_ionicstorage',
      storeName: '_ionickv',
      driverOrder: ['sqlite', 'indexeddb', 'websql', 'localstorage']
    };
    

    这个配置最重要的部分就是 drivers ,这决定了存储机制的性能。在这个例子里,sqlite是首选, localstorage 是最后的选择。为了确保这些驱动命名正确,用到了下面这个方法:

    _getDriverOrder(driverOrder) {
      return driverOrder.map((driver) => {
        switch (driver) {
          case 'sqlite':
            return CordovaSQLiteDriver._driver;
          case 'indexeddb':
            return LocalForage.INDEXEDDB;
          case 'websql':
            return LocalForage.WEBSQL;
          case 'localstorage':
            return LocalForage.LOCALSTORAGE;
        }
      });
    }
    

    这个方法会映射driver order数组来使用由 localForage 提供的合适的值。如果你不熟悉数组的map方法,你可能会对这个视频感兴趣。基本概念就是map操作会对数组里的每个元素进行一些转换。在这个例子里,我们会使用由 localForage 定义的实际的名称来替换数组里的值。

    剩下的API基本都是一些围绕着 localForage 的方法的简单封装:

    get(key: string): Promise<any> {
      return this._dbPromise.then(db => db.getItem(key));
    }
    
    set(key: string, value: any): Promise<any> {
      return this._dbPromise.then(db => db.setItem(key, value));
    }
    

    所有Ionic存储模块在做的事情就是通过检查dbPromise 的类成员,来确保存储已经完成了正确的实例化。一旦promise完成,getItem 和setItem 方法就会被用来在存储空间里设置(或者销毁)值。

    在Vue里创建Storage服务

    我们可以直接在我们的组件里使用localForage 接口,但是如果我们想做的像Ionic的 Staorage API 那样智能,把它独立到它自己的服务里会更有意义。我们将使用刚才学习到的那些概念,用它们在 Ionic/Vue 应用里来创建一个 Storage服务

    首先,我们需要安装必要的依赖库:

    npm install localforage --save
    npm install localforage-cordovasqlitedriver --save
    

    创建src/services/storage.js文件:

    import LocalForage from ‘localforage’;
    import CordovaSQLiteDriver from ‘localforage-cordovasqlitedriver’;

    export default class Storage {

    dbPromise;

    constructor(){

    this.dbPromise = new Promise((resolve, reject) => {
    
      let db;
    
      let config = {
          name: '_vuestorage',
          storeName: '_vuekv',
          driverOrder: ['sqlite', 'indexeddb', 'websql', 'localstorage']
      }
    
      LocalForage.defineDriver(CordovaSQLiteDriver).then(() => {
        db = LocalForage.createInstance(config);
      })
        .then(() => db.setDriver(this.getDriverOrder(config.driverOrder)))
        .then(() => {
          resolve(db);
        })
        .catch(reason => reject(reason));
    
    });
    

    }

    ready(){
    return this.dbPromise;
    }

    getDriverOrder(driverOrder){

    return driverOrder.map((driver) => {
    
      switch(driver){
        case 'sqlite':
          return CordovaSQLiteDriver._driver;
        case 'indexeddb':
          return LocalForage.INDEXEDDB;
        case 'websql':
          return LocalForage.WEBSQL;
        case 'localstorage':
          return LocalForage.LOCALSTORAGE;
      }
    
    });
    

    }

    get(key){
    return this.dbPromise.then(db => db.getItem(key));
    }

    set(key, value){
    return this.dbPromise.then(db => db.setItem(key, value));
    }

    remove(key){
    return this.dbPromise.then(db => db.removeItem(key));
    }

    clear(){
    return this.dbPromise.then(db => db.clear());
    }

    }

    这只是Ionic Storage API 相同代码的简化版——它或多或少地以同样的方式起作用。为了看起来更友好我留下了一些功能没封装,但是你没有理由不去实现剩下的那些功能。

    使用Storage服务保存和获取数据
    现在,我们要做的是使用我们的服务。保存数据很简单:

    storage.set('something', 'somevalue');
    

    获取数据:

    storage.get('something').then((value) => {
      console.log(value);
    });
    

    修改 src/components/HelloWorld.vue如下:

    <template>
      <ion-app>
        <ion-header>
    
            <ion-navbar>
                <ion-title>REDDIT!</ion-title>
            </ion-navbar>
    
        </ion-header>
    
        <ion-content>
    
          <ion-button @click="switchSubreddit('funny')">Funny</ion-button>
          <ion-button @click="switchSubreddit('gifs')">Gifs</ion-button>
          <ion-button @click="switchSubreddit('worldnews')">Worldnews</ion-button>
    
          <ion-list>
            <ion-item v-for="post in posts" v-bind:key="post.data.id">
              {{post.data.title}}
            </ion-item>
          </ion-list>
    
        </ion-content>
      </ion-app>
    </template>
    
    <script>
    import RedditService from '../services/reddit';
    import Storage from '../services/storage';
    
    const storage = new Storage();
    
    export default {
      name: 'HelloWorld',
      data () {
        return {
          posts: []
        }
      },
      created() {
    
        storage.get('subreddit').then((value) => {
    
          if(value === null){
            value = 'gifs';
          }
    
          RedditService.getPosts(value).then(response => {
            this.posts = response.body.data.children;
          });
    
        });
    
      },
      methods: {
        switchSubreddit(subreddit){
    
          storage.set('subreddit', subreddit);
    
          RedditService.getPosts(subreddit).then(response => {
            this.posts = response.body.data.children;
          });     
    
        }
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    h1, h2 {
      font-weight: normal;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      display: inline-block;
      margin: 0 10px;
    }
    a {
      color: #42b983;
    }
    </style>
    

    我们引入了刚创建的 storage 服务,我们首先在 created 里调用了get方法。 created 方法会在组件已创建就执行,所以它会立即检查storage里subreddit存不存在,如果存在,subreddit值会被用于调用API,如果不存在,默认的使用gifs代替。

    我们也设置了三个按钮以不同的值触发 switchSubreddit 。这个方法会保存新的值到 storage ,然后调用 getPosts 。下次应用重启的时候,保存在 Storage 的值会代替默认的 gifs 被使用。

    备注:如果你没有看之前的教程,你可能不知道如何使用这个模板的组件

    总结

    没有做太多额外的工作,我们就创建了自己的storage服务,和Ionic/Angular应用的存储机制一样的便利和有用。

    目前暂无回复
    关于 广告投放
    ©2016 - 2018 V4.1.6 Powered by 北京雏森科技有限公司