Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple templates declared in one .vue file

I have a component inside a .vue file that can benefit from reusing a chunk of code. I know I can move that code to a separate .vue file and import it as a new component. However, this component would not be used anywhere else and I'd like to avoid cluttering the directory. Is it possible to declare this component's template inside the parent without using the in-code template:"<div>.....</div>" stuff?

This is the idea:

<template>
  <div>
    ...some html here...
    <div v-for="item in items">
      {{item.name}}: 
      <div v-if="item.available">YES!</div>
      <div v-else>NO :(</div>     
    </div>    

    ...some other components and data here...

    <div v-for="item in items">
      {{item.name}}: 
      <div v-if="item.available">YES!</div>
      <div v-else>NO :(</div>
    </div>    
  </div>
</template>

I would like to be able to do something like this:

<template>
  <div>
    ...some html here...
    <div v-for="item in items">
      <itemizer inline-template v-model="item">
        {{value.name}}: 
        <div v-if="value.available">YES!</div>
        <div v-else>NO :(</div>
      </itemizer>
    </div>    

    ...some other components and data here...

    <div v-for="item in items">
      <itemizer v-model="item"/>
    </div>    
  </div>
</template>

However, from what I understand this is not possible.

like image 826
ierdna Avatar asked Oct 13 '17 20:10

ierdna


People also ask

Can you have multiple templates in Vue?

Vue allows only a single element as a template root. If multiple root elements are specified, unintended behaviors occur as follows: For single-file component with a . vue extension, Vue throws a compile error.

What is a .Vue file?

Vue Single-File Components (a.k.a. *.vue files, abbreviated as SFC) is a special file format that allows us to encapsulate the template, logic, and styling of a Vue component in a single file. Here's an example SFC: vue <script> export default { data() { return { greeting: 'Hello World!'

How do I transfer data from one component to another in Vue 3?

Using Props To Share Data From Parent To Child # VueJS props are the simplest way to share data between components. Props are custom attributes that we can give to a component. Then, in our template, we can give those attributes values and — BAM — we're passing data from a parent to a child component!

What is a single file component?

Single File Components(SFCs) are a style of application organization used by JavaScript UI libraries where each file represents a single component in all aspects. Typically they resemble an HTML document where you have HTML tags, Style Tag, and Script Tag all in a file.


3 Answers

Unfortunately this pattern does not appear to be supported by the creator of Vue:

I personally feel the syntax is less maintainable than [Single File Components]

Note that we want to keep the SFC syntax as consistent possible, because it involves a big ecosystem of tools that need to support any new features added (e.g. Vetur would need to do something very different for handling SFCs with multiple scripts/templates). The proposed syntax, IMO, does not justify adding the new syntax.

https://github.com/vuejs/vue/pull/7264#issuecomment-352452213

That's too bad, as even beyond flexibility and developer choice, there is a good argument for inlining small functions that are not used by other components in order to reduce complexity. It's a common pattern in React and does not inhibit Single File Components when they're needed. In fact it allows gradual migration as inline components grow.


Here's one of the only resources currently that offers some potential workarounds: https://codewithhugo.com/writing-multiple-vue-components-in-a-single-file/

I've tried them all and am not satisfied with any of them at this time. At best you can set runtimerCompiler: true and use template strings, but it'll add 10KB to your bundle and you'll likely miss out on full syntax highlighting available in the <template> element. Maybe you can hack Teleport, but I have not made a dedicated attempt.

like image 166
Raine Revere Avatar answered Nov 15 '22 04:11

Raine Revere


Actually, this should work. Just register your Vue inline-template like this in the section of your parent .vue file:

<template>

    <div v-for="item in items">
        <test-template :item="item">
            <h1>{{item.text}}</h1>
        </test-template>
    </div>

</template>


<script>
    Vue.component('test-template', {
        template:'#hello-world-template',
        props: {
            item: Object
        }
    });

    export default {...}
</script>

In your parent HTML file, put this:

<script type="text/x-template" id="hello-world-template">
    <p>Hello hello hello</p>
</script>
like image 31
Bryan Miller Avatar answered Nov 15 '22 04:11

Bryan Miller


With vue3 there are multiple options:

  1. with vue-jsx you can just declare a component in your script setup section and use that
const Named = defineComponent(() => {
  const count = ref(0)
  const inc = () => count.value++

  return () => (
    <button class="named" onClick={inc}>
      named {count.value}
    </button>
  )
})

  1. There is another option described by Michael Thiessen here

  2. Also you can have multiple render function components in one file: https://staging.vuejs.org/guide/extras/render-function.html

like image 31
husayt Avatar answered Nov 15 '22 03:11

husayt