【问题标题】:Vuejs and Request: Computed property function doesnt display GET JSON valueVuejs 和请求:计算属性函数不显示 GET JSON 值
【发布时间】:2017-05-18 07:32:32
【问题描述】:

我有一个 Vue 实例。

// create a root instance
var app = new Vue({
    el: '#app',
    data:
    {
        album: '',
        artist: '',
        link: '',
        genre: '',
        rating: '',
        genres: ["Memphis Rap", "R&B\Soul", "Pop", "Vaporwave", "Alt-Lat"],
        length: 0
    },
    methods: {
        addAlbum: function (event) {
            this.youtubeAlbumList.push({ album: this.album, artist: this.artist, link: this.link, genre: this.genre, rating: this.rating });
            request.post(
                'http://localhost:3000/album',
                { json: { album: this.album, artist: this.artist, link: this.link, genre: this.genre, rating: this.rating } },
                function (error, response, body) {
                    if (!error && response.statusCode == 201) {
                        console.log(body)
                    }
                }
            );
            this.length = this.youtubeAlbumList.length;
            this.album = '';
            this.link = '';
            this.genre = 'Genre';
            this.rating = '';
        }
    },
    computed: {
        albumList:
        {
            get: function () {
                request.get(
                    'http://localhost:3000/album',
                    function (err, res, body) {
                        var info = JSON.parse(body);
                        //.forEach(function(obj) { console.log(obj.id); });
                        return info;
                    }
                )
            }
        }
    }
});

我正在尝试使用 Request 的 get 方法填充“albumList”。服务器成功返回 200 状态码。在开发者工具中,我看到 JSON 正在返回。

问题是列表(尽管很短)未在页面上呈现。为了呈现列表,我使用了以下组件:

Vue.component('album-component', {
    template: ` 
    <div class="content">
            <div class="col-sm-6 col-md-4">
                    <div class="thumbnail">
                    <img src="#" alt="#">
                    <div class="caption">
                        <h3>{{x.album}}</h3>
                        <div class="message-body">
                            <h2>Artist:&nbsp{{x.artist}}</h2>
                            <h3>Link:&nbsp<a v-bind:href="x.link">Link</a></h3>
                            <div>Genre:&nbsp{{x.genre}}</div>
                            <div>Rating:&nbsp{{x.rating}}</div>
                        </div>
                        <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p>
                    </div>
                    </div>
                </div>
            </div>`,
    props: ['album'],
    data: function () {
        return {
            x:this.album
        }
    }
});


// register
Vue.component('youtube-album-list-component', {
    template: `<div class="row">
                    <album-component v-for="album in albumList" :album="album"> </album-component>         
            </div>`
    ,
    props: ['albums'],
    data: function () {
        return {
            albumList: this.albums
        }
    }
})

还有 index.html

 <div id="app">
      <div>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Album</span>
          <input v-model="album" class="form-control" placeholder="Title">
        </div><br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Artist</span>
          <input type="text" class="form-control" placeholder="Name" v-model="artist">
        </div><br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Link</span>
          <input type="text" class="form-control" placeholder="Link" v-model="link">
        </div><br>

        <div v-cloak class="input-group input-group-med">
          <select v-model="genre">
          <option v-for="genre in genres" v-bind:values="genre">{{genre}}</option>
        </select>
        </div>
        <br>
        <div class="input-group input-group-med">
          <span class="input-group-addon">Rating</span>
          <input type="text" class="form-control" placeholder="Rating" v-model="rating">
        </div><br>
      </div>
      <button v-on:click="addAlbum" type="button" class="btn btn-danger btn-lg">Left</button>
      <br>
      <br>
      <div>
        <div class="page-header result-header">
          <h1>Album list</h1>
        </div>
      </div>
      <youtube-album-list-component :albums="albumList"></youtube-album-list-component>
    </div>

我正在尝试将计算出的专辑列表作为道具传递给我的 youtube-album-list-component。然后使用该列表创建专辑组件。我试图弄清楚为什么尽管 info 变量有一个正在返回的数组,但它没有被渲染。有什么想法吗?

【问题讨论】:

  • 属性,无论是计算的还是其他的,都不能是异步的。
  • @MathewJibin Vuejs 通常如何处理渲染异步数据?我是否必须使用 vue-async-computed 之类的东西才能实现该目标?
  • 您必须调用一个操作来请求异步资源,或者您可以在 vue 组件的任何生命周期事件挂钩中执行此操作,然后设置一个支持属性。如果没有进一步处理,您可以绑定到该属性,否则,您可以使用计算属性,该属性将根据支持属性自动更新。
  • @MathewJibin 你能在这种情况下澄清“支持属性”吗? Vuejs 实例之外的东西?
  • 评论变得太长,所以发布了一个答案。看看这是否对你有帮助。享受您的 Vue 之旅。

标签: json vue.js vue-component


【解决方案1】:

你可以重新设计这样的东西, 基本上,您将有一个属性来保存组件的 data 属性中的列表,您使用 ajax 对其进行更新,然后使用您的计算属性进行转换和公开。

Vue.component('album-component',{
template:"#album-template",
props: ['album']
});

Vue.component('youtube-album-list-component', {
template:"#youtube-list-template",
props: ['albums',"isLoading"]
});



var app = new Vue({
    el: '#app',
    data:
    {
        album: '',
        artist: '',
        link: '',
        genre: '',
        rating: '',
        genres: ["Memphis Rap", "R&B\Soul", "Pop", "Vaporwave", "Alt-Lat"],
        length: 0,
        albumStore:[],  //This will be your backing store
        limit:2,  
        isBusy:true
    },
    created:function(){
        var me=this;

      //*********REPLACE WITH YOUR AJAX CALL HERE*********

      //moke a ajax request
      setTimeout(function(){
        me.albumStore.push.apply(me.albumStore,[
        {album:"Album 1",artist:"Artist 1",genre:"Pop",rating:4},
        {album:"Album 2",artist:"Artist 1",genre:"Vaporwave",rating:3},
        {album:"Album 3",artist:"Artist 1",genre:"Memphis Rap",rating:5},
        ]);
        me.isBusy=false;
      },3000);
    },
    methods: {
        addAlbum: function (event) { }
    },
    computed: {
        albumList:
        {
            get: function () {
                    //do some for loop or $.map processing here and return the result.
                  var list=[];
                  for(var i=0; i<this.limit && i < this.albumStore.length;i++)
                  {
                    list.push(this.albumStore[i]);
                  }

                  return list;
               }
         }
    }
});

一个完整的工作fiddle is here。添加功能尚未完成,您可以在此基础上构建或根据自己的喜好对其进行调整。

【讨论】:

  • 我认为“后备存储”通常被称为“初始值”,它更直接和易于理解。
  • 谢谢。我现在明白你所说的“后备商店”是什么意思了。发布问题后,我开始使用“创建前”生命周期事件进行异步调用。它工作得很好,但不如你的答案。最后一个问题:我认为显示异步数据并不是一个不寻常的框架问题,是我还是这个功能是 Vuejs 的弱点?
  • 对不起,我的主要堆栈是 .net 和 c#,它被称为属性的支持字段:)​​。这不是一个弱点,但这是通常推荐的方式,具有默认值的属性,当新值可用时会更新。 vue 中的计算属性用于对已有数据进行转换,而不是用于 aync 操作。复杂场景可以查看Vuex,但是如果你是初学者,建议先熟悉vue的做事方式再考虑vuex..
【解决方案2】:

计算属性不能是异步的,你不能从中调用 API,因为这是异步的,你可以在方法中编写该代码并且它应该可以工作:

 methods: {
        albumList:
        {
            get: function () {
                request.get(
                    'http://localhost:3000/album',
                    function (err, res, body) {
                        var info = JSON.parse(body);
                        //.forEach(function(obj) { console.log(obj.id); });
                        return info;
                    }
                )
            }
        }

如果您坚持或有一个仅在计算属性中具有此功能的强大用例,那么您可以使用 vue-async-computed 之类的东西,这使得在 Vue 中具有异步计算的计算属性成为可能。

但我相信使用方法应该是完全没问题的。

【讨论】:

  • 我尝试了那个解决方案,但是之后,虽然专辑列表仍然被传递到列表组件中,但没有调用 get 函数。但我会研究 vue-async-computed 模块。
  • @TYMG 任何特定原因,你不想使用方法,因为那是 vue 的方法吗?
  • 我尝试过使用 Vue 提供的方法,但我认为我使用不正确。我将尝试 MatthewJbin 的解决方案,因为它不需要外部库。
猜你喜欢
  • 2021-03-22
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
  • 2020-11-23
  • 2020-02-05
相关资源
最近更新 更多