WP API V2 的 Nuxt / Vue 导航菜单问题

Nuxt / Vue navigation menu issue with WP API V2

我正在使用 Nuxt 和 headless wordpress 构建一个网站。所有数据均来自 wordpress api (wp-json).

导航菜单有问题,有 parent/child 个菜单项。

单击父元素时,会立即触发所有具有子元素的菜单项。 我需要它只触发我点击的那个。

Here's what happens @click right now

这是我目前的情况:

HTML:

<nav>
    <div class="">
      <!-- Triggers burger menu -->
      <ul :class="isOpen ? 'block' : 'hidden'" class="sm:flex">
        <!-- Loop through the parent navigation -->
        <!-- Add click event to trigger dropdown menu -->
        <li class="sm:mx-8 text-white cursor-pointer py-4 sm:py-0" 
            v-for="item in linksArray" 
            :key="item.ID"
            @click="isOpen = !isOpen"
        >
          <!-- Insert the data from wp-json -->
          <div class="">
            <!-- Parent navigation elements -->
            <div class="flex items-center">
              <div class=""> {{item.title}} </div>
            </div>
            <!-- Child navigation here -->
            <div>
              <!-- Trigger show or hide child elements on click from above -->
              <ul 
              v-show="isOpen" 
              class="sm:absolute bg-gray-800 rounded mt-4"
              >
                <!-- Loop through the child elements -->
                <li class="text-white rounded hover:bg-gray-700 cursor-pointer py-2 px-2"
                    v-for="childItem in item.child_items" 
                    :key="childItem.ID"
                >
                  <!-- Insert the data for children from wp-json -->
                  <nuxt-link :to="childItem.url">
                    <div class="flex items-center">
                      <span class="title">
                        {{ childItem.title }}
                      </span>
                    </div>
                  </nuxt-link>

                </li>
              </ul>
            </div>
          </div>
        </li>
      </ul>
    </div>
  </nav>

脚本:

<script>
  export default {
    name: "Navbar",
    props: {
      linksArray: {
        type: Array
      },
    },
    data() {
      return {
        isOpen: false,
      };
    },
    watch: {
      // Use to close the menu on route change
      '$route'() {
        this.isOpen = false;
      },
    }
  };
</script>

wp-json 菜单响应

{
"term_id": 2,
"name": "Main",
"slug": "main",
"term_group": 0,
"term_taxonomy_id": 2,
"taxonomy": "nav_menu",
"description": "",
"parent": 0,
"count": 14,
"filter": "raw",
"items": [
{
"ID": 319,
"post_author": "1",
"post_date": "2020-01-11 21:42:33",
"post_date_gmt": "2020-01-11 21:42:33",
"post_content": "",
"post_title": "Games",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "games",
"to_ping": "",
"pinged": "",
"post_modified": "2020-01-15 21:10:20",
"post_modified_gmt": "2020-01-15 21:10:20",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://localhost/?p=319",
"menu_order": 1,
"post_type": "nav_menu_item",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw",
"db_id": 319,
"menu_item_parent": "0",
"object_id": "319",
"object": "custom",
"type": "custom",
"type_label": "Custom Link",
"title": "Games",
"url": "#",
"target": "",
"attr_title": "",
"description": "",
"classes": [],
"xfn": "",
"logo": {},
"child_items": [
{
"ID": 321,
"post_author": "1",
"post_date": "2020-01-11 21:42:33",
"post_date_gmt": "2020-01-11 21:42:33",
"post_content": "",
"post_title": "Dota 2",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "dota-2",
"to_ping": "",
"pinged": "",
"post_modified": "2020-01-15 21:10:20",
"post_modified_gmt": "2020-01-15 21:10:20",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://localhost/?p=321",
"menu_order": 2,
"post_type": "nav_menu_item",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw",
"db_id": 321,
"menu_item_parent": "319",
"object_id": "301",
"object": "games",
"type": "post_type",
"type_label": "Game",
"url": "http://localhost/games/dota-2/",
"title": "Dota 2",
"target": "",
"attr_title": "",
"description": "",
"classes": [
""
],
"xfn": "",
"logo": {},
"slug": "dota-2"
},
{
"ID": 322,
"post_author": "1",
"post_date": "2020-01-11 21:42:33",
"post_date_gmt": "2020-01-11 21:42:33",
"post_content": "",
"post_title": "Overwatch",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "overwatch",
"to_ping": "",
"pinged": "",
"post_modified": "2020-01-15 21:10:20",
"post_modified_gmt": "2020-01-15 21:10:20",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://localhost/?p=322",
"menu_order": 3,
"post_type": "nav_menu_item",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw",
"db_id": 322,
"menu_item_parent": "319",
"object_id": "264",
"object": "games",
"type": "post_type",
"type_label": "Game",
"url": "http://localhost/games/overwatch/",
"title": "Overwatch",
"target": "",
"attr_title": "",
"description": "",
"classes": [
""
],
"xfn": "",
"logo": {},
"slug": "overwatch"
},
{},
{},
{}
]
},
{
"ID": 320,
"post_author": "1",
"post_date": "2020-01-11 21:42:33",
"post_date_gmt": "2020-01-11 21:42:33",
"post_content": "",
"post_title": "Gambling",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "gambling",
"to_ping": "",
"pinged": "",
"post_modified": "2020-01-15 21:10:20",
"post_modified_gmt": "2020-01-15 21:10:20",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://localhost/?p=320",
"menu_order": 7,
"post_type": "nav_menu_item",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw",
"db_id": 320,
"menu_item_parent": "0",
"object_id": "320",
"object": "custom",
"type": "custom",
"type_label": "Custom Link",
"title": "Gambling",
"url": "#",
"target": "",
"attr_title": "",
"description": "",
"classes": [
""
],
"xfn": "",
"logo": {},
"child_items": [
{
"ID": 336,
"post_author": "1",
"post_date": "2020-01-12 00:46:53",
"post_date_gmt": "2020-01-12 00:46:53",
"post_content": "",
"post_title": "CSGO Gambling",
"post_excerpt": "",
"post_status": "publish",
"comment_status": "closed",
"ping_status": "closed",
"post_password": "",
"post_name": "csgo-gambling",
"to_ping": "",
"pinged": "",
"post_modified": "2020-01-15 21:10:20",
"post_modified_gmt": "2020-01-15 21:10:20",
"post_content_filtered": "",
"post_parent": 0,
"guid": "http://localhost/?p=336",
"menu_order": 8,
"post_type": "nav_menu_item",
"post_mime_type": "",
"comment_count": "0",
"filter": "raw",
"db_id": 336,
"menu_item_parent": "320",
"object_id": "336",
"object": "custom",
"type": "custom",
"type_label": "Custom Link",
"title": "CSGO Gambling",
"url": "/csgo/gambling",
"target": "",
"attr_title": "",
"description": "",
"classes": [
""
],
"xfn": "",
"logo": {}
}
]
},
{},
{},
{}
]
}

我是开发新手,已经坚持了一个多星期了。 不知道去哪里寻找答案。在此处或 google 上找不到任何内容。 能否请您指出我做错了什么或解决方案。

谢谢!

在您的代码中,所有 children 都使用相同的变量来表示是否应显示它们。因此,如果此变量为真,则将显示所有 children,如果为假,则将隐藏所有。

您需要跟踪要显示的菜单项。以下是如何实现此目的的示例:

new Vue({
  el: "#app",
  data: {
    menu: [{
        title: "Main one",
        children: ['child 1', 'child 2', 'child 3']
      },
      {
        title: "Main two",
        children: ['child 4', 'child 5', 'child 6']
      },
      {
        title: "Main three",
        children: ['child 7']
      },
      {
        title: "Main four",
        children: ['child 8', 'child 9']
      }
    ],
    openMenu: null
  },
  methods: {
    showChildren(i) {
      if (this.openMenu === i) this.openMenu = null
      else this.openMenu = i
    }
  }
})
li {
  margin: 8px;
  padding: 8px;
  background: pink;
  cursor: pointer;
}
<div id="app">
  <h2>menu:</h2>
  <ul>
    <li v-for="(nav, i) in menu" @click="showChildren(i)">
      {{nav.title}}
      <ul v-show="openMenu === i" v-for="child in nav.children">
        <li>{{ child }}</li>
      </ul>
    </li>
  </ul>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

基本上,如果 openMenu 与数组中的 parent 项索引相同,则仅显示 children。

当您单击 parent 时,它会将其索引发送到一个函数函数,该函数检查它是否已经打开(openMenu 等于 parents 索引),如果因此将 openMenu 更改为 null 以隐藏 children。否则它将 openMenu 设置为 parent 索引,使 v-show="openMenu === i" 对 parent 有效。