How to load data into vue.js from an external file

2019-09-01 19:48发布

问题:

in this vue example down below I'm trying to load the 'images' array from an external js file using vue only. I tried something similar to this post: How do I access data from an external file in Vue.js please? but it's not quite working for me (most likely because I'm doing something obvious wrong). Any advice on how to make that work very much appreciated.

I created a codePen for you in case you prefer to look at it this way. Thanks! https://codepen.io/FloydGekko/pen/eLoRBQ

<head>
    <style>
        [v-cloak] {
          display: none;
        }

        .imageBlock{
            width:100%;
            margin:10px;
        }
        div.polaroid {
            width:310px;
            height:440px;
            margin:10px;
            background-color: white;
            box-shadow: 6px 4px 8px 0 rgba(0, 0, 0, 0.2), 6px 6px 20px 0 rgba(0, 0, 0, 0.19);
            margin-bottom: 25px;
            border-radius: 18px
        }
        div.container {
            text-align: center;
            padding: 10px 20px;
        }
    </style>
</head>

<body>

<div id="vue" v-cloak>
    <h2 align="center">
        Show
    <select v-model="currentKind" @change="onChange">
        <option v-for="kind, index in kinds" :value="kind" :key="`kind_${index}`">{{kind ? kind : 'kind...'}}</option>
    </select>
    <select v-model="currentColor" @change="onChange">
        <option v-for="color, index in colors" :value="color" :key="`kind_${index}`">{{color ? color : 'color...'}}</option>
    </select>
        and
     <select v-model="currentShape" @change="onChange">
        <option v-for="shape, index in shapes" :value="shape" :key="`kind_${index}`">{{shape ? shape : 'shape...'}}</option>
    </select>
    </h2>

    <isotope
            id="root_isotope"
            ref="isotope"
            :options='options'
            :list="images"
            align="center">
        <div class="polaroid" align="center"
            v-for="(image, index) in images"
            class="imageBlock"
            :key="image.id">
            <a target="_blank"  :href="image.url"><img border="0" :src="image.pic" alt=""
            style="
                border-radius: 20px;
                display: block;
                margin-left: auto;
                margin-right: auto;
                width: 100%;">
            </a>
            <div class="container">
                <a target="_blank"  :href="image.url">
                <h3 align="center">{{image.title}}</h3>
                </a>
            </div>
        </div>
    </isotope>
    <h2 align="center">
        <button @click="reset">Show all</button>
    </h2>
</div>


<script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js'></script>
<script src='https://npmcdn.com/isotope-layout@3.0.6/dist/isotope.pkgd.min.js'></script>
<script src='https://rawgit.com/David-Desmaisons/Vue.Isotope/master/src/vue_isotope.js'></script>


<script>
    let currentKind = null;
    let currentColor = null;
    let currentShape = null;

    var vm = new Vue({
        el: '#vue',
        data() {
            return {
                currentKind:'',
                currentColor:'',
                currentShape:'',
                options: {
                    itemSelector: ".imageBlock",
                    getSortData: {
                      id: "id"
                    },
                    sortBy : "id",
                    getFilterData: {
                        Finder: function(itemElem) {
                            let kindSearch = currentKind ? itemElem.kind.indexOf(currentKind) !== -1 : true;
                            let colorSearch = currentColor ? itemElem.color.indexOf(currentColor) !== -1 : true;
                            let shapeSearch = currentShape ? itemElem.shape.indexOf(currentShape) !== -1 : true;
                            return kindSearch && colorSearch && shapeSearch
                        },
                    },
                },

        //THIS IS THE ARRAY IM TRYING TO LOAD FROM AN EXTERNAL FILE
                images: [
                    {
                        id: 1,
                        kind: ['A'],
                        color: ['Green', 'Blue'],
                        shape: ['Square'],
                        pic: 'http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg',
                        url: 'http://r.ddmcdn.com/s_f/o_1/cx_462/cy_245/cw_1349/ch_1349/w_720/APL/uploads/2015/06/caturday-shutterstock_149320799.jpg',
                        title: 'A',
                    },
                    {
                        id: 2,
                        kind: ['B'],
                        color: ['Green', 'Red'],
                        shape: ['Circle'],
                        pic: 'https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG',
                        url: 'https://www.kimballstock.com/pix/DOG/05/DOG-05-JE0078-01P.JPG',
                        title: 'B',
                    },
                ],

            };
        },
        computed: {
            kinds(){
                let allTags = _.flatten(this.images.map(image => image.kind))
                return [''].concat(_.uniq(allTags))
            },
            colors(){
                let allTags = _.flatten(this.images.map(image => image.color))
                return [''].concat(_.uniq(allTags))
            },
            shapes(){
                let allTags = _.flatten(this.images.map(image => image.shape))
                return [''].concat(_.uniq(allTags))
            },
        },
        methods: {
            onChange: function() {
                currentColor = this.currentColor;
                currentShape = this.currentShape;
                currentKind = this.currentKind;

                this.$refs.isotope.filter('Finder');
                this.$refs.cpt.layout('packery');
            },
            reset(){
                currentColor = '';
                currentShape = '';
                currentKind = '';

                this.currentColor = '';
                this.currentShape = '';
                this.currentKind = '';
                this.onChange()
            }
        },
    });
</script>
</body>
</html>

https://codepen.io/FloydGekko/pen/eLoRBQ

回答1:

It really depends on what "external" means, and what "Vue only" means. If you have control over the data, it's structure and it's location, you can do something like what @softbear has done - just import a javascript file inside your project. You can do it in numerous ways depending on your setup. His example consists of

<script src="images.js"></script>

which exports something along the lines of

window.images = [{ 'array of images': 'goes here'}]

If you're using Vue you should be able to use the bootstrapped project and just import this from your source files directly.

You can have a backend that provides the same result, and the browser will automatically load it when importing the script.

There are numerous ways but the result is the same. The most important thing here is that this file must declare your variable that should be used later on.


There are few problems with the approach on top: you don't have full control of when to start loading the data, nor when the data is loaded (there are ways to do that, but harder and pretty ugly); some cross domain serves don't allow you to execute js code directly - they can only provide data.

Which means that if you end up in this situation (like connecting to a dynamic set of data and not a hardcoded one), it's always better to make a request to load this data. Basically manually doing what the browser can do for you. But this way you have full (and easy) control of when and how this is done.

Again there are numerous ways - if you're using latest JS in a modern browser you can use the fetch API, or use some external tools like axios.

I would vote for the second approach, despite it might add another dependency to your project.