likes
comments
collection
share

跟着AI助理学习Vue3,这一篇文章足够了

作者站长头像
站长
· 阅读数 18

在讲述我的学习历程之前,我必须先声明:文档和我,视频和我,都不是好朋友。一提到他们,我就困得像只懒猫,学习效率和记忆能力一落千丈。然而,自从我遇见了GPT4,一切都变得如此不同。

GPT4就像那个学校里的调皮生,给我的学习带来了不少趣味。我和它的交流仿佛是一场精彩绝伦的话剧,我可以让它扮演各种角色,玩转各种场景。这一次,我决定学习Vue3,但我不再需要去硬啃那些令我头疼的API文档。我选择与GPT4并肩作战,一起在知识的矿洞中挖掘珍宝。

过程中,我遇到了一些困难,有些知识点像是一团乱麻。但我有GPT4,它就像一把魔法钥匙,为我打开了那些难题的大门,让我轻松理解。我觉得,这样的学习效率,真的是我从未有过的新体验。

现在,我想分享的这篇文章,就是GPT4和我一起完善的Vue3知识点总结。我必须说,GPT4就像那个学校里的优等生,无论是哪个知识点,它都可以轻松搞定。

接下来,通过这一篇文章,超级详细的带你学习一遍Vue3的知识点。

跟着AI助理学习Vue3,这一篇文章足够了

Vue3基础

如何创建Vue实例

在 Vue3 中,我们不再使用 new Vue() 来创建一个 Vue 实例。取而代之的是一个名为 createApp() 的函数。createApp() 是 Vue3 的新函数,它用于创建并挂载 Vue 应用。

以下是一个简单的 Vue3 应用的创建方式:

// 1. 导入Vue和你的应用组件
import { createApp } from 'vue'
import App from './App.vue'

// 2. 创建Vue应用实例
const app = createApp(App)

// 3. 挂载Vue应用实例到你的HTML元素上
app.mount('#app')

在上述代码中:

  1. 我们从 'vue' 导入 createApp 函数和你的应用组件 App.vue。
  2. 使用 createApp 函数和你的根组件创建 Vue 应用实例。这个根组件通常是你的应用的主组件,并且其他所有组件都会作为其子组件。
  3. 你需要指定一个 HTML 元素(在这里是 id 为 'app' 的元素),将 Vue 应用实例挂载到这个元素上。

在实际开发中,你可能还需要安装和配置各种插件(如 vue-router 或 vuex),然后在创建应用实例之前使用它们。在这种情况下,你可以使用 app.use(plugin)。例如,如果你要使用 Vue Router,代码可能会看起来像这样:

import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import routes from './routes' 

const router = createRouter({
  history: createWebHistory(),
  routes, // short for `routes: routes`
})

const app = createApp(App)
app.use(router)
app.mount('#app')

总的来说,createApp() 方法为我们提供了一个更清晰和更灵活的方式来创建和配置我们的 Vue 应用。

Vue生命周期钩子函数

Vue 3 的生命周期钩子函数与 Vue 2.x 的生命周期钩子函数在名称和功能上有一些差异。以下是 Vue 3 中可用的主要生命周期钩子:

  1. beforeCreate 和 created:在 Vue 3 中,这两个生命周期钩子已被移除。Vue 3 使用 setup 函数替代了这两个钩子,setup 函数在组件初始化之后,属性和反应性系统设置之前调用。
  2. beforeMount:在挂载开始之前被调用,此时模板或渲染函数尚未编译,而 DOM 还未生成。在服务器端渲染期间,此钩子不被调用。
  3. mounted:在挂载(即,组件被插入其挂载点)结束之后被调用。此时,你可以通过 this 访问到新创建的 vm 实例。注意 mounted 不会保证所有的子组件也都一起被挂载。如果你想等到整个视图都渲染完毕,可以使用 vm.$nextTick。
  4. beforeUpdate:在数据更改之后,虚拟 DOM 重新渲染和打补丁之前调用。你可以在这个钩子中进一步地更改状态,这不会触发额外的重渲染过程。
  5. updated:在包含异步组件的组件的数据更改之后,当组件和子组件的虚拟 DOM 重新渲染和打补丁之后立即调用。
  6. beforeUnmount:在卸载组件之前被调用。在这一阶段,实例仍然完全可用。这是 Vue 2.x 中的 beforeDestroy 钩子。
  7. unmounted:在卸载(即,组件被销毁)组件之后被调用。这是 Vue 2.x 中的 destroyed 钩子。

注意:在 Vue 3 中,生命周期方法的命名已经改变,以更好地反映它们何时被调用。比如,beforeDestroy 改名为 beforeUnmount,destroyed 改名为 unmounted。如果你正在从 Vue 2.x 迁移到 Vue 3,需要留意这些更改。

以下是一段使用了生命周期钩子函数的 Vue 3 代码示例:

import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      console.log('onBeforeMount')
    })

    onMounted(() => {
      console.log('onMounted')
    })

    onBeforeUpdate(() => {
      console.log('onBeforeUpdate')
    })

    onUpdated(() => {
      console.log('onUpdated')
    })

    onBeforeUnmount(() => {
      console.log('onBeforeUnmount')
    })

    onUnmounted(() => {
      console.log('onUnmounted')
    })

    // ...
  }
}

模板语法和指令

在 Vue 3 中,模板语法仍然是非常关键的概念,以下是一些核心的模板语法特性:

1. 插值

在双大括号 {{ }} 中,可以插入 JavaScript 表达式,例如 {{ message }}。

<template>
  <div>{{ message }}</div>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const message = ref('Hello Vue 3!')
    return {
      message
    }
  }
}
</script>

2. 指令:

Vue 提供了一些特殊属性,称为指令,例如 v-if, v-for, v-bind, v-on, v-model。

  • v-if:根据表达式的真假决定是否渲染元素。
<template>
  <div v-if="showMessage">{{ message }}</div>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const showMessage = ref(true)
    const message = ref('Hello Vue 3!')
    return {
      showMessage,
      message
    }
  }
}
</script>
  • v-for:基于源数据多次渲染元素或模板块。
<template>
  <div v-for="(item, index) in items" :key="index">{{ item.text }}</div>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const items = ref([
      { text: 'Item 1' },
      { text: 'Item 2' },
      { text: 'Item 3' },
    ])
    return {
      items
    }
  }
}
</script>
  • v-bind:动态绑定一个或多个特性,或一个组件 prop 到表达式
<template>
  <div v-bind:id="dynamicId"></div>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const dynamicId = ref('myId')
    return {
      dynamicId
    }
  }
}
</script>
  • v-on:添加事件监听器
<template>
  <button v-on:click="incrementCounter">Click me</button>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const counter = ref(0)
    const incrementCounter = () => {
      counter.value++
    }
    return {
      incrementCounter
    }
  }
}
</script>
  • v-model:创建双向数据绑定。

在 Vue 中,v-model 指令用于在输入元素和 Vue 实例的数据之间建立双向数据绑定。这意味着当输入元素的值改变时,数据会自动更新,反之亦然。

在内部,v-model 实际上是一个语法糖,它结合了 v-bind 和 v-on。以下是 v-model 的基本使用方法:

<template>
  <input v-model="message" placeholder="edit me">
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const message = ref('Hello Vue 3!')
    return {
      message
    }
  }
}
</script>

在这个例子中,v-model 指令与 Vue 实例中的 message 数据属性绑定。当用户在输入框中键入内容时,message 的值将随之改变。

对于一些特殊的表单控件,如复选框和单选按钮,v-model 的工作方式会有所不同:

<template>
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">{{ checked }}</label>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const checked = ref(false)
    return {
      checked
    }
  }
}
</script>

在这个例子中,v-model 指令与 Vue 实例中的 checked 数据属性绑定。当用户点击复选框时,checked 的值将切换为 true 或 false。

请注意,v-model 不仅仅适用于 元素。它可以用于任何表单控件,包括 和 ,也可以在自定义组件上使用。

另外,在 Vue 3 中,v-model 更具灵活性。在 Vue 2 中,如果你想在一个组件上使用多个 v-model,你必须为它们指定不同的名字(比如:v-model:value, v-model:input)。但在 Vue 3 中,你可以直接使用 v-model,例如:v-model:title, v-model:content,这使得在自定义组件上使用 v-model 变得更加简洁和灵活。

  • 计算属性

在 Vue 中,计算属性 (computed properties) 是一种特殊的响应式属性,它的值由一个函数计算得出,并且 Vue 会自动跟踪其依赖项的变化,当依赖项变化时重新计算它的值。

下面是一个基本的计算属性示例:

<template>
  <div>
    <p>Original message: "{{ message }}"</p>
    <p>Computed reversed message: "{{ reversedMessage }}"</p>
  </div>
</template>

<script>
import { ref, computed } from 'vue';

export default {
  setup() {
    const message = ref('Hello Vue!');
    const reversedMessage = computed(() => message.value.split('').reverse().join(''));

    return {
      message,
      reversedMessage
    };
  }
}
</script>

在这个例子中,reversedMessage 是一个计算属性,它的值是 message 值的反转。当 message 的值改变时,reversedMessage 的值也会自动更新。

需要注意的是,计算属性默认是懒加载的,也就是说只有在它们的值被实际需要时才会被计算。一旦计算过一次,它们的值就会被缓存起来,只有当它们的依赖项改变时才会重新计算。这使得计算属性在处理大量数据或者复杂计算时非常高效。

在 Vue 3 中,你还可以定义一个 setter 函数来实现可写的计算属性。例如:

<template>
  <input v-model="fullname">
</template>

<script>
import { ref, computed } from 'vue';

export default {
  setup() {
    const firstname = ref('John');
    const lastname = ref('Doe');

    const fullname = computed({
      get: () => `${firstname.value} ${lastname.value}`,
      set: (newValue) => {
        const [newFirstname, newLastname] = newValue.split(' ');
        firstname.value = newFirstname;
        lastname.value = newLastname;
      }
    });

    return {
      fullname
    };
  }
}
</script>

在这个例子中,当用户修改 fullname 输入框的值时,setter 函数会被调用,将新的 firstname 和 lastname 值设置到 Vue 实例中。

  • 侦听器

侦听器 (Watchers) 是 Vue.js 提供的一种用来响应式地追踪数据变化并执行相应操作的功能。侦听器可以观察和响应 Vue 实例上的数据变化。

以下是一个简单的使用 watch 的示例:

<template>
  <div>
    <input v-model="question" placeholder="Ask something...">
    <p>{{ answer }}</p>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const question = ref('');
    const answer = ref('I cannot give you an answer until you ask a question.');

    watch(question, (newQuestion, oldQuestion) => {
      if (newQuestion.indexOf('?') > -1) {
        answer.value = 'That sounds like a question.';
      }
    });

    return {
      question,
      answer
    };
  }
}
</script>

在这个例子中,我们使用 watch 创建了一个侦听器,该侦听器监视 question 的值。当 question 的值发生变化时,侦听器的回调函数会被调用。新的值和旧的值会被作为参数传给回调函数。

在 Vue 3 中,侦听器可以在 setup 函数中使用 watch 或者 watchEffect 创建。

  • watch 需要一个被观察的源和一个执行当源改变时的回调函数。源可以是响应式引用 (例如 ref 或 reactive 创建的对象),也可以是返回期望响应的数据的函数。
  • watchEffect 自动跟踪其内部使用的响应式状态,并在状态改变时重新运行。它比 watch 更为“自动化”,因为你不需要指定观察哪些特定的状态。

在某些情况下,你可能需要手动停止侦听。例如,当你在一个组件中使用 watch 或 watchEffect 创建侦听器,并在组件卸载时停止侦听。在这种情况下,watch 和 watchEffect 函数都会返回一个停止函数,你可以在需要时调用这个函数来停止侦听。

响应式数据

在 Vue 3 中,提供了 ref 和 reactive 两种创建响应式数据的方式。这两种方式各有优势,它们可以适用于不同的场景。

  1. ref

ref 函数用于创建一个响应式的数据对象。ref 返回的对象拥有一个 .value 属性,通过这个属性可以获取或者修改其值。

import { ref } from 'vue';

const count = ref(0);
console.log(count.value); // 0
count.value++; 
console.log(count.value); // 1
  1. reactive

reactive 用于创建一个响应式的对象。与 ref 不同,reactive 不需要 .value 属性,可以直接访问或修改对象的属性。

import { reactive } from 'vue';

const state = reactive({ count: 0 });
console.log(state.count); // 0
state.count++; 
console.log(state.count); // 1
  1. toRefs

当使用 reactive 创建响应式对象后,我们可能会想将其解构,然而直接解构会导致失去响应性。这时,我们可以使用 toRefs 函数将响应式对象转换为普通对象,该对象的每个属性都是一个 ref,这样就能保持响应性。

import { reactive, toRefs } from 'vue';

const state = reactive({ count: 0 });
const { count } = toRefs(state);

console.log(count.value); // 0
count.value++; 
console.log(count.value); // 1

请注意,toRefs 并不会创建新的响应式对象,而是创建了新的 ref 对象,这些 ref 对象引用的还是原来的值。这意味着修改通过 toRefs 解构出来的 ref,原 reactive 对象也会同时改变。

以上就是 ref、reactive 和 toRefs 的基本使用,它们都是 Vue 3 响应性系统的核心部分。

Vue3组件

如何创建和使用Vue3组件

在Vue 3中,组件的创建和使用过程进行了一些改变,尤其是引入了新的setup函数和Composition API,它们提供了一种更直观和灵活的方式来组织和复用代码。

首先,我们来看一个简单的Vue 3组件的创建和使用过程:

<template>
  <button @click="increment">
    Count is: {{ count }}, double is: {{ double }}
  </button>
</template>

<script>
import { ref, computed } from 'vue';

export default {
  name: 'Counter',
  setup() {
    const count = ref(0);
    const double = computed(() => count.value * 2);

    function increment() {
      count.value++;
    }

    return {
      count,
      double,
      increment
    };
  }
}
</script>

在上述代码中:

  • template 部分定义了组件的HTML结构。我们使用v-on:click或简写形式@click监听按钮的点击事件。
  • script 部分使用Vue 3的setup函数和Composition API定义了组件的行为。
  • setup函数是Vue 3组件的新入口。在这个函数中,我们可以定义和返回我们的响应式数据和方法。这个函数在创建组件实例,但是在初始化任何声明式逻辑之前被调用。提供的第一个参数是props,第二个参数是context对象,包含了组件的上下文。
  • 我们使用ref函数创建了一个响应式的数据count,并使用computed函数创建了一个基于count的计算属性double。
  • 我们定义了一个方法increment来增加count的值。
  • 最后,我们返回了我们希望在模板中使用的所有响应式数据和方法。

然后,你可以在父组件中引用并使用这个组件,就像这样:

<template>
  <Counter />
</template>

<script>
import Counter from './Counter.vue';

export default {
  components: {
    Counter
  }
}
</script>

在这里,我们首先导入了我们刚才创建的Counter组件。然后,我们在components选项中注册了这个组件,这样我们就可以在父组件的模板中使用它了。

Vue3的父组件引用子组件

在 Vue 3 中,父组件可以通过几种方式引用子组件。

  1. 使用 ref

在你的 HTML 中,你可以在任何元素或者组件上添加 ref 属性。然后,在你的 setup 函数中,你可以通过 ref 方法获取这个元素或组件的引用。这种方式通常用于获取 DOM 元素或者组件实例的引用。

例如:

<template>
  <ChildComponent ref="childRef" />
</template>

<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  setup() {
    const childRef = ref(null);

    // 在 onMounted 钩子中可以访问子组件实例
    onMounted(() => {
      console.log(childRef.value);
    });

    return {
      childRef
    };
  }
}
</script>
  1. 使用 provide 和 inject

Vue 提供了 provide 和 inject 方法,允许你在父组件中定义一些值,然后在任何子孙组件中使用这些值,而不需要通过 props 一层层传递。这在开发高阶组件或者插件时特别有用。

例如:

// 父组件
<template>
  <ChildComponent />
</template>

<script>
import { provide } from 'vue';
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  setup() {
    const value = ref('Hello from parent');
    provide('myValue', value);
  }
}
</script>
// 子组件
<template>
  <div>{{ myValue }}</div>
</template>

<script>
import { inject } from 'vue';

export default {
  setup() {
    const myValue = inject('myValue');
    return {
      myValue
    };
  }
}
</script>

这两种方式都可以实现父子组件的通信,但是它们各有适用的场景。ref 方式适用于需要直接操作子组件或者元素的场景,而 provide 和 inject 方式则适用于跨越多层组件的通信场景。

Vue3组件使用Props

在Vue 3中,props 是组件用来接收从父组件传递过来的数据的。这是一种单向下行绑定:父组件的数据更新会流向子组件,但如果子组件修改了 prop,反过来不会影响父组件。

这是使用props的基本例子:

<!-- 子组件 -->
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  props: ['message']
}
</script>
<!-- 父组件 -->
<template>
  <child-component message="Hello from parent!"></child-component>
</template>
  1. 指定 Prop 类型:

为了使代码更健壮,建议总是为每个 prop 指定一个类型:

<script>
export default {
  props: {
    message: String,
    age: Number
  }
}
</script>
  1. 默认值:

你可以为 prop 设置一个默认值。对于对象或数组,默认值必须是一个函数:

<script>
export default {
  props: {
    message: {
      type: String,
      default: "Hello World"
    },
    list: {
      type: Array,
      default: () => []
    }
  }
}
</script>
  1. Prop 验证:

可以提供一个包含验证要求的对象来对 props 进行更复杂的验证:

<script>
export default {
  props: {
    age: {
      type: Number,
      required: true,
      validator: value => value >= 18
    }
  }
}
</script>

这里我们要求 age 必须是一个数字,并且大于或等于 18。validator 是一个自定义的验证函数。

  1. Prop的不可变性:

请注意,子组件不应更改从父组件接收的 prop。如果需要基于 prop 的值来定义一个可以修改的数据属性,可以在组件内部定义一个 data 属性或计算属性。

通过使用props,Vue.js 允许你创建可重用且可配置的组件,这是构建大型应用程序的基础。

Vue3的slots

在 Vue 3 中,插槽(slots)是一种强大的工具,它可以用来定义组件模板中的一部分,并允许父组件决定如何填充这些部分。

  1. 默认插槽:

最简单的插槽类型是默认插槽。如果你在组件模板中定义一个 元素,父组件可以在使用组件的地方插入一些内容,这些内容将替代 元素。

例如,以下是一个简单的 Card 组件:

<!-- Card.vue -->
<template>
  <div class="card">
    <div class="card-body">
      <slot></slot>
    </div>
  </div>
</template>

使用 Card 组件并传递内容到插槽:

<template>
  <Card>
    <h1>Hello World!</h1>
    <p>This is some text inside of a card body.</p>
  </Card>
</template>

在这个例子中,我们在 组件中插入了一些内容。这些内容将替代 Card 组件模板中的 。

  1. 具名插槽:

除了默认插槽,Vue 还支持具名插槽。这允许你定义多个插槽,并在使用组件时指定哪个插槽应接收哪个内容。

例如,以下是一个具有标题插槽和内容插槽的 Card 组件:

<!-- Card.vue -->
<template>
  <div class="card">
    <div class="card-header">
      <slot name="header"></slot>
    </div>
    <div class="card-body">
      <slot name="body"></slot>
    </div>
  </div>
</template>

使用 Card 组件并传递内容到具名插槽:

<template>
  <Card>
    <template v-slot:header>
      <h1>Hello World!</h1>
    </template>
    <template v-slot:body>
      <p>This is some text inside of a card body.</p>
    </template>
  </Card>
</template>

在这个例子中,我们为每个插槽提供了一个<template> 元素,并使用 v-slot 指令来指定应该将内容插入到哪个插槽。

  1. 作用域插槽:

有时,你可能希望子组件向父组件传递数据。在这种情况下,你可以使用作用域插槽。

作用域插槽是一种特殊的插槽,允许子组件将数据传递给插槽。在父组件中,你可以接收这些数据,并在插槽内容中使用它们。

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :item="item"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      item: { id: 1, name: 'Vue.js' }
    }
  }
}
</script>

在父组件中,你可以使用 v-slot 指令和一个值(在本例中为 data)来接收传递的数据

<template>
  <ChildComponent>
    <template v-slot:default="data">
      <p>ID: {{ data.item.id }}</p>
      <p>Name: {{ data.item.name }}</p>
    </template>
  </ChildComponent>
</template>

Vue3的新特性

1. Composition API:

Composition API 是 Vue 3 的核心特性,是为了解决更大,更复杂应用的问题而设计的。它提供了一种新的、更加灵活的方式来组织和复用组件逻辑。此 API 主要包括以下几个函数:

  • reactive(): 接收一个普通对象并返回其响应式副本。
  • ref(): 创建一个响应式的引用。
  • computed(): 创建一个响应式的计算属性。
  • watch()和watchEffect(): 允许我们对响应式数据进行“观察”并在其改变时运行一些代码。

2. 多个根节点:

Vue 3 允许在单个文件组件(SFC)的模板中包含多个根元素。在 Vue 2 中,如果你试图这样做,会导致编译错误。这意味着我们不再需要添加额外的无意义的元素来包装模板。

// 例如,以下这段代码在 Vue 2 中是无效的,因为它有两个根节点:
<template>
  <div>Root Node 1</div>
  <div>Root Node 2</div>
</template>

// 在这种情况下,你通常需要添加一个包裹元素,以创建一个有效的模板,如下所示:
<template>
  <div>
    <div>Root Node 1</div>
    <div>Root Node 2</div>
  </div>
</template>

// 然而,在 Vue 3 中,你可以在模板中有多个根节点,如下所示:
<template>
  <div>Root Node 1</div>
  <div>Root Node 2</div>
</template>

3.Teleport

Teleport 是 Vue 3 的一个新特性,它允许你将组件的子元素在 DOM 中的位置“传送”到 DOM 的其他部分。

这个特性对于一些特定的 UI 情况非常有用,例如,当你需要创建一个模态对话框、通知、或者弹出式菜单时,你通常希望这些元素能够跳出其父组件的边界并出现在 DOM 的顶层。

让我们看一个例子:

<div id="app">
  <div>Other content...</div>
  <teleport to="#end-of-body">
    <div>Teleported content...</div>
  </teleport>
</div>

<div id="end-of-body"></div>

在这个例子中,我们使用 组件将 "Teleported content..." 从它的父元素中“传送”到 #end-of-body 元素中。即使这个 div 在 DOM 树中的位置和 是相隔很远的,我们也能够以这种方式移动内容。

当你查看生成的 HTML 时,你会发现 "Teleported content..." 确实出现在 #end-of-body 元素中,而不是它在 Vue 模板中的位置。

<div id="app">
  <div>Other content...</div>
</div>

<div id="end-of-body">
  <div>Teleported content...</div>
</div>

这就是 Vue 3 的 Teleport 特性,它为处理某些 UI 问题提供了更加灵活的解决方案。

4.Suspense

Suspense 是 Vue 3 中的一个新组件,用于处理组件的异步依赖关系。当你的组件依赖于异步操作(例如数据获取)时,Suspense 可以提供一种干净、简洁的方式来处理加载状态和错误状态。

在异步组件中使用 Suspense 非常直接,你可以在你的组件中返回一个 Promise,然后用 Suspense 包裹这个组件。在 Promise 解析之前,Suspense 会渲染它的 fallback 插槽;一旦 Promise 解析,它就会渲染默认的插槽。以下是一个基本的示例:

import { ref } from 'vue';

export default {
  async setup() {
    const posts = ref(null);

    // 这将是一个异步操作,例如 API 调用
    const fetchPosts = new Promise((resolve) => {
      setTimeout(() => {
        resolve([
          { id: 1, title: 'Post 1' },
          { id: 2, title: 'Post 2' },
        ]);
      }, 2000);
    });

    posts.value = await fetchPosts;

    return {
      posts,
    };
  },
};

接下来,我们在父组件中使用 Suspense 来包裹这个组件:

<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>

<script>
import AsyncComponent from './AsyncComponent.vue';

export default {
  components: {
    AsyncComponent,
  },
};
</script>

在这个例子中,当我们等待异步组件的数据时,将会显示 "Loading..."。一旦数据可用,AsyncComponent 将会渲染并显示我们的帖子。

这就是 Suspense 如何在 Vue 3 中工作的基本示例。请注意,这是一个实验性的特性,其 API 在未来可能会有所改变。

Vue3的Router路由管理

在 Vue.js 中,路由是用来管理应用中的各种页面和它们之间跳转的方式。Vue Router 是 Vue.js 官方的路由管理器,它可以让我们更方便地创建单页应用。

首先,你需要通过 npm 安装 Vue Router:

npm install vue-router@next

然后,在你的应用中引入和使用 Vue Router:

// main.js
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';

// 导入组件
import HomeComponent from './components/HomeComponent.vue';
import AboutComponent from './components/AboutComponent.vue';

// 定义路由
const routes = [
  { path: '/', component: HomeComponent },
  { path: '/about', component: AboutComponent },
];

// 创建路由实例
const router = createRouter({
  history: createWebHistory(),
  routes,
});

// 创建 Vue 应用
const app = createApp(App);

// 使用路由
app.use(router);

// 挂载应用
app.mount('#app');

上面的代码创建了一个 Vue 应用,并且设置了两个路由:首页 ("/") 和关于页面 ("/about")。这两个路由分别对应两个不同的 Vue 组件 (HomeComponent 和 AboutComponent)。当用户在浏览器中访问不同的 URL 时,Vue Router 会动态地加载对应的组件,呈现给用户。

在 Vue 组件中,你可以通过 this.router访问路由器实例,通过this.router 访问路由器实例,通过 this.router访问路由器实例,通过this.route 访问当前路由。你可以使用 和 两个 Vue Router 提供的组件来创建导航菜单和渲染当前路由对应的组件。例如:

<template>
  <div>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
    <router-view/>
  </div>
</template>

上面的代码中, 创建了一个导航链接,当用户点击链接时,应用会导航到该链接对应的路由。 会动态地渲染当前路由对应的组件。

Vue Router 还提供了许多高级功能,如路由参数、嵌套路由、路由守卫等。你可以查阅 Vue Router 的官方文档,了解更多详细的内容。

路由参数:

在某些情况下,你可能需要将动态数据(例如来自数据库的用户ID)作为URL的一部分。你可以在Vue Router的路由配置中使用:前缀来定义路由参数:

const routes = [
  { path: '/user/:id', component: UserComponent },
];

上面的代码中,/user/:id定义了一个路由,其中id是一个动态的路由参数。当用户访问类似/user/123的URL时,123就会作为参数id的值。在对应的UserComponent组件中,你可以通过this.$route.params.id获取到这个值。

嵌套路由:

嵌套路由可以让你更灵活地组织应用的界面结构。在定义路由时,你可以使用children选项来定义子路由:

const routes = [
  {
    path: '/user/:id', 
    component: UserComponent,
    children: [
      { path: 'profile', component: UserProfileComponent },
      { path: 'posts', component: UserPostsComponent }
    ]
  },
];

上面的代码定义了两个嵌套路由。当用户访问/user/123/profile时,会渲染UserProfileComponent组件;访问/user/123/posts时,会渲染UserPostsComponent组件。

路由守卫:

路由守卫是一些特殊的函数,它们会在路由导航发生之前或之后被调用。你可以使用路由守卫来实现一些高级的路由逻辑,例如权限验证、动态标题等。

以下是一个简单的全局前置守卫的示例:

router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
});

在这个例子中,我们在每次路由导航前检查用户是否已经登录。如果用户尚未登录,并且他们试图访问非登录页面,则会被重定向到登录页面。你可以根据需要使用更复杂的逻辑来控制导航的行为。

这就是Vue Router中路由参数、嵌套路由和路由守卫的基本概念。你可以通过阅读Vue Router的官方文档来了解更多详情和更复杂的示例。

Vue3的Pinia状态管理库

Pinia 是 Vue3 的一个状态管理库,它是 Vue 官方的一种对 Vuex 的替代方案,因此它更适合在 Vue3 中使用。

Pinia 提供了一个非常简单的 API,你可以使用它轻松地创建和管理应用的状态。下面是一个基本的 Pinia 使用示例:

首先,你需要安装 pinia:

npm install pinia

在 Vue 3 组件中使用 Pinia 非常直接。首先,我们需要在主程序文件(通常是 main.js 或 main.ts)中安装 Pinia 插件并创建一个 Pinia store:

import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';

const app = createApp(App);

// 创建 pinia 实例
const pinia = createPinia();
// 在 app 中使用 pinia
app.use(pinia);

app.mount('#app');

然后,我们可以在 Pinia 中定义一个 store:

import { defineStore } from 'pinia';

export const useCounterStore = defineStore({
  id: 'counter',
  state: () => ({
    count: 0,
  }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++;
    },
  },
});

接下来,我们可以在 Vue 组件中使用这个 store:

<template>
  <div>
    <p>Count: {{ counter.count }}</p>
    <p>Double: {{ counter.double }}</p>
    <button @click="counter.increment">Increment</button>
  </div>
</template>

<script>
import { useCounterStore } from './counterStore';

export default {
  setup() {
    const counter = useCounterStore();
    return { counter };
  },
};
</script>

在 Pinia 中,我们通常会定义一个 store,这个 store 对象是应用状态的容器,它由以下几个部分组成:

  1. state: 这是一个函数,返回一个对象,该对象包含了这个 store 的初始状态。每当一个新的 store 实例被创建时,这个函数就会被调用,以生成新的状态对象。例如:
state: () => ({
  count: 0,
}),
  1. getters: 这是一个对象,它的属性是函数,这些函数可以基于 store 的状态计算出一些值。这些函数的结果会被缓存,只有当它们的依赖发生变化时,它们才会重新计算。例如:
getters: {
  double: (state) => state.count * 2,
},

在这个例子中,double getter 将会返回 count 的两倍。如果 count 的值发生了变化,double 将会被重新计算。

  1. actions: 这是一个对象,它的属性是方法,这些方法可以被用来改变 store 的状态。actions 通常用于处理异步操作,例如 API 调用。例如:
actions: {
  increment() {
    this.count++;
  },
},

在这个例子中,increment action 会增加 count 的值。注意,actions 是通过 this 来访问 state 和其他 actions 的。

在 Pinia 中,你可以使用 defineStore 函数来定义一个 store,然后在组件中使用 useStore 函数来获取这个 store 的实例。这个实例将会包含你在定义时指定的 state、getters 和 actions,你可以在组件中直接使用它们。

转载自:https://juejin.cn/post/7249595460289855543
评论
请登录