尝试使用Vue.JS保存到本地存储时出错

时间:2019-06-26 15:27:37

标签: javascript vue.js

我从rest api获取数据,在我的应用程序中,我有两个组件。

1-(主)显示结果 2-(列表)显示从主要结果中选择的项目列表

我希望能够对list(2)组件有一个保存按钮,因此我可以保存从api中选择的项的列表。我得到的错误是:

Error in mounted hook: "SyntaxError: Unexpected token u in JSON at position 0"

列出组件

    <template>
      <div class="mb-5 mt-5 container">
        <div class="list-group">
          <a href="#" class="list-group-item list-group-item-action active">
            My List
            <span class="badge badge-light">{{List.length}}</span>
          </a>
          <a
            href="#"
            class="list-group-item list-group-item-action"
            v-for="(result, index) in List"
            :key="index"
          >
            {{result.collectionName}}
            <br>
            <b>{{result.artistName}}</b>
            <br>
            <div class="row">
              <div class="col-md-6">
                <button
                  class="btn btn-success btn-sm btn-block"
                  v-on:click="removeElement(index)"
                >Remove</button>
              </div>
              <div class="col-md-6">
                <button
                  class="btn btn-info btn-sm btn-block"
                  @click="toAlbum(result)"
                >View on iTunes</button>
              </div>
            </div>
          </a>
        </div>
        <button class="btn btn-info mt-5 btn-lg btn-block" @click="saveList()">Save</button>
      </div>
    </template>
    <script>
    export default {
      name: "List",
      props: ["List"],
      mounted() {
    if(localStorage.result) this.result = JSON.parse(this.result);
  },

      methods: {
          saveList() {
          localStorage.result = this.result;
          localStorage.setItem('result', JSON.stringify(this.result));   
          /* eslint-disable no-console */
          console.log(localStorage.result.length + 'List Saved');
          /* eslint-disable no-console */
        },
        removeElement: function(index) {
          this.List.splice(index, 1);
        },
        resizeArtworkUrl(result) {
          return result.artworkUrl100.replace("100x100", "160x160");
        },
        toiAlbum(result) {
          window.open(result.collectionViewUrl, "_blank");
        }
      }
    };
    </script>
    <style scoped>
    .album-cover {
      width: 100%;
      height: auto;
      background-color: aqua;
    }
    .album-container {
      height: 350px;
    }
    </style>

主要组件

<template>
      <div class="container search">
        <div class="row">
          <div class="col-md-8">
     <div class="jumbotron mt-5" style="clear:both">
          <h1 class="display-4">{{title}}</h1>
          <p class="lead">{{intro}}</p>
          <hr class="my-4">
          <p v-if="validated" :class="errorTextClass">Enter a valid search term</p>
          <button
            type="button"
            class="btn btn-primary btn-lg mb-3"
            v-on:click="refreshPage"
            v-if="result.length > 1"
          >
            <font-awesome-icon icon="redo"/> Start again
          </button>
          <input
            class="form-control form-control-lg mb-3"
            type="search"
            placeholder="Search"
            aria-label="Search"
            v-model="search"
            required
            autocomplete="off"
            id="search"
          >
          <div v-for="(result, index) in result" :key="index">
            <div class="media mb-4">
              <img
                :src="resizeArtworkUrl(result)"
                alt="Album Cover"
                class="album-cover align-self-start mr-3"
              >
              <div class="media-body">
                <h4 class="mt-0">
                  <!-- <button
                    type="button"
                    class="btn btn-primary btn-lg mb-3 float-right"
                    v-on:click="addItem(result)"
                  >
                    <font-awesome-icon icon="plus"/>
                  </button>-->
                  <button
                    type="button"
                    class="btn btn-primary btn-lg mb-3 float-right"
                    v-on:click="addItem(result)"
                    :disabled="result.disableButton"
                  >
                    <font-awesome-icon icon="plus"/>
                  </button>
                  <b>{{result.collectionName}}</b>
                </h4>
                <h6 class="mt-0">{{result.artistName}}</h6>
                <p class="mt-0">{{result.primaryGenreName}}</p>
              </div>
            </div>
          </div>
          <div :class="loadingClass" v-if="loading"></div>
          <button
            class="btn btn-success btn-lg btn-block mb-3"
            type="submit"
            v-on:click="getData"
            v-if="result.length < 1"
          >
            <font-awesome-icon icon="search"/>Search
          </button>
        </div>
          </div>
          <div class="col-md-4">
        <List :List="List"/>

          </div>
        </div>
        <!-- <div class='div' v-bind:class="[isActive ? 'red' : 'blue']" @click="toggleClass()"></div> -->

      </div>
    </template>
    <script>
    import List from "../components/myList.vue";
    export default {
      name: "Hero",
      components: {
        List
      },
      data: function() {
        return {
          title: "Simple Search",
          isActive: true,
          intro: "This is a simple hero unit, a simple jumbotron-style.",
          subintro:
            "It uses utility classes for typography and spacing to space content out.",
          result: [],
          errors: [],
          List: [],
          search: "",
          loading: "",
          message: false,
          isValidationAllowed: false,
          loadingClass: "loading",
          errorTextClass: "error-text",
          disableButton: false
        };
      },
      watch: {
        search: function(val) {
          if (!val) {
            this.result = [];
          }
        }
      },
      computed: {
        validated() {
          return this.isValidationAllowed && !this.search;
        },
        isDisabled: function() {
          return !this.terms;
        }
      },
      methods: {
        getData: function() {
          this.isValidationAllowed = true;
          this.loading = true;
          fetch(`https://api.results.com/api`)
            .then(response => response.json())
            .then(data => {
              this.result = data.results;
              this.loading = false;
              /* eslint-disable no-console */
              console.log(data);
              /* eslint-disable no-console */
            });
        },
        toggleClass: function() {
          // Check value
          if (this.isActive) {
            this.isActive = false;
          } else {
            this.isActive = true;
          }
        },
        refreshPage: function() {
          this.search = "";
        },
        addItem: function(result) {
          result.disableButton = true; // Or result['disableButton'] = true;
          this.List.push(result);
          /* eslint-disable no-console */
          console.log(result);
          /* eslint-disable no-console */
        },
        resizeArtworkUrl(result) {
          return result.artworkUrl100.replace("100x100", "160x160");
        },
        toiTunesAlbum (result) {
            window.open(result.collectionViewUrl, '_blank')
          }
      }
    };
    </script>
    <style>
    .loading {
      background-image: url("../assets/Rolling-1s-42px.gif");
      background-repeat: no-repeat;
      height: 50px;
      width: 50px;
      margin: 15px;
      margin-left: auto;
      margin-right: auto;
    }
    .error-text {
      color: red;
    }
    .media {
      text-align: left;
    }
    .album-cover {
      width: 80px;
      height: auto;
    }
    .red {
      background: red;
    }
    .blue {
      background: blue;
    }
    .div {
      width: 100px;
      height: 100px;
      display: inline-block;
      border: 1px solid black;
    }
    </style>

任何想法将不胜感激。我已经将本地存储添加到列表组件中,而不是主要组件中,我不知道这是否合适或应该这样做。

2 个答案:

答案 0 :(得分:0)

您似乎正在尝试解析LAMBDA=$1 CURRENTVARIABLES=$(aws lambda get-function-configuration --function-name $LAMBDA | jq '.Environment.Variables') NEWVARIABLES=$(echo $CURRENTVARIABLES | jq '. += {"kick":"'$(getrandom 8)'"}') COMMAND="aws lambda update-function-configuration --function-name $LAMBDA --environment '{\"Variables\":$NEWVARIABLES}'" eval $COMMAND

在您的undefined钩中,我看到:

mounted

我认为您需要使用:

if(localStorage.result) this.result = JSON.parse(this.result);

因为此结果将在开始时未定义

答案 1 :(得分:0)

您基本上正在执行JSON.parse(undefined),这将引发错误。您应该使用try/catch来处理这种情况:

function willThrow() {
  JSON.parse(undefined); // Execution would stop with this
}

// Vs.

function willCatch() {
  try {
    JSON.parse(undefined);
  } catch (err) {
    console.log(err);
  }
}

考虑以下代码(由于针对localStorage的同源策略,以下代码段实际上不会运行):

const app = new Vue({
  el: "#app",
  data() {
    return {
      result: ""
    };
  },
  mounted() {
    /*
     * If this program has never run before, then localStorage.result
     * is the literal: undefined.  Trying to parse undefined will 
     * throw an exception.  You should wrap the JSON.parse() in
     * a try/catch to handle this case.
     */

    try {
      if (localStorage.result) this.result = JSON.parse(this.result);
    } catch (err) {
      console.error(err);
    }
  }
});
<script src="https://unpkg.com/vue"></script>

<div id="app">{{result}}</div>