skip to Main Content

I want to build project with Vue3 CDN (because project environment cannot run npm) so I try to create component with html+CDN.
But when I try to create recursive component, It just render top-level element.
Is there any solution to solve this problem?

<!DOCTYPE html>
<html>
<head>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <title>Form Example</title>
</head>
<body>
<div id="app">
    <ul>
        <menu-comp v-for="item in message" :key="item.id" :item="item"></menu-comp>
    </ul>
</div>

</body>

<script type="module">
    const {createApp, ref, } = Vue
    const MenuComp = {
        template: `
            <li>{{ item.menuName }}
                <ul v-if="item.subMenu.length>0">
                    <component is="menu-comp" v-for="subs in item.subMenu" :key="subs.id" :item="subs"></component>
                </ul>
            </li>
        `,
        props: ['item'],
    }
    const app = createApp({
        setup() {
            const message = ref([])
            return {
                message
            }
        },
        mounted() {
            this.getMenus();
        },
        components: {
            "menu-comp": MenuComp,
        },

        methods: {
            getMenus() {
                axios.get('/api/menu', {
                    contentType: "application/json; charset=UTF-8",
                }).then(r => {
                    const {data} = r;
                    this.message = data.results;
                    console.log(r);
                });
            }
        }
    }).mount('#app')

</script>

But When I render this page

<div id="app" data-v-app="">
<ul>
<li>test1 <ul>
<menu-comp item="[object Object]"></menu-comp>
</ul>
</li>
<li>test2
 <!--v-if-->
</li>
</ul>
</div>
``

2

Answers


  1. For the expected result, why not use slot inside your component, and inject the component itself afterwards?.

    For example :

    <div id="app">
          <ul>
            <menu-comp v-for="item in message" :key="item.id" :item="item">
              {{message.menuName}}
              <menu-comp
                v-for="subItem in item.subMenu"
                :key="subItem.id"
                :item="subItem"
                >{{subItem.menuName}}</menu-comp
              >
            </menu-comp>
          </ul>
        </div>
    
    
    const MenuComp = {
          template: `
                <li>{{ item.menuName }}
                    <ul v-if="item.subMenu?.length>0">
                        <slot/>
                    </ul>
                </li>
            `,
          props: ["item"],
        };
    
    Login or Signup to reply.
  2. Then for an infinit recursion like you want, another way is to use API composition for explicit recursion

    //...
    <!DOCTYPE html>
    <html>
      <head>
        <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
        <title>Form Example</title>
      </head>
      <body>
        <div id="app">
          <ul>
            <menu-comp
              v-for="item in message"
              :key="item.id"
              :item="item"
            ></menu-comp>
          </ul>
        </div>
    
        <script type="module">
          const { createApp, defineComponent, ref, h } = Vue;
    
          const MenuComp = defineComponent({
            name: "MenuComp",
            props: ["item"],
            setup(props) {
              return () =>
                h("li", [
                  props.item.menuName,
                  props.item.subMenu && props.item.subMenu.length
                    ? h(
                        "ul",
                        props.item.subMenu.map((sub) =>
                          h(MenuComp, { item: sub, key: sub.id })
                        )
                      )
                    : null,
                ]);
            },
          });
    
          const app = createApp({
            setup() {
              const message = ref([
                {
                  menuName: "first",
                  id: 1,
                  subMenu: [
                    {
                      menuName: "sub first",
                      id: 11,
                      subMenu: [],
                    },
                    {
                      menuName: "sub second",
                      id: 12,
                      subMenu: [],
                    },
                  ],
                },
              ]);
              return {
                message,
              };
            },
            components: {
              "menu-comp": MenuComp,
            },
          }).mount("#app");
        </script>
      </body>
    </html>
    
    //...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search