学习Vue3的第四天

目录

pinia

安装 Pinia

存储+读取数据

修改数据(三种方式)

storeToRefs

getters

$subscribe

store组合式写法

组件通信

props

自定义事件

mitt

v-model

$attrs

$refs、$parent

provide、inject

slot


pinia

Pinia 是一个用于 Vue.js 的状态管理库,作为 Vuex 的替代方案,旨在提供更简单、更灵活的状态管理功能。它与 Vue 3 紧密集成,充分利用了 Vue 的 Composition API,提供了更直观的 API 和更强大的功能。

安装 Pinia

npm install pinia

操作 src/main.ts

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

const pinia = createPinia();
const app = createApp(App);

app.use(pinia);
app.mount('#app');

存储+读取数据

Store 是一个保存:状态、业务逻辑 的实体,每个组件都可以读取、写入它。

在 Pinia 中,可以使用 defineStore 来定义一个 store。这个 store 包括 state、getters 和 actions,相当于组件中的: `data`、 `computed` 和 `methods`。

import { defineStore } from 'pinia';
import axios from 'axios';
import { nanoid } from 'nanoid';

// 定义一个名为useLoveTalkStore的Pinia存储模块
export const useLoveTalkStore = defineStore('loveTalk', {
    // 定义模块的状态
    state: () => ({
        talkList: [
            { id: 'yuysada01', content: '你今天有点怪,哪里怪?怪好看的!' },
            { id: 'yuysada02', content: '草莓、蓝莓、蔓越莓,你想我了没?' },
            { id: 'yuysada03', content: '心里给你留了一块地,我的死心塌地' }
        ]
    }),
    // 定义模块的动作
    actions: {
        // 异步获取情话并添加到列表中
        async getLoveTalk() {
            try {
                // 发起HTTP GET请求获取随机情话
                const { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json');
                // 生成唯一ID并创建新的情话语对象
                const obj = { id: nanoid(), content: title };
                // 将新的情话添加到列表后面
                this.talkList.push(obj);
            } catch (error) {
                // 请求失败时输出错误信息
                console.error('Error fetching love talk:', error);
            }
        }
    }
});
<template>
  <div>
    <!-- 按钮用于获取爱情话语 -->
    <button @click="fetchLoveTalk">Get Love Talk</button>
    <!-- 循环显示爱情话语列表 -->
    <ul>
      <li v-for="talk in loveTalkStore.talkList" :key="talk.id">{{ talk.content }}</li>
    </ul>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { useLoveTalkStore } from '@/store/talk';

export default defineComponent({
  setup() {
    // 使用爱情话语的store
    const loveTalkStore = useLoveTalkStore();

    /**
     * 获取爱情话语的方法
     */
    const fetchLoveTalk = async () => {
      await loveTalkStore.getLoveTalk();
    };

    return { loveTalkStore, fetchLoveTalk };
  }
});
</script>

修改数据(三种方式)

直接修改

直接通过 store 的 state 属性来修改数据:

countStore.sum = 666;

这种方式简单直接,但通常建议避免直接修改,因为这可能绕过一些管理逻辑(比如响应式更新)。

批量修改

使用 $patch 方法批量更新多个属性:

countStore.$patch({
  sum: 999,
  school: 'atguigu'
});

$patch 方法允许一次性更新 store 的多个属性,并且它会保留之前的其他属性值。

通过 Action 修改

在 store 中定义 actions,以便在更新数据时可以包含额外的业务逻辑:

import { defineStore } from 'pinia';

export const useCountStore = defineStore('count', {
  state: () => ({
    sum: 0,
    school: ''
  }),
  actions: {
    // 加
    increment(value: number) {
      if (this.sum < 10) {
        this.sum += value;
      }
    },
    // 减
    decrement(value: number) {
      if (this.sum > 1) {
        this.sum -= value;
      }
    }
  }
});

使用 actions 的好处在于可以在状态更新之前或之后执行额外的逻辑,比如检查条件、调用其他函数等。

组件中调用 Action

在组件中,可以通过 store 实例调用 actions:

import { useCountStore } from './stores/countStore'; // 假设 store 定义在 countStore 文件中

export default {
  setup() {
    const countStore = useCountStore();

    // 示例:调用 increment 方法
    const incrementValue = 5;
    countStore.increment(incrementValue);

    // 示例:调用 decrement 方法
    const decrementValue = 2;
    countStore.decrement(decrementValue);
  }
};

storeToRefs

storeToRefs 函数将 Pinia store 中的 state 数据转换为 Vue 的 ref 对象,从而使得这些数据在模板中保持响应性。

这与 Vue 的 toRefs 函数类似,但 storeToRefs 特别针对 Pinia 的 store 设计,确保了 store 数据的响应式管理(`pinia`提供的`storeToRefs`只会将数据做转换,而`Vue`的`toRefs`会转换`store`中数据。)。使用 storeToRefs 使得组件模板中对 store 的引用更加清晰和简洁。

<template>
	<div class="count">
		<h2>当前求和为:{{sum}}</h2>
	</div>
</template>

<script setup lang="ts" name="Count">
  import { useCountStore } from '@/store/count'
  /* 引入storeToRefs */
  import { storeToRefs } from 'pinia'

	/* 得到countStore */
  const countStore = useCountStore()
  /* 使用storeToRefs转换countStore,随后解构 */
  const {sum} = storeToRefs(countStore)
</script>

storeToRefs 的优势

  • 保持响应性: 使用 storeToRefs 可以确保 store 的属性在模板中保持响应性。它将 state 属性转换为 ref 对象,从而可以在模板中直接使用。
  • 简化代码: 在模板中直接使用 storeToRefs 转化的属性,避免了对 countStore.sum 的直接引用,代码更简洁。
  • 提高可维护性: 对于较大的 store,使用 storeToRefs 可以避免直接解构 state 对象,提高代码的可维护性和清晰度。

getters

getters 是用于从 state 中派生计算值的属性,它们可以看作是 state 的“计算属性”。

  • 计算属性:getters 可以对 state 中的数据进行处理,返回一个计算后的值。
  • 缓存:getters 是基于其依赖的 state 缓存的,只有当依赖的 state 发生变化时,getters 才会重新计算。
  • 使用方法:可以在组件中直接访问 getters,它们就像普通的属性一样。
import { defineStore } from 'pinia';

/**
 * 定义一个名为Counter的Pinia存储
 * 该存储用于管理计数器相关的状态和操作
 */
export const useCounterStore = defineStore('counter', {
    /**
     * 定义存储的状态
     * 返回一个包含初始状态的对象
     */
    state: () => ({
        count: 0, // 计数器的当前值
        message: '你好,Pinia!' // 欢迎消息
    }),
    /**
     * 定义Getter,用于处理状态并返回结果
     */
    getters: {
        /**
         * 获取计数器值的两倍
         * @param state 当前的状态
         * @returns 计数器值的两倍
         */
        doubledCount: (state) => state.count * 2,
        /**
         * 将消息转换为大写
         * @param state 当前的状态
         * @returns 大写的消息
         */
        uppercaseMessage: (state) => state.message.toUpperCase()
    },
    /**
     * 定义可以修改状态的方法
     */
    actions: {
        /**
         * 增加计数器的值
         */
        increment() {
            this.count++;
        },
        /**
         * 更新消息
         * @param newMessage 新的消息内容
         */
        updateMessage(newMessage) {
            this.message = newMessage;
        }
    }
});
<template>
  <div>
    <!-- 显示计算后的计数值 -->
    <p>计数: {{ doubledCount }}</p>
    <!-- 显示转换为大写的消息 -->
    <p>消息: {{ uppercaseMessage }}</p>
    <!-- 触发计数增加的操作按钮 -->
    <button @click="increment">增加</button>
    <!-- 输入框,用于用户输入新的消息 -->
    <input v-model="newMessage" placeholder="输入新消息" />
    <!-- 触发消息更新的操作按钮 -->
    <button @click="updateMessage">修改消息</button>
  </div>
</template>

<script setup>
import { storeToRefs } from 'pinia';
import { useCounterStore } from '@/store/counterStore';

// 获取计数和消息的计算属性以及定义新的消息引用
const counterStore = useCounterStore();
// 将store中的属性转换为Vue中的ref,以便在模板中使用
const { doubledCount, uppercaseMessage } = storeToRefs(counterStore);
const newMessage = ref('');

// 增加计数
function increment() {
  counterStore.increment();
}

// 更新消息
function updateMessage() {
  counterStore.updateMessage(newMessage.value);
}
</script>

$subscribe

$subscribe 是 Pinia 中用于侦听 state 变化的一个方法。可以用它来监控 state 的任何变化,并在变化发生时执行特定的操作。它允许对 store 的 state 进行观察和响应。

talkStore.$subscribe((mutate,state)=>{
  console.log('LoveTalk',mutate,state)
  localStorage.setItem('talk',JSON.stringify(talkList.value))
})

store组合式写法

import {defineStore} from 'pinia';

export const useCounterStore = defineStore('counter', {
    state: () => ({
        count: 0,
    }),
    actions: {
        increment() {
            this.count++;
        },
        decrement() {
            this.count--;
        },
    },
});
<template>
  <div>
    <p>计数: {{ counterStore.count }}</p>
    <button @click="counterStore.increment">增加</button>
    <button @click="counterStore.decrement">减少</button>
  </div>
</template>

<script setup>
import {useCounterStore} from '@/store/counterStore';

const counterStore = useCounterStore();
</script>

组件通信

在 Vue 3 中,组件通信与 Vue 2 相比有一些显著的变化:

事件总线:

  • Vue 2:常用事件总线进行组件间的通信。
  • Vue 3:推荐使用 mitt 或其他轻量级的事件库,作为事件总线的替代方案。mitt 是一个小巧的事件发射器,可以很方便地用来处理组件之间的事件。

状态管理:

  • Vue 2:使用 vuex 进行状态管理。
  • Vue 3:pinia 作为推荐的状态管理库,提供了更简洁的 API 和更好的 TypeScript 支持。

双向绑定:

  • Vue 2:使用 .sync 修饰符来处理双向绑定。
  • Vue 3:将 .sync 的功能优化到了 v-model 中,使得双向绑定更加一致和简洁。你可以通过在 v-model 上自定义事件名称来实现类似 .sync 的功能。

事件和属性:

  • Vue 2:使用 $listeners 来访问和传递事件监听器。
  • Vue 3:将 $listeners 和其他属性合并到 $attrs 中,可以通过 v-bind="$attrs" 来传递这些属性。

子组件访问:

  • Vue 2:可以通过 $children 访问子组件。
  • Vue 3:去掉了 $children,推荐使用 ref 和 expose 来访问和操作子组件。使用 ref 可以更精确地控制子组件实例的引用。

props

在 Vue 中,props 是一种常用的组件间通信方式,主要用于 父组件到子组件 的数据传递。

父组件:

<template>
  <div class="parent">
    <!-- 按钮用于触发获取随机情话的事件 -->
    <button @click="fetchQuote">获取随机情话</button>
    <!-- 子组件用于展示获取到的随机情话 -->
    <ChildComponent :message="randomQuote" />
  </div>
</template>

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

// 定义一个响应式变量来存储随机情话
const randomQuote = ref('');

/**
 * 异步函数,用于从API获取随机情话
 */
const fetchQuote = async () => {
  try {
    // 使用axios库从指定API获取随机情话
    const {data: {content}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json');
    // 将获取到的情话内容赋值给randomQuote变量
    randomQuote.value = content;
  } catch (error) {
    // 如果发生错误,输出错误信息到控制台
    console.error('Failed to fetch quote:', error);
  }
};
</script>

<style scoped>
.parent {
  background-color: #f0f8ff; /* 轻微蓝色背景,用于区分页面其他部分 */
  padding: 20px;
  border-radius: 8px;
}
</style>

子组件

<template>
  <!-- 这个模板用来显示从父组件传递的消息 -->
  <div class="child">
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import {defineProps} from 'vue';

// 定义组件接受的props,包括一个名为message的字符串类型属性
const props = defineProps({
  message: String
});
</script>

<style scoped>
/* 为.child类定义样式,使其具有轻微的绿色背景,适当的内边距和圆角 */
.child {
  background-color: #e6ffe6; /* 轻微绿色背景 */
  padding: 10px;
  border-radius: 4px;
  margin-top: 10px;
}
</style>

总结

  • 父传子:通过 props 传递数据,属性值通常是静态数据或者动态计算的值。
  • 子传父:通过自定义事件(例如使用 emit)将数据传递回父组件。子组件触发事件,父组件处理事件并获取数据。

这种方式保证了数据流的单向性,父组件将数据传递给子组件,子组件通过事件向父组件反馈变化。

自定义事件

自定义事件是 Vue 中用来实现子组件与父组件之间通信的一种方式。

概述

自定义事件用于子组件向父组件传递信息。子组件通过 emit 方法触发事件,父组件通过 v-on 监听这些事件并响应。

区分原生事件与自定义事件

原生事件

  • 事件名是固定的,如 click、mouseenter 等。
  • 事件对象 $event 包含关于事件的详细信息,如 pageX、pageY、target 和 keyCode。

自定义事件

  • 事件名是任意名称,如 update, customEvent 等。
  • 事件对象 $event 是触发事件时通过 emit 方法传递的数据,可以是任何类型的值。

子组件

<template>
  <div class="parents">
    <button @click="fetchQuote">获取随机情话</button>
  </div>
</template>

<script setup>
import {defineEmits} from 'vue';
import axios from 'axios';

// 定义可用于子组件向父组件发送信息的自定义事件
const emit = defineEmits(['quoteReceived']);

/**
 * 异步获取随机情话并发送到父组件
 */
const fetchQuote = async () => {
  try {
    // 使用axios库从API获取随机情话数据
    const {data: {content}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json');
    // 触发自定义事件,将获取到的情话内容传递给父组件
    emit('quoteReceived', content);
  } catch (error) {
    // 在控制台记录获取情话失败的错误信息
    console.error('获取情话失败:', error);
  }
};
</script>

<style scoped>
.parents {
  background-color: #ffcccb; /* 浅红色背景 */
  border: none;
  padding: 10px 20px;
  border-radius: 5px;
  cursor: pointer;
}
</style>

父组件:

<template>
  <div class="parent">
    <!-- 引入子组件,并监听quoteReceived事件 -->
    <ChildComponent @quoteReceived="handleQuoteReceived" />
    <!-- 条件性渲染接收到的报价 -->
    <p v-if="quote">{{ quote }}</p>
  </div>
</template>

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

// 定义一个响应式变量quote来存储报价信息
const quote = ref('');

/**
 * 处理接收到的报价数据
 * @param {string} receivedQuote - 接收到的报价字符串
 */
const handleQuoteReceived = (receivedQuote) => {
  quote.value = receivedQuote;
};
</script>

<style scoped>
.parent {
  background-color: #e6e6ff; /* 浅蓝色背景 */
  padding: 20px;
  border-radius: 8px;
}
</style>

mitt

mitt 是一个轻量级的事件发布/订阅库,适用于组件间通信,特别是在 Vue.js 或其他前端框架中。它可以用来在不同组件间传递消息,而无需组件之间直接依赖。

安装 mitt

npm install mitt

创建一个事件总线

import mitt from 'mitt';
const emitter = mitt();
export default emitter;

在子组件中发布事件

<template>
  <button @click="sendMessage">发送消息</button>
</template>

<script setup>
import emitter from './eventBus.ts';

const sendMessage = () => {
  emitter.emit('message', 'Hello from child!');
};
</script>

<style scoped>
button {
  background-color: #ffcccb;
  border: none;
  padding: 10px 20px;
  border-radius: 5px;
  cursor: pointer;
}
</style>

在父组件中订阅事件

<template>
  <div>
    <ChildComponent />
    <p v-if="message">{{ message }}</p>
  </div>
</template>

<script setup>
import {ref, onMounted, onUnmounted} from 'vue';
import emitter from './eventBus.ts';
import ChildComponent from './ChildComponent.vue';

const message = ref('');

const handleMessage = (msg) => {
  message.value = msg;
};

onMounted(() => {
  emitter.on('message', handleMessage);
});

onUnmounted(() => {
  emitter.off('message', handleMessage);
});
</script>

<style scoped>
div {
  background-color: #e6e6ff;
  padding: 20px;
  border-radius: 8px;
}
</style>

v-model

v-model 是 Vue.js 中用于双向数据绑定的指令,它可以轻松地实现父子组件之间的通信。在 Vue.js 中,v-model 通常用于表单元素(如 <input>, <textarea>, <select>),但它也可以用于自定义组件以实现父子组件间的双向数据绑定。

基础示例

假设我们有一个父组件和一个子组件,父组件希望通过 v-model 来双向绑定子组件中的数据。

子组件

<template>
  <div>
    <input v-bind="inputProps" @input="updateValue"/>
  </div>
</template>

<script setup>
import {defineProps, defineEmits} from 'vue';

const props = defineProps({
  modelValue: String, // 这里定义了 v-model 的绑定值
});

const emit = defineEmits(['update:modelValue']); // 触发事件来更新 v-model 绑定的值

const updateValue = (event) => {
  emit('update:modelValue', event.target.value); // 当输入值改变时,触发事件更新父组件的数据
};
</script>
<style scoped>
div {
  background-color: #ffcccb;
  padding: 20px;
  border-radius: 8px;
}
</style>

父组件

<template>
  <div>
    <ChildComponent v-model="parentValue" />
    <p>父组件中的值: {{ parentValue }}</p>
  </div>
</template>

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

const parentValue = ref(''); // 父组件中的数据

</script>
<style scoped>
div {
  background-color: #e6e6ff;
  padding: 20px;
  border-radius: 8px;
}
</style>

$attrs

概述

$attrs 是 Vue.js 提供的一个特殊对象,用于在当前组件中接收并传递父组件传递的属性,这些属性未被当前组件声明为 props。它支持从祖组件到孙组件的通信。

具体说明

$attrs 包含所有父组件传递的非 props 属性(如 HTML 属性、用户自定义属性等),但排除了已在子组件中声明的 props。这样,子组件可以通过 $attrs 将这些属性继续传递给孙组件,确保属性链的完整传递。

父组件:

<template>
  <div class="father">
    <h3>父组件</h3>
		<Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/>
  </div>
</template>

<script setup lang="ts" name="Father">
	import Child from './Child.vue'
	import { ref } from "vue";
	let a = ref(1)
	let b = ref(2)
	let c = ref(3)
	let d = ref(4)

	function updateA(value){
		a.value = value
	}
</script>

子组件:

<template>
	<div class="child">
		<h3>子组件</h3>
		<GrandChild v-bind="$attrs"/>
	</div>
</template>

<script setup lang="ts" name="Child">
	import GrandChild from './GrandChild.vue'
</script>

孙组件:

<template>
	<div class="grand-child">
		<h3>孙组件</h3>
		<h4>a:{{ a }}</h4>
		<h4>b:{{ b }}</h4>
		<h4>c:{{ c }}</h4>
		<h4>d:{{ d }}</h4>
		<h4>x:{{ x }}</h4>
		<h4>y:{{ y }}</h4>
		<button @click="updateA(666)">点我更新A</button>
	</div>
</template>

<script setup lang="ts" name="GrandChild">
	defineProps(['a','b','c','d','x','y','updateA'])
</script>

$refs、$parent

$refs

用途:父组件 → 子组件

概述:$refs 是一个对象,包含所有被 ref 属性标识的 DOM 元素或子组件实例。它允许你直接访问子组件或 DOM 元素,通常用于在父组件中调用子组件的方法或操作 DOM。

$parent

用途:子组件 → 父组件

概述:$parent 是当前组件实例的父组件实例对象。通过 $parent,子组件可以访问父组件的方法、数据或其他属性。然而,过度使用 $parent 可能会使组件之间的耦合变得紧密,影响可维护性。

示例

<template>
  <div>
    <h1>{{ message }}</h1>
    <ChildComponent ref="childComponentRef" />
    <button @click="callChildMethod">调用子组件的方法</button>
  </div>
</template>

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

// 定义数据
const message = ref('这是父组件的消息');

// 定义方法
const childComponentRef = ref(null);

const callChildMethod = () => {
  childComponentRef.value.changeMessageInParent();
};

const updateMessage = (newMessage) => {
  message.value = newMessage;
};

// 暴露方法给子组件
defineExpose({
  updateMessage
});
</script>
<template>
  <div>
    <button @click="updateParentMessage">更新父组件的消息</button>
  </div>
</template>

<script setup>
import {getCurrentInstance} from 'vue';

// 获取父组件实例
const parent = getCurrentInstance().parent;

// 定义方法
const updateParentMessage = () => {
  parent.exposed.updateMessage('子组件更新了父组件的消息');
};

const changeMessageInParent = () => {
  parent.exposed.updateMessage('子组件方法被调用了');
};

// 暴露方法给父组件
defineExpose({
  changeMessageInParent
});
</script>

provide、inject

provide 和 inject 是 Vue 3 中用于实现祖孙组件直接通信的机制。它们允许祖先组件向其所有的后代组件传递数据或方法,而不需要逐层传递 props。这在复杂的组件树中尤其有用,可以避免 prop drilling(逐层传递 props)。

概述

  • provide:在祖先组件中定义并提供数据或方法,供后代组件使用。
  • inject:在后代组件中声明并接收祖先组件提供的数据或方法。

示例

父组件

<template>
  <div style="background-color: #e0f7fa; padding: 20px;">
    <h1>{{ message }}</h1>
    <ChildComponent />
  </div>
</template>

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

// 定义数据
const message = ref('这是父组件的消息');

// 提供数据和方法
provide('message', message);
provide('updateMessage', (newMessage) => {
  message.value = newMessage;
});
</script>

子组件

<template>
  <div style="background-color: #b2ebf2; padding: 20px;">
    <button @click="updateParentMessage">更新父组件的消息</button>
    <GrandChildComponent />
  </div>
</template>

<script setup>
import {inject} from 'vue';
import GrandChildComponent from './GrandChildComponent.vue';

// 注入数据和方法
const message = inject('message');
const updateMessage = inject('updateMessage');

// 定义方法
const updateParentMessage = () => {
  updateMessage('子组件更新了父组件的消息');
};
</script>

孙子组件

<template>
  <div style="background-color: #80deea; padding: 20px;">
    <button @click="updateParentMessage">孙子组件更新父组件的消息</button>
  </div>
</template>

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

// 注入数据和方法
const message = inject('message');
const updateMessage = inject('updateMessage');

// 定义方法
const updateParentMessage = () => {
  updateMessage('孙子组件更新了父组件的消息');
};
</script>

slot

在 Vue 3 中,slot 是一种强大的内容分发机制,允许父组件向子组件传递内容。slot 可以分为三种类型:默认插槽、具名插槽和作用域插槽。

  • 默认插槽:默认插槽是最简单的插槽类型,父组件传递的内容会被插入到子组件的默认插槽中。
  • 具名插槽:具名插槽允许父组件向子组件的不同位置传递内容,通过 name 属性来区分不同的插槽。
  • 作用域插槽:作用域插槽允许子组件向父组件传递数据,父组件可以通过作用域插槽访问这些数据。

父组件

<template>
  <div style="background-color: #e0f7fa; padding: 20px;">
    <h1>{{ message }}</h1>
    <ChildComponent>
      <!-- 具名插槽 -->
      <template #header>
        <h2>这是父组件传递的头部内容</h2>
      </template>

      <!-- 作用域插槽 -->
      <template #default="slotProps">
        <p>这是父组件传递的默认内容</p>
        <p>{{ slotProps.text }}</p>
      </template>

      <template #footer>
        <p>这是父组件传递的尾部内容</p>
      </template>
    </ChildComponent>
  </div>
</template>

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

// 定义数据
const message = ref('这是父组件的消息');
</script>

子组件

<template>
  <div style="background-color: #b2ebf2; padding: 20px;">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot :text="slotData"></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<script setup>
import { ref } from 'vue';

// 定义数据
const slotData = ref('这是子组件传递的数据');
</script>

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!很高兴回答您关于学习Vue 3的问题。Vue 3是一种流行的JavaScript框架,用于构建用户界面。它具有许多令人兴奋的新特性和改进,可以让您更轻松地开发可维护和可扩展的应用程序。 如果您已经掌握了Vue 2,那么学习Vue 3将会比较容易。以下是您可以开始学习Vue 3的一些建议: 1. 先了解Vue 3的新特性:Vue 3引入了一些重要的变化,例如Composition API(组合式API)和Teleport(传送门),这些新特性可以提升您的开发效率和代码组织能力。阅读官方文档并了解这些新特性的用法和优势是一个不错的开始。 2. 尝试使用Vue CLI创建一个新项目:Vue CLI是一个命令行工具,可以帮助您快速搭建Vue项目并提供一些常用的配置和插件。使用Vue CLI创建一个新项目可以让您更好地了解Vue 3的工作流程和项目结构。 3. 参考官方文档和教程:Vue官方文档提供了非常详细和完善的介绍,包括基础概念、API参考和实例等。您可以从官方文档中学习Vue 3的核心知识。此外,还有许多优秀的在线教程和视频资源可供参考,可以帮助您更深入地理解Vue 3的用法和最佳实践。 4. 练习和实践:学习理论知识只是第一步,更重要的是将所学知识应用于实际项目中。尝试编写一些小型的Vue 3应用程序,并逐渐增加复杂度。通过实践,您可以更好地理解Vue 3的各种概念和技术。 希望这些建议对您有所帮助!如果您有任何进一步的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在奋斗的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值