skip to Main Content

I would like to export a function from a component from within the "" section and use it in another component.

I tried it like this:

<!-- TestHeading.vue -->
<template>
  <h1>{{ title }}</h1>
</template>

<script setup>
import { ref } from 'vue';
const title = ref('title');

export function set_title(new_title) {
  title.value = new_title;
}
</script>

<!-- TestDocument.vue -->
<template>
  <TestHeading />
  <p>Main text</p>
</template>

<script setup>
import { TestHeading, set_title } from '../components/TestHeading.vue';
set_title('new title');
</script>

This just gives me the error: <script setup> cannot contain ES module exports. If you are using a previous version of <script setup>, please consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.

Omitting the "export" I just get:
Uncaught SyntaxError: import not found: set_title in TestDocument.vue.

Is there a way to do it?
The component (TestHeading) will only appear once in the whole document, so I should be able to set the title using a global function like this.

Update: Found my workaround, instead of exporting the function, I just set window.set_title = (new_title) => { ... }. Does not seem so clean, but I am probably going to use this unless I find a better way.

2

Answers


  1. You could expose the function using defineExpose macro, then use a template ref on the child component :

    <!-- TestHeading.vue -->
    <template>
      <h1>{{ title }}</h1>
    </template>
    
    <script setup>
    import { ref } from 'vue';
    const title = ref('title');
    
     function set_title(new_title) {
      title.value = new_title;
    }
    
    defineExpose({
      set_title
    })
    </script>
    
    <!-- TestDocument.vue -->
    <template>
      <TestHeading ref="heading" />
      <p>Main text</p>
    </template>
    
    <script setup>
    import { TestHeading } from '../components/TestHeading.vue';
    
    const heading = ref()
    
    heading.value.set_title('new title');
    </script>
    
    
    

    But it’s recommended to use a prop or slot :

    <!-- TestHeading.vue -->
    <template>
      <h1>
        <slot/>
      </h1>
    </template>
    
    <script setup>
    
    </script>
    
    <!-- TestDocument.vue -->
    <template>
      <TestHeading >
         {{title}}
      </TestHeading> 
     <p>Main text</p>
    </template>
    
    <script setup>
    import { ref } from 'vue';
    import { TestHeading} from '../components/TestHeading.vue';
    
    const title = ref('title');
    
    </script>
    
    
    
    Login or Signup to reply.
  2. Vue SFC Playground

    What you’re trying is an anti-pattern, you should avoid mutations in components as much as possible. It’s also not reactive. Use props instead.
    If your title contains a markup you could use slots instead.

    Also note that the latest convention is to put <script setup> at the top of an SFC since <template> doesn’t make much sense without knowning what the injected variables mean.

    TestHeading.vue

    <script setup>
    defineProps({title: {
        type: String, default: 'title'
      }
    });
    </script>
    
    <template>
      <h1>{{ title }}</h1>
    </template>
    

    TestDocument.vue

    <script setup>
    import { TestHeading } from './TestHeading.vue';
    
    </script>
    
    <template>
      <TestHeading title="new title"/>
      <p>Main text</p>
    </template>
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search