使用 Vue 访问嵌套的 JSON

Posted

技术标签:

【中文标题】使用 Vue 访问嵌套的 JSON【英文标题】:Accessing nested JSON with Vue 【发布时间】:2019-01-24 16:51:26 【问题描述】:

我正在尝试使用 Vue 访问数组中的嵌套 JSON 进行基本搜索。每所学校都包装在一个“命中”数组中,因此它认为只有一个“命中”结果,而不是返回每所学校的数据。我确定我只需要为每个学校实例添加命中,但我不确定如何。感谢您的帮助。

我的主应用文件:

<template>
    <div class="app search">
        <!-- Search header -->
        <header id="searchHeader" class="search--header py-2 py-md-4">
            <div class="container">
                <div class="input-group">
                    <!-- Type filter -->
                    <TypeFilter v-model="type"/>

                    <!-- Location filter -->
                    <!--<LocationFilter />-->

                    <!-- Search box -->
                    <SearchBox v-model="searchTerm"/>

                    <!-- More filters -->
                    <!--<div class="dropdown checkbox-dropdown mx-2">
                        <button class="btn btn-lg btn-white py-3 px-4 dropdown-toggle" type="button" id="dropdownMenuButtonFilters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">More Filters</button>
                        <div class="dropdown-menu" aria-labelledby="dropdownMenuButtonFilters">
                        </div>
                    </div>-->

                    <!-- Search button -->
                    <button v-on:click="searchSubmit(searchTerm)" class="btn btn-lg btn-white ml-2 px-4 search-submit">Search</button>
                </div>

                <!-- Active filters (hidden for v0) -->
                <!--<div class="search--header--filters mt-3">
                    <span class="badge">Filter</span>
                    <span class="badge">Filter</span>
                    <span class="badge">Filter</span>
                </div>-->
            </div>
        </header>

        <!-- Main results -->
        <div class="container">
             message 

            <!-- Result count and show/sort -->
            <ResultCount v-model="page" :items="schools.length" :perPage="10"/>

            <!-- Results -->
            <SchoolList :schools="pageOfSchools"/>

            <!-- Pagination -->
            <Pagination v-model="page" :items="schools.length" :perPage="10"/>
        </div>
    </div>
</template>

<script>
    import SchoolList from './SchoolList'
    import ResultCount from './ResultCount'
    import Pagination from './Pagination'
    import SearchBox from './SearchBox'
    import TypeFilter from "./TypeFilter";
    import LocationFilter from "./LocationFilter";
    import getArraySection from '../utilities/get-array-section'
    //import schools as schoolData from '../data'

    export default 
        name: 'app',
        components: SchoolList, ResultCount, Pagination, SearchBox, TypeFilter, LocationFilter,
        data: () => (
            searchTerm: '',
            type: '',
            //schools: [],
            schools: [
                
                    "hit": [
                        "title": "State Peter Pan Institute",
                    , 
                        "title": "State Flatland University",
                    , 
                        "title": "State Applewood Halls of Ivy",
                    ]
                
            ],
            page: 1,
            message: ''
        ),
        computed: 
            pageOfSchools: function () 
                return getArraySection(this.schools, this.page, 10)
            
        ,
        watch: 
            /*searchTerm: function () 
                this.filterSchools()
            ,
            type: function () 
                this.filterSchools()
            */
        ,
        methods:     
            filterSchools: function () 
                const searchTerm = this.searchTerm.toLowerCase()
                const type = this.type
                let result = schoolData

                if (searchTerm) 
                    result = result.filter(school => 
                        return (
                            school.title.toLowerCase().search(searchTerm) >= 0 ||
                            school.location.toLowerCase().search(searchTerm) >= 0
                        )
                    )
                

                if (type) 
                    result = result.filter(school => school.type.indexOf(type) >= 0)
                

                this.schools = result
                this.page = 1
            
        ,
        created: function () 
            this.filterSchools()
        
    
</script>

我的 SchoolList 组件:

<template>
    <Transition name="swap" mode="out-in">
        <div class="school-list" :key="schools">
            <div class="row">
                <div class="col-md-8 search--results">
                    <School class="school row justify-content-between search--results--card my-2 pt-2 pb-3 border-bottom" v-for="school in schools" :item="school" :key="school"/>
                </div>

                <div class="col-md-4 mt-4 pl-md-6 search--results--featured">
                    <FeaturedList />
                </div>
            </div>
        </div>
    </Transition>
</template>

<script>
    import School from './School'
    import FeaturedList from './FeaturedList'

    export default 
        name: 'school-list',
        components: School, FeaturedList,
        props: ['schools']
    
</script>

<style scoped>
    .swap-enter-active, .swap-leave-active 
        transition: opacity 0.2s ease-in-out;
    

    .swap-enter, .swap-leave-active 
        opacity: 0;
    

    .swap-enter 
        opacity: 1;
    
    .swap-leave-to 
        opacity: 0;
    
</style>

我的学校组件:

<template>
    <div>
        <div class="col-9 col-md-auto d-flex align-items-center card-body">
            <img v-bind:src="item.logo" class="logo mr-2 mr-md-4 p-2 bg-white rounded-circle">
            <div>
                <h5 class="mb-0"><a :href="item.url" class="text-dark"> item.title </a></h5>
                <p class="mb-0"> item.location </p>
                <TypeLabel class="badge type-label mt-2" v-for="type in item.type" :type="type" :key="type"/>
                <span class="badge badge-yellow mt-2">Featured</span>
            </div>
        </div>
        <div class="col-3 col-md-auto text-right">
            <button type="button" class="btn btn-link d-inline-flex px-2 save"><i></i></button>
            <button type="button" class="btn btn-link d-inline-flex px-2 share"><i></i></button>
            <a data-placement="top" data-toggle="popoverMoreInfo" data-title="Get More Info" data-container="body" data-html="true" href="#" id="login" class="btn btn-outline-light d-none d-md-inline-block ml-3">Get More Info</a>
            <!-- Get More Info Popover -->
            <div id="popover-content" class="d-none more-info">
                <form>
                    <div class="form-group mb-2 has-float-label">
                        <input class="form-control" id="your-name" type="text" placeholder="Your name"
                               aria-label="Your name" aria-describedby="your-name"/>
                        <label for="your-name">Your name</label>
                    </div>

                    <div class="form-group mb-2 has-float-label">
                        <input class="form-control" id="your-email" type="email" placeholder="Your email"
                               aria-label="Your email" aria-describedby="your-email"/>
                        <label for="your-email">Your email</label>
                    </div>

                    <div class="form-group mb-2 has-float-label">
                        <input class="form-control" id="your-phone" type="tel" placeholder="Your phone"
                               aria-label="Your phone" aria-describedby="your-phone"/>
                        <label for="your-phone">Your phone</label>
                    </div>

                    <button type="submit" class="btn btn-primary w-100">Request More Info</button>
                </form>
            </div>

        </div>
    </div>
</template>

<script>
    import TypeLabel from './TypeLabel'

    let parser = document.createElement('a')

    export default 
        name: 'school',
        props: ['item'],
        components: TypeLabel,
        methods: 
            domainOf: url => ((parser.href = url), parser.hostname.replace(/^www\./, ''))
        
    
</script>

【问题讨论】:

【参考方案1】:

要访问每所学校的名称,您应该像这样访问它:

const hit = this.schools[0].hit;

然后你迭代属性命中

hit.forEach(function(el) 
  console.log(el.title);
);

为此,您可能应该将计算属性中的属性学校展平,以便以后更容易访问。

要声明扁平化变量,可以在计算属性中声明它:

computed: 
 // other properties ...
 flattenedSchools: function () 
      const schools = [];
      if (this.schools && this.schools.length) 
          // up to you to check if hit exist and has values
          this.schools[0].hit.forEach(function(el) 
            schools.push((el.title);
          );
      
      return schools;
   ,
,

要访问 flattenedSchools,只需使用 this.flattenedSchools 并对其进行迭代。

【讨论】:

感谢您的帮助。我在哪里定义常量?抱歉,我是 Vue.js 的新手。

以上是关于使用 Vue 访问嵌套的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

axios在vue中嵌套json

Rails 使用 JSON 将深度嵌套属性到 Vue 实例

Vue 循环嵌套 JSON 的麻烦

Vue - 使用 ref 访问嵌套的孩子

使用 python 访问嵌套的 JSON

如何使用 Alamofire 和 SwiftyJSON 访问嵌套的 JSON 值?