admin管理员组

文章数量:1221441

This is an example of routes I have in my application:

{
  path: "/something",
  name: "SomeRoute",
  component: SomeComponent,
  meta: {showExtra: true},
},
{
  path: "/somethingElse",
  name: "SomeOtherRoute",
  component: SomeOtherComponent,
},

Then I have the following component, which as you will notice has two script tags, one with composition API, one without:

<template>
  <div>
    This will always be visible. Also here's a number: {{ number }}
  </div>

  <div v-if="showExtra">
    This will be hidden in some routes.
  </div>
</template>

<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"

const number = 5
const showExtra = ref(true)

const onRouteChange = (to: RouteLocationNormalized) => {
  showExtra.value = !!to.meta?.showExtra
}
</script>

<script lang="ts">
import { defineComponent } from "vue"


export default defineComponent({
  watch: {
    $route: {
      handler: "onRouteChange",
      flush: "pre",
      immediate: true,
      deep: true,
    },
  },
})
</script>

This works correctly: when I enter a route with meta: {showExtra: false} it hides the extra div, otherwise it shows it.

What I want to do, however, is achieve the same by only using the composition API, in other words removing the second <script> tag entirely. I have tried this:

<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"
import { onBeforeRouteUpdate } from "vue-router"


// ...
// same as before
// ...

onBeforeRouteUpdate(onRouteChange)
</script>

But this won't take effect as expected when I switch route. I'm aware of the watch function I could import, but I'm unsure how to get the meta information about the route and how to appease the type checker.

This is an example of routes I have in my application:

{
  path: "/something",
  name: "SomeRoute",
  component: SomeComponent,
  meta: {showExtra: true},
},
{
  path: "/somethingElse",
  name: "SomeOtherRoute",
  component: SomeOtherComponent,
},

Then I have the following component, which as you will notice has two script tags, one with composition API, one without:

<template>
  <div>
    This will always be visible. Also here's a number: {{ number }}
  </div>

  <div v-if="showExtra">
    This will be hidden in some routes.
  </div>
</template>

<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"

const number = 5
const showExtra = ref(true)

const onRouteChange = (to: RouteLocationNormalized) => {
  showExtra.value = !!to.meta?.showExtra
}
</script>

<script lang="ts">
import { defineComponent } from "vue"


export default defineComponent({
  watch: {
    $route: {
      handler: "onRouteChange",
      flush: "pre",
      immediate: true,
      deep: true,
    },
  },
})
</script>

This works correctly: when I enter a route with meta: {showExtra: false} it hides the extra div, otherwise it shows it.

What I want to do, however, is achieve the same by only using the composition API, in other words removing the second <script> tag entirely. I have tried this:

<script setup lang="ts">
import type { RouteLocationNormalized } from "vue-router"
import { ref } from "vue"
import { onBeforeRouteUpdate } from "vue-router"


// ...
// same as before
// ...

onBeforeRouteUpdate(onRouteChange)
</script>

But this won't take effect as expected when I switch route. I'm aware of the watch function I could import, but I'm unsure how to get the meta information about the route and how to appease the type checker.

Share Improve this question asked Sep 5, 2021 at 15:57 theberzitheberzi 2,6455 gold badges29 silver badges42 bronze badges 1
  • this won't take effect as expected when I switch route - isn't this the case for onBeforeRouteLeave ? onBeforeRouteUpdate is for current route. – Estus Flask Commented Sep 5, 2021 at 16:22
Add a comment  | 

2 Answers 2

Reset to default 10

You can convert your watcher to composition api by importing watch method from vue

<script lang="ts">
import { defineComponent, vue, watch } from "vue"
import { useRoute } from "vue-router"

export default defineComponent({
  setup() {
    const route = useRoute()
    watch(route, (to) => {
      showExtra.value = !!to.meta?.showExtra
    }, {flush: 'pre', immediate: true, deep: true})
  },
})
</script>

I don't have enough rep to comment, but the above accepted answer does have a slight difference in operation.

Options API:

watch: {
  '$route': {
    handler(oldValue, newValue) => {}
  }
}

composition API:

setup() {
  const route = useRoute();
  watch(route, (newValue, oldValue) => {});
}

In the composition API, the oldValue will just be a clone of newValue (the same object), whereas in the options API, the oldValue will actually be the previous route (useful in many scenarios).

本文标签: