学习Vue3的第四天

news2024/11/12 21:29:28

目录

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129410.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为工程师构建生成式 AI 应用程序

作为全栈工程师&#xff0c;我们经常需要将后端和前端代码与 AI 模型集成。然而&#xff0c;访问这些模型一直是一项重大挑战。主要障碍之一是缺乏对开放和封闭模型的轻松访问。在 GitHub&#xff0c;我们正在打破访问障碍并推出GitHub Models。让您&#xff08;开发人员&#…

微服务网关终极进化:设计模式驱动的性能与可用性优化(四)

时间&#xff1a;2024年09月12日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 希望大家帮个忙&#xff01;如果大家有工作机会&#xff0c;希望帮小蒋推荐一下&#xff0c;小蒋希望遇到一个认真做事的团队&#xff0c;一起努力…

信息安全数学基础(7)最小公倍数

前言 在信息安全数学基础中&#xff0c;最小公倍数&#xff08;Least Common Multiple, LCM&#xff09;是一个重要的概念&#xff0c;它经常与最大公约数&#xff08;Greatest Common Divisor, GCD&#xff09;一起出现&#xff0c;两者在数论、密码学、模运算等领域都有广泛的…

docker-compose 部署 flink

下载 flink 镜像 [rootlocalhost ~]# docker pull flink Using default tag: latest latest: Pulling from library/flink 762bedf4b1b7: Pull complete 95f9bd9906fa: Pull complete a880dee0d8e9: Pull complete 8c5deab9cbd6: Pull complete 56c142282fae: Pull comple…

黑龙江等保测评:保障数据安全的最佳选择,助力企业无忧发展!

在数字化时代&#xff0c;数据安全已成为企业发展的重中之重。尤其是在黑龙江&#xff0c;随着信息技术的快速发展&#xff0c;数据泄露和网络攻击的风险日益增加。为了帮助企业提升数据安全防护能力&#xff0c;黑龙江等保测评应运而生&#xff0c;成为保障数据安全的有力工具…

DRW的公式推导及代码解析

流程 分阶段指定β值 # 根据当前epoch计算使用的beta值idx epoch // 160 # 每160轮epoch切换一次加权系数betas [0, 0.9999] # 两个beta值beta betas[idx] # 根据idx选择beta值 计算有效样本的权重 对权重进行归一化 &#xff08;每类权重值 / 权重总和&#xff09;* …

第7篇:【系统分析师】计算机网络

考点汇总 考点详情 1网络模型和协议&#xff1a;OSI/RM七层模型&#xff0c;网络标准和协议&#xff0c;TCP/IP协议族&#xff0c;端口 七层&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;网络层&#xff0c;数据链路层&#xff0c;…

MBD_入门篇_23_SimulinkSinks

23.1 概述 Sink库里面是Simulink的显示或导出信号数据的模块&#xff0c;可以理解为信号的最后接收的模块&#xff0c;要么用于显示要么用于传递给更上层的系统要么终止。 Sink库里面的模块都只有输入&#xff0c;没有输出。 23.2 回顾常用模块 23.2.1 Display 用于实时仿真…

终端文件管理神器 !!!【送源码】

项目简介 nnn是一款专为命令行爱好者打造的高效终端文件管理器。它以其超小的体积、几乎零配置的要求以及卓越的速度表现而著称。nnn不仅适用于Linux、macOS、BSD等操作系统&#xff0c;还能够在诸如树莓派、Android上的Termux、WSL、Cygwin等多个平台运行。它遵循POSIX标准&am…

EPSG 标识符和Web墨卡托投影的关系

Web 墨卡托投影使用修改版的墨卡托投影,并已成为 Web 制图的默认地图投影。此投影的主要区别在于它在所有尺度上都使用球面公式。而墨卡托投影使用与赤道相切的垂直圆柱投影。以下是 Web 墨卡托投影成为 Web 和在线制图事实上的标准的一些原因。 哪些 Web 地图使用 Web Merca…

从 Data 到 Data + AI,必然之路还是盲目跟风?

从 Data 到 Data AI&#xff0c;必然之路还是盲目跟风&#xff1f; 前言从 Data 到 Data AI 前言 数据和人工智能的发展日新月异&#xff0c;深刻地改变着我们的生活和工作方式。数据平台作为数据处理和分析的核心基础设施&#xff0c;也在不断演进和发展。从数据库时代到大…

Linux系统使用Docker安装DockerUI并实现远程管理本地容器无需公网IP

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

如何用MATLAB搭建ResNet网络(复现论文)

文章目录 前言基础工具网络搭建ResNet网络代码完整代码总结参考文献 前言 之前暑假实习了3个月&#xff0c;后来又赶上开学一堆事&#xff0c;现在终于有时间记录一下学习经历。新的学期开始了&#xff0c;要继续努力。 因为最近要做一个无人机航迹分类的项目&#xff0c;所以…

一周完成计算机毕业设计论文:高效写作技巧与方法(纯干货/总结与提炼)

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Trie字符串统计(每周一类)

这节课我们学习Trie字符串。这个算法的主要应用就是字符串的快速存储和查找。我们通过下面这个题来讲 Tire字符串统计 &#xff0c;另外说个题外话&#xff0c;本人是从ACwing里学习的算法知识&#xff0c;希望大家支持一下y总(ACwing大佬)&#xff0c;如果觉得我这里的知识讲得…

Unity Apple Vision Pro 开发(十):通过图像识别锚定空间

XR 开发者社区链接&#xff1a; SpatialXR社区&#xff1a;完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 课程试看&#xff1a;https://www.bilibili.com/video/BV1mpH9eVErW 课程完整版&#xff0c;答疑仅社区成员可见&#xff0c;可以通过文章开头的链接加入…

另类动态规划

前言&#xff1a;一开始我根本想不到这个题目是一个动态规划的题目&#xff0c;而且我一开始的初始状态还写错了 我还忘记了写算法题的基本步骤&#xff0c;先看数据范围&#xff0c;再考虑能不能用动态规划写 题目地址 #include <bits/stdc.h> using namespace std; #de…

RTR_Chapter_4_上半部分

第四章 Transform 变换 变换&#xff08;transform&#xff09;是指以点、向量、颜色等实体作为输入&#xff0c;并以某种方式对其进行转换的一种操作。对于计算机图形学从业者而言&#xff0c;熟练掌握变换相关的知识是非常重要的。通过各种变换操作可以对物体、光源和相机进…

开源网安斩获CCIA中国网络安全创新创业大赛总决赛三等奖

近日&#xff0c;由中央网信办指导&#xff0c;中国网络安全产业联盟&#xff08;CCIA&#xff09;主办的2024年中国网络安全创新创业大赛总决赛及颁奖典礼在国家网络安全宣传周落下帷幕。开源网安“AI代码审核平台CodeSec V4.0” 凭借在AI方向的技术创新、技术突破及功能应用创…

数据库——MySQL概述

一、数据库 存储数据的仓库&#xff0c;数据是有组织的存储&#xff0c;简称database&#xff08;DB&#xff09; 二、数据库管理系统 操控和管理数据库的大型软件&#xff08;DBMS&#xff09; 三、SQL 操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库…