Vue基础(2)

19、组件之间传递数据

组件与组件之间不是完全独立的,而是有交集的,那就是组件与组 件之间是可以传递数据的 传递数据的解决方案就是 props

ComponentA.vue

<template><!-- 使用ComponentB组件,并传递title属性 --><h3>ComponentA</h3><ComponentB title="传递数据"/>
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {// 定义组件选项对象components: {// 将ComponentB注册为当前组件的局部组件ComponentB}
};
</script>

ComponentB.vue 

<template><!-- 使用props接收来自父组件的title属性 --><h3>ComponentB</h3><p>{{ title }}</p>
</template><script>
export default {// 定义组件选项对象props: ["title"]
};
</script>

动态数据传递

<template><!-- 使用ComponentA和ComponentB组件 --><h3>ComponentA</h3><!-- 将父组件的数据message传递给ComponentB --><ComponentB :title="message" />
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {// 定义组件选项对象data() {return {message: "动态数据" // 定义数据message};},components: {ComponentB // 将ComponentB注册为当前组件的局部组件}
};
</script>

注意事项:

props 传递数据,只能从父级传递到子级,不能反其道而行

组件传递多种数据类型

通过 props 传递数据,不仅可以传递字符串类型的数据,还可以是其 他类型,例如:数字、对象、数组等 但实际上任何类型的值都可以作为 props 的值被传递.

传递Number类型

ComponentA.vue

<template><!-- 显示ComponentA标题 --><h3>ComponentA</h3><!-- 使用ComponentB组件,并传递age属性 --><ComponentB :age="age"/>
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {data() {return {age: 20 // 定义数据age};},components: {ComponentB // 将ComponentB注册为当前组件的局部组件}
};
</script>

 ComponentB.vue

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 显示从父组件传递过来的age属性 --><p>{{ age }}</p>
</template><script>
export default {props: ["age"] // 定义props接收来自父组件的age属性
};
</script>

传递Array类型

ComponentA.vue

<template><!-- 显示ComponentA标题 --><h3>ComponentA</h3><!-- 使用ComponentB组件,并传递names属性 --><ComponentB :names="names" />
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {data() {return {names: ["iwen", "ime", "frank"] // 定义数据names};},components: {ComponentB // 将ComponentB注册为当前组件的局部组件}
};
</script>

 ComponentB.vue

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 使用v-for指令遍历names数组,并显示每个元素 --><p v-for="(item, index) of names" :key="index">{{ item }}</p>
</template><script>
export default {props: ["names"] // 定义props接收来自父组件的names属性
};
</script>

传递Object类型

ComponentA.vue

<template><!-- 显示ComponentA标题 --><h3>ComponentA</h3><!-- 使用ComponentB组件,并传递userInfo属性 --><ComponentB :userInfo="userInfo" />
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {data() {return {userInfo: { // 定义数据userInfoname: "iwen",age: 20}};},components: {ComponentB // 将ComponentB注册为当前组件的局部组件}
};
</script>

 ComponentB.vue

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 显示从父组件传递过来的userInfo.name属性的值 --><p>{{ userInfo.name }}</p><!-- 显示从父组件传递过来的userInfo.age属性的值 --><p>{{ userInfo.age }}</p>
</template><script>
export default {props: ["userInfo"] // 定义props接收来自父组件的userInfo属性
};
</script>

组件传递Props效验

Vue 组件可以更细致地声明对传入的 props 的校验要求

ComponentA.vue

<template><!-- 显示ComponentA标题 --><h3>ComponentA</h3><!-- 使用ComponentB组件,并传递title和userInfo属性 --><ComponentB title="Props效验" :userInfo="userInfo" />
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";export default {data() {return {userInfo: { // 定义数据userInfoname: "iwen",age: 20}},components: {ComponentB // 将ComponentB注册为当前组件的局部组件}
};
</script>

ComponentB.vue

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 显示从父组件传递过来的title属性的值 --><p>{{ title }}</p><!-- 显示从父组件传递过来的userInfo.name属性的值 --><p>{{ userInfo.name }}</p><!-- 显示从父组件传递过来的userInfo.age属性的值 --><p>{{ userInfo.age }}</p>
</template><script>
export default {props: { // 定义props接收来自父组件的title和userInfo属性title: {type: String},userInfo: {type: Object}}
};
</script>

默认值default

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 显示从父组件传递过来的title属性的值 --><p>{{ title }}</p><!-- 显示从父组件传递过来的userInfo.name属性的值 --><p>{{ userInfo.name }}</p><!-- 显示从父组件传递过来的userInfo.age属性的值 --><p>{{ userInfo.age }}</p><!-- 显示从父组件传递过来的age属性的值 --><p>{{ age }}</p>
</template><script>
export default {// 定义props选项,接收来自父组件的title、userInfo和age属性props: {title: {type: String // title属性的类型为String},userInfo: {type: Object, // userInfo属性的类型为Objectdefault() {return {} // 默认值为空对象}},age: {type: Number, // age属性的类型为Numberdefault: 20 // 默认值为20}}
};
</script>

必选项required

<template><!-- 显示ComponentB标题 --><h3>ComponentB</h3><!-- 显示从父组件传递过来的title属性的值 --><p>{{ title }}</p><!-- 显示从父组件传递过来的userInfo.name属性的值 --><p>{{ userInfo.name }}</p><!-- 显示从父组件传递过来的userInfo.age属性的值 --><p>{{ userInfo.age }}</p><!-- 显示从父组件传递过来的age属性的值 --><p>{{ age }}</p>
</template><script>
export default {// 定义props选项,接收来自父组件的title、userInfo和age属性props: {title: {type: String, // title属性的类型为Stringrequired: true // title属性是必需的},userInfo: {type: Object, // userInfo属性的类型为Object// 对象或者数组应当用工厂函数返回default() {return {} // 默认值为空对象}},age: {type: Number, // age属性的类型为Numberdefault: 20 // 默认值为20}
};
</script>

在Vue.js中,prop 是一种特殊的数据属性,用于父组件向子组件传递数据。prop 是只读的,这意味着子组件不能修改从父组件接收到的 prop 数据。如果尝试修改 prop 的值,Vue 会发出警告信息,提示 prop 是只读的。

20、组件事件

在Vue.js框架中,组件之间的通信是一个常见的需求。$emit方法就是用来在组件的模板表达式中触发自定义事件的,这使得父子组件之间可以进行通信。通过这种方式,子组件可以向父组件发送消息,比如通知某个操作已经完成,或者请求父组件执行某个操作。

自定义事件的触发可以用于多种目的,其中之一就是组件之间传递数据。例如,当用户在子组件中进行某种操作时,子组件可以通过$emit方法向父组件发送一个事件,携带必要的数据。父组件可以监听这个事件,并在事件触发时接收数据,从而实现数据的传递。

父组件(ComponentA.vue)

<template><!-- 显示标题 --><h3>ComponentA</h3><!-- 引入子组件ComponentB,并监听名为some-event的自定义事件 --><ComponentB @some-event="getHandle"/><!-- 显示从子组件接收到的数据 --><p>ComponentA接受的数据: {{ message }}</p>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue"export default {data() {return {// 初始化一个空字符串用于存储从子组件接收到的数据message: ""}},components: {// 注册子组件ComponentBComponentB},methods: {// 定义一个方法getHandle,用于处理从子组件接收到的数据getHandle(data) {this.message = data; // 将接收到的数据赋值给message属性}}
}
</script>

子组件(ComponentB.vue)

<template><!-- 显示标题 --><h3>ComponentB</h3><!-- 定义一个按钮,点击时触发sendHandle方法 --><button @click="sendHandle">发送数据</button>
</template><script>
export default {methods: {// 定义一个方法sendHandle,用于触发自定义事件并发送数据sendHandle() {this.$emit("someEvent", "ComponentB的数据"); // 触发名为someEvent的事件,并传递数据}}
}
</script>

组件之间传递数据:

  1. 父传子:使用 props

    • 在Vue.js中,props是父组件向子组件传递数据的一种方式。父组件可以通过在子组件标签中定义属性来传递数据,这些属性在子组件内部可以通过props对象访问。

    • 这种方式是单向数据流,确保了数据的流向是从父组件到子组件,有助于避免组件之间的耦合。

  2. 子传父:使用自定义事件 (this.$emit)

    • 当需要从子组件向父组件传递数据时,可以使用自定义事件。子组件通过this.$emit方法触发一个事件,并将数据作为参数传递。父组件需要监听这个事件,并在事件触发时接收数据。

    • 这种方式允许子组件在需要时通知父组件,例如用户交互或数据变化。

组件事件配合 v-model 使用

如果是用户输入,我们希望在获取数据的同时发送数据配合 v-model 来使用

父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用@some-event监听来自ComponentB的自定义事件 --><componentB @some-event="getHandle"/><!-- 显示从ComponentB接收到的数据 --><p>ComponentA接受的数据: {{ message }}</p></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue"export default {data() {return {// 初始化message为空字符串,用于存储从子组件接收的数据message: ""}},components: {// 注册子组件ComponentBComponentB},methods: {// 定义getHandle方法来接收从子组件传递的数据getHandle(data) {this.message = data;}}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用v-model绑定输入框的值到searchText --><input v-model="searchText" /></div>
</template><script>
export default {data() {return {// 初始化searchText为空字符串searchText: ""}},watch: {// 监听searchText的变化searchText(newVal, oldVal) {// 当searchText变化时,触发someEvent事件,并将新值作为参数传递this.$emit("someEvent", newVal);}}
}
</script>

组件数据传递

通常我们使用 props 来实现父组件向子组件的数据传递(单向下行绑定),但Vue.js也提供了一种方式,使得子组件可以通过 props 实现数据的“回传”给父组件,这通常通过使用 .sync 修饰符或在Vue 3中使用 v-model 来实现。

父组件(ParentComponent.vue)

<template><div><h3>ComponentA</h3><!-- 使用:onFnEvent监听来自ChildComponent的自定义事件 --><Child :onFnEvent="fn" /><!-- 显示从ChildComponent接收到的数据 --><p>{{ message }}</p></div>
</template><script>
// 导入子组件Child
import Child from "./components/Child.vue";export default {data() {return {// 初始化message为空字符串,用于存储从子组件接收的数据message: ""}},methods: {// 定义fn方法来接收从子组件传递的数据fn(data) {this.message = data;}},components: {// 注册子组件ChildChild}
}
</script>

子组件(Child.vue)

<template><div><h3>组件传递数据</h3><!-- 调用onFnEvent方法并传递数据 --><p>{{ onFnEvent('测试数据') }}</p></div>
</template><script>
export default {props: {// 定义一个名为onFnEvent的prop,类型为FunctiononFnEvent: {type: Function}}
}
</script>

代码解释

  1. 父组件(ParentComponent.vue):

    • 在模板中,使用<Child :onFnEvent="fn" />标签引入子组件,并使用:onFnEvent="fn"来监听子组件触发的事件。

    • 当子组件触发事件时,父组件的fn方法会被调用,并接收子组件传递的数据。

    • message数据属性用于存储从子组件接收到的数据,并在模板中显示。

  2. 子组件(Child.vue):

    • 在模板中,调用onFnEvent方法并传递数据'测试数据'

    • 定义一个名为onFnEventprop,类型为Function,用于接收父组件传递的事件处理函数。

21、插槽 Slots

我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能 想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这 些片段。

<solt>元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽 内容 (slot content) 将在哪里被渲染.

父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用ComponentB,并在插槽中传递内容 --><ComponentB><h3>插槽传递视图内容</h3></ComponentB></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";export default {components: {// 注册子组件ComponentBComponentB}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签来接收从父组件传递的内容 --><slot></slot></div>
</template><script>
export default {// ComponentB不需要额外的逻辑,只需定义插槽
}
</script>

渲染作用域

插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在 父组件模板中定义的.

父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用ComponentB,并在插槽中传递内容 --><ComponentB><h3>{{ message }}</h3></ComponentB></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";export default {data() {return {// 定义message数据属性,用于存储要传递给子组件的内容message: "message在父级"}},components: {// 注册子组件ComponentBComponentB}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签来接收从父组件传递的内容 --><slot></slot></div>
</template><script>
export default {// ComponentB不需要额外的逻辑,只需定义插槽
}
</script>

默认内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容.

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签定义插槽,并设置默认内容 --><slot>插槽默认值</slot></div>
</template><script>
export default {// ComponentB不需要额外的逻辑,只需定义插槽和默认值
}
</script>

具名插槽

父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用ComponentB,并为header和main插槽传递内容 --><ComponentB><template v-slot:header><h3>标题</h3></template><template v-slot:main><p>内容</p></template></ComponentB></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";export default {data() {return {// 定义message数据属性,虽然在这个例子中没有用到message: "message在父级"}},components: {// 注册子组件ComponentBComponentB}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签定义具名插槽header --><slot name="header"></slot><hr><!-- 使用<slot>标签定义具名插槽main --><slot name="main"></slot></div>
</template><script>
export default {// ComponentB不需要额外的逻辑,只需定义具名插槽
}
</script>

代码解释

  1. 父组件(ComponentA.vue):

    • 在模板中,使用<ComponentB>标签引入子组件,并为headermain插槽传递内容。

    • 使用<template v-slot:header><template v-slot:main>来指定内容应该填充到哪个插槽中。

    • ComponentB组件被注册在父组件的components对象中,使其可以在父组件的模板中使用。

  2. 子组件(ComponentB.vue):

    • 在模板中,使用<slot name="header"></slot><slot name="main"></slot>来定义具名插槽。这些插槽用于接收从父组件传递的内容。

    • 当父组件使用<ComponentB>标签并包含具名插槽的内容时,这些内容将替换子组件中的相应插槽标签。

 在Vue.js中,v-slot 指令用于定义插槽,而 # 符号是 v-slot 的简写形式,用于指定插槽的名称。

 父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用ComponentB,并为header和main插槽传递内容 --><ComponentB><template #header><h3>标题</h3></template><template #main><p>内容</p></template></ComponentB></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";export default {data() {return {// 定义message数据属性,用于存储要传递给子组件的内容message: "message在父级"}},components: {// 注册子组件ComponentBComponentB}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签定义具名插槽header --><slot name="header"></slot><hr><!-- 使用<slot>标签定义具名插槽main --><slot name="main"></slot></div>
</template><script>
export default {// ComponentB不需要额外的逻辑,只需定义具名插槽
}
</script>

在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时 将一部分数据提供给插槽 我们也确实有办法这么做!可以像对组件传递 props 那样,向一个 插槽的出口上传递 attributes

父组件(ComponentA.vue)

<template><div><h3>ComponentA</h3><!-- 使用ComponentB,并通过具名插槽slotProps传递数据 --><componentB v-slot="slotProps"><h3>{{ message }}-{{ slotProps.text }}</h3></componentB></div>
</template><script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";export default {data() {return {// 定义message数据属性,用于存储要传递给子组件的内容message: "message在父级"}},components: {// 注册子组件ComponentBComponentB}
}
</script>

子组件(ComponentB.vue)

<template><div><h3>ComponentB</h3><!-- 使用<slot>标签定义具名插槽,并传递message数据 --><slot :text="message"></slot></div>
</template><script>
export default {data() {return {// 定义message数据属性,用于存储子组件的数据message: "ComponentB中的数据"}}
}
</script>

代码解释

  1. 父组件(ComponentA.vue):

    • 在模板中,使用<componentB>标签引入子组件,并为slotProps插槽传递内容。

    • 使用<template v-slot="slotProps">来指定内容应该填充到哪个插槽中,并从子组件接收数据。

    • message数据属性用于存储要传递给子组件的内容。

    • ComponentB组件被注册在父组件的components对象中,使其可以在父组件的模板中使用。

  2. 子组件(ComponentB.vue):

    • 在模板中,使用<slot :text="message"></slot>来定义具名插槽。这个插槽用于接收从父组件传递的内容。

    • message数据属性用于存储子组件的数据,并通过插槽传递给父组件。

 具名插槽传递数据

<template><!-- 显示ComponentA的标题 --><h3>ComponentA</h3><!-- 使用ComponentB组件,并通过名为header的slot传递slotProps --><ComponentB #header="slotProps"><!-- 显示从父组件传递的消息和slotProps.text --><h3>{{ message }}-{{ slotProps.text }}</h3></ComponentB>
</template><script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue"export default {data() {return {// 定义一个消息变量,用于在模板中显示message: "message在父级"}},// 定义组件对象,用于注册子组件components: {ComponentB}
}
</script>
<template><!-- 显示ComponentB的标题 --><h3>ComponentB</h3><!-- 使用slot,允许父组件通过名为header的slot传递内容 --><slot name="header" :text="message"></slot>
</template><script>
export default {data() {return {// 定义一个消息变量,用于在模板中显示message: "ComponentB中的数据"}}
}
</script>

22、组件生命周期

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如 设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变 时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函 数,让开发者有机会在特定阶段运行自己的代码。

<template><!-- 显示组件生命周期的标题 --><h3>组件生命周期</h3><!-- 显示message数据 --><p>{{ message }}</p><!-- 一个按钮,点击时调用updateHandle方法更新数据 --><button @click="updateHandle">更新数据</button>
</template><script>
export default {// data函数返回一个对象,其中包含一个message属性,初始值为"老数据"data() {return {message: "老数据"}},// methods对象包含组件的方法methods: {// updateHandle方法更新message属性的值为"新数据"updateHandle() {this.message = "新数据"}},// 生命周期钩子函数beforeCreate() {// 在组件实例初始化之后调用,此时不能访问data中的属性console.log("组件创建之前");},created() {// 在实例创建完成后被立即调用,此时可以访问data中的属性console.log("组件创建之后");},beforeMount() {// 在挂载开始之前被调用,相关的render函数首次被调用console.log("组件渲染之前");},mounted() {// el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子console.log("组件挂载之后");},beforeUpdate() {// 数据更新之前调用,可以访问data中的属性,但是视图尚未更新console.log("数据更新之前");},updated() {// 数据更新之后调用,可以访问data中的属性,视图已经更新console.log("数据更新之后");},beforeUnmount() {// 实例销毁之前调用,此时可以访问data中的属性,但是视图已经销毁console.log("组件卸载之前");},unmounted() {// 实例销毁后调用,此时不能访问data中的属性console.log("组件卸载之后");}
}
</script>
  • beforeCreate:在组件实例初始化之后调用,此时不能访问data中的属性。

  • created:在实例创建完成后被立即调用,此时可以访问data中的属性。

  • beforeMount:在挂载开始之前被调用,相关的render函数首次被调用。

  • mounted:el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。

  • beforeUpdate:数据更新之前调用,可以访问data中的属性,但是视图尚未更新。

  • updated:数据更新之后调用,可以访问data中的属性,视图已经更新。

  • beforeUnmount:实例销毁之前调用,此时可以访问data中的属性,但是视图已经销毁。

  • unmounted:实例销毁后调用,此时不能访问data中的属性。

生命周期应用

通过ref获取元素DOM结构

<template><!-- 模板部分 --><h3>组件生命周期应用</h3><!-- 一个段落元素,通过ref属性设置引用名为"name" --><p ref="name">哈哈哈</p>
</template><script>
export default {// beforeMount生命周期钩子beforeMount() {// 在这个阶段,DOM尚未渲染,因此$refs.name是undefinedconsole.log(this.$refs.name); // 输出:undefined},// mounted生命周期钩子mounted() {// 在这个阶段,DOM已经渲染完成,可以通过$refs访问模板中的DOM元素console.log(this.$refs.name); // 输出:<p ref="name">哈哈哈</p>的DOM元素}
}
</script>
  • beforeMount 生命周期钩子:在这个阶段,Vue 已经完成了模板的编译,但是还没有挂载 DOM 元素,因此 this.$refs.nameundefined

  • mounted 生命周期钩子:在这个阶段,Vue 已经完成了模板的挂载,DOM 元素已经创建并添加到页面中,因此可以通过 this.$refs.name 访问到 <p> 元素的 DOM 对象。

模拟网络请求渲染数据,页面加载后初始化数据

<template><!-- 模板部分 --><h3>组件生命周期应用</h3><!-- 使用v-for指令循环渲染banner数组中的每一项 --><ul><li v-for="(item, index) in banner" :key="index"><!-- 显示每一项的标题 --><h3>{{ item.title }}</h3><!-- 显示每一项的内容 --><p>{{ item.content }}</p></li></ul>
</template><script>
export default {// data函数返回一个对象,其中包含一个banner数组,初始为空data() {return {banner: []}},// mounted生命周期钩子mounted() {// 在组件挂载到DOM后,初始化banner数组this.banner = [{"title": "我在爱尔兰","content": "爱尔兰(爱尔兰语:Poblacht na hÉireann;英语:Republic of Ireland), 是一个西欧的议会共和制国家,西临大西洋,东靠爱尔兰海,与英国隔海相望,是北美通向欧洲的通道爱尔兰自然",},{"title": "一个人的东京","content": "东京(Tokyo)是日本国的首都,是亚洲第一大城市,世界第二大城市。全球最大的经济中心之一。东京的著名观光景点有东京铁塔、皇居、国会议事堂、浅草寺、浜离宫、上野公园与动物园",},{"title": "普罗旺斯的梦","content": "普罗旺斯(Provence)位于法国东南部,毗邻地中海和意大利,从地中海沿岸延伸到内陆的丘陵地区,中间有大河“Rhone”流过。自古就以靓丽的阳光和蔚蓝的天空,迷人的地中海和心醉",},{"title": "相约夏威夷之夏","content": "夏威夷州位于北太平洋中,距离美国本土3,700公里,总面积16,633平方公里,属于太平洋沿岸地区。首府为檀香山。在1778至1898年间,夏威夷也被称为“三明治群岛”(Sandwich Islands)",}]}
}
</script>

 23、动态组件

有些场景会需要在两个组件间来回切换,比如 Tab 界面

<template><h3>ComponentA</h3>
</template>
<template><h3>ComponentB</h3>
</template>
<template><!-- 模板部分 --><h3>组件切换</h3><!-- 使用 :is 绑定来动态切换组件 --><component :is="currentTab"></component><!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 --><button @click="changeComponentHandle">切换</button>
</template><script>
// 导入ComponentA和ComponentB组件
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"export default {// 注册ComponentA和ComponentB为本地组件components: {ComponentA,ComponentB},// data函数返回一个对象,其中包含一个currentTab属性,用于控制显示哪个组件data() {return {currentTab: "ComponentA", // 默认显示ComponentA}},// methods对象包含组件的方法methods: {// changeComponentHandle方法用于切换currentTab的值,从而切换组件changeComponentHandle() {this.currentTab = this.currentTab === "ComponentA" ? "ComponentB" : "ComponentA";}}
}
</script>
  • :is 是一个属性绑定,它用于动态地绑定组件的名称或路径。

 就相当于是<componentA/>

24、组件保持存活

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过<keep-alive>组件强制被切换掉的组件仍然保持“存活”的状态,下一次使用该组件的时候需要重新渲染,浪费资源。

就是加个标签的事儿

<template><!-- 模板部分 --><h3>组件切换</h3><!-- 使用 <keep-alive> 包裹动态组件,保持切换组件的状态 --><keep-alive><!-- 使用 :is 绑定来动态切换组件 --><!-- 当 currentTab 变化时,Vue 将根据 currentTab 的值渲染对应的组件 --><component :is="currentTab"></component></keep-alive><!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 --><!-- 这将改变 currentTab 的值,从而触发组件的切换 --><button @click="changeComponentHandle">切换</button>
</template><script>
// 导入ComponentA和ComponentB组件
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"export default {// 注册ComponentA和ComponentB为本地组件,使其在模板中可用components: {ComponentA,ComponentB},// data函数返回一个对象,其中包含一个currentTab属性,用于控制显示哪个组件data() {return {currentTab: "ComponentA", // 默认显示ComponentA组件}},// methods对象包含组件的方法methods: {// changeComponentHandle方法用于切换currentTab的值,从而切换组件// 当按钮被点击时,这个方法会被调用changeComponentHandle() {// 使用三元运算符来切换currentTab的值// 如果当前是ComponentA,则切换到ComponentB,反之亦然this.currentTab = this.currentTab === "ComponentA" ? "ComponentB" : "ComponentA";}}
}
</script>
  • <keep-alive> 标签用于包裹动态组件 <component :is="currentTab"></component>。它的作用是保持组件的状态,即使组件被切换,之前的状态也不会丢失,这样可以提高性能,因为避免了不必要的组件销毁和重建。

 25、异步组件

在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent方法来实现此功能

<template><!-- 模板部分 --><h3>组件切换</h3><!-- 使用 <keep-alive> 包裹动态组件,保持切换组件的状态 --><keep-alive><!-- 使用 :is 绑定来动态切换组件 --><!-- 当 currentTab 变化时,Vue 将根据 currentTab 的值渲染对应的组件 --><component :is="currentTab"></component></keep-alive><!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 --><!-- 这将改变 currentTab 的值,从而触发组件的切换 --><button @click="changeComponentHandle">切换</button>
</template><script>
// 从 'vue' 导入 defineAsyncComponent 方法,用于定义异步组件
import { defineAsyncComponent } from 'vue'
// 导入 ComponentA 组件
import ComponentA from "./components/ComponentA.vue"
// 使用 defineAsyncComponent 定义异步加载的 ComponentB 组件
const AsyncComponentB = defineAsyncComponent(() =>import('./components/ComponentB.vue')
)export default {// 注册 ComponentA 和 AsyncComponentB 为本地组件,使其在模板中可用components: {ComponentA,AsyncComponentB},// data 函数返回一个对象,其中包含一个 currentTab 属性,用于控制显示哪个组件data() {return {currentTab: "ComponentA", // 默认显示 ComponentA 组件}},// methods 对象包含组件的方法methods: {// changeComponentHandle 方法用于切换 currentTab 的值,从而切换组件// 当按钮被点击时,这个方法会被调用changeComponentHandle() {// 使用条件运算符来切换 currentTab 的值// 如果当前是 ComponentA,则切换到 AsyncComponentB,反之亦然this.currentTab = this.currentTab == "ComponentA" ? "AsyncComponentB" : "ComponentA";}}
}
</script>
  1. 异步组件

    • 使用 defineAsyncComponent 方法定义了一个异步组件 AsyncComponentB。这允许 Vue 延迟加载 ComponentB.vue 文件,直到实际需要渲染该组件时才加载。

    • 异步组件在大型应用中非常有用,可以减少初始加载时间,提高性能。

26、依赖注入

通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦 。

这一问题被称为“prop 逐级透传”

provide 和 inject 可以帮助我们解决这一问题。 一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖 

<template><!-- 模板部分 --><h3>祖宗</h3> <!-- 显示“祖宗”标题 --><Parent /> <!-- 使用子组件 Parent -->
</template><script>
// 导入子组件 Parent
import Parent from "./components/Parent.vue"export default {// 使用 provide 提供一个 message,可以在子孙组件中通过 inject 访问provide: {message: "爷爷的财产"},// 注册子组件 Parent,使其在模板中可用components: {Parent}
}
</script>
<template><!-- 模板部分 --><h3>Parent</h3> <!-- 显示“Parent”标题 --><Child /> <!-- 使用子组件 Child -->
</template><script>
// 导入子组件 Child
import Child from "./Child.vue"export default {// 注册子组件 Child,使其在模板中可用components: {Child // 注册的组件名称与模板中使用的标签名称一致}
}
</script>

 

<template><!-- 模板部分 --><h3>Child</h3> <!-- 显示“Child”标题 --><p>{{ message }}</p> <!-- 显示从祖先组件注入的消息 -->
</template><script>
export default {// 使用 inject 选项来接收名为 message 的数据inject: ["message"]
}
</script>
  • provide/inject:这是 Vue 提供的一种跨组件通信方式,允许一个祖先组件向其所有子孙组件提供数据,而不必通过每个中间组件逐级传递 props。

  • provide 和 inject 只能由上到下的传递,不能反向传递

// 导入 Vue 的 createApp 函数
import { createApp } from 'vue'
// 导入根组件 App
import App from './App.vue'// 创建一个 Vue 应用实例
const app = createApp(App)// 使用 app.provide 提供全局数据
// 这里提供一个名为 "golabData" 的数据,值是 "我是全局数据"
app.provide("golabData", "我是全局数据")// 将 Vue 应用挂载到 id 为 'app' 的 DOM 元素上
app.mount('#app')

 

  • 使用 app.provide("golabData", "我是全局数据") 提供一个全局数据。这里 golabData 是一个键,"我是全局数据" 是这个键对应的值。任何组件都可以通过 inject 选项访问这个全局数据。

 27、Vue应用

vue从哪开始执行的?

每个 Vue 应用都是通过 createApp函数创建一个新的 应用实例

// 从 'vue' 导入 createApp 函数,用于创建 Vue 应用实例
import { createApp } from 'vue'
// 导入根组件 App
import App from './App.vue'// 创建 Vue 应用实例
// 在一个 Vue 项目中,通常只有一个 Vue 应用实例
const app = createApp(App)// 将 Vue 应用挂载到页面中 id 为 'app' 的元素上
app.mount('#app')

我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。

import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'const app = createApp(App)

应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串.页面挂载到index.html文件上的id=app元素上。

app.mount('#app')
<div id="app"></div>

src目录下的assets文件夹的作用就是存放公共资源,例如:图片、公共CSS或者字体图标等. 

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

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

相关文章

STM32_SD卡的SDIO通信_基础读写

本篇将使用CubeMXKeil, 创建一个SD卡读写的工程。 目录 一、SD卡要点速读 二、SDIO要点速读 三、SD卡座接线原理图 四、CubeMX新建工程 五、CubeMX 生成 SD卡的SDIO通信部分 六、Keil 编辑工程代码 七、实验效果 实现效果&#xff0c;如下图&#xff1a; 一、SD卡 速读…

【深度学习】2.视觉问题与得分函数

计算机视觉任务 可以通过神经网络搜索是什么类别的动物。 图像实际就是含有数值的三维矩阵。 像素值从0-255可以表示亮度递增的参数。数字越大&#xff0c;像素点越亮。 最后的3表示三个颜色通道&#xff0c;常见的如JPG、RGB等。 现实场景容易发生各种遮蔽现象。 计算机判断…

JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收 我们会把堆内存中的对象间隔一段时间做一次GC&#xff08;即垃圾回收&#xff09;&#xff0c;但是堆内存很大一块&#xff0c;内存布局分为新生代和老年代、其对象的特点不一样&#xff0c;所以回收的策略也应该各不相同 对于“刚出生”的新对象&#xf…

从根源分析,调试,定位和解决MacOS ld: unsupported tapi file type ‘!tapi-tbd‘ in YAML file

你要是遇到同样错误&#xff0c;找一圈都没有解决&#xff0c;建议认真读一下本文&#xff0c;这个应该是最终极的解决办法&#xff0c;从原理上剖析了产生的原因&#xff0c;同时给出来了调试和定位的办法。 maccos使用brew安装了一个gcc14, 结果编译一个最简单的程序都报错&a…

单片机-STM32 IIC通信(OLED屏幕)(十一)

一、屏幕的分类 1、LED屏幕&#xff1a; 由无数个发光的LED灯珠按照一定的顺序排列而成&#xff0c;当需要显示内容的时候&#xff0c;点亮相关的LED灯即可&#xff0c;市场占有率很高&#xff0c;主要是用于户外&#xff0c;广告屏幕&#xff0c;成本低。 LED屏是一种用发光…

Windows cmd常用命令

文章目录 Windows cmd常用命令一、引言二、文件和目录操作1、查看和切换目录2、文件和目录的创建与删除 三、系统信息与网络配置1、系统信息2、网络配置 四、使用示例五、总结 Windows cmd常用命令 一、引言 Windows 命令提示符&#xff08;cmd&#xff09;是一个强大的工具&a…

snippets router pinia axios mock

文章目录 补充VS Code 代码片段注册自定义组件vue routerpinia删除vite创建项目时默认的文件axiosmock3.0.x版本的 viteMockServe 补充 为文章做补充&#xff1a;https://blog.csdn.net/yavlgloss/article/details/140063387 VS Code 代码片段 为当前项目创建 Snippets {&quo…

Spring MVC中HandlerInterceptor和Filter的区别

目录 一、处理阶段 二、功能范围 三、参数访问 四、配置方式 五、使用场景说明 在Spring MVC中&#xff0c;HandlerInterceptor和Filter都是用于拦截请求的重要组件&#xff0c;但它们在多个方面存在显著的差异。本文将详细解析这两种拦截机制的区别&#xff0c;并结合使用…

在K8S中,如何使用EFK实现日志的统一管理?

在Kubernetes中&#xff0c;EFK是一种常见的日志统一管理方案。EFK堆栈允许你收集、存储、搜素、分析和可视化容器应用程序的日志。下面是如何在Kubernetes中使用EFK实现日志统一管理的详细步骤&#xff1a; 部署Elasticsearch elasticsearch是一个分布式、RESTful风格的搜索…

神经网络基础 | 给定条件下推导对应的卷积层参数

神经网络基础 | 给定条件下推导对应的卷积层参数 按照 PyTorch 文档中 给定的设置&#xff1a; H o u t ⌊ H i n 2 padding [ 0 ] − dilation [ 0 ] ( kernel_size [ 0 ] − 1 ) − 1 stride [ 0 ] 1 ⌋ H_{out} \left\lfloor\frac{H_{in} 2 \times \text{padding}[0]…

欧拉(Euler 22.03)安装ProxySQL

下载离线安装包 proxysql-2.0.8-1-centos7.x86_64.rpm 链接: https://pan.baidu.com/s/1R-SJiVUEu24oNnPFlm9wRw 提取码: sa2w离线安装proxysql yum localinstall -y proxysql-2.0.8-1-centos7.x86_64.rpm 启动proxysql并检查状态 systemctl start proxysql 启动proxysql syste…

Sharding-JDBC 5.4.1+SpringBoot3.4.1+MySQL8.4.1 使用案例

最近在升级 SpringBoot 项目&#xff0c;原版本是 2.7.16&#xff0c;要升级到 3.4.0 &#xff0c;JDK 版本要从 JDK8 升级 JDK21&#xff0c;原项目中使用了 Sharding-JDBC&#xff0c;版本 4.0.0-RC1&#xff0c;在升级 SpringBoot 版本到 3.4.0 之后&#xff0c;服务启动失败…

MacOS/C/C++下怎样进行软件性能分析(CPU/GPU/Memory)

在macOS环境下进行C/C软件性能分析&#xff0c;可以使用多种工具和技术来测量和优化CPU、GPU和内存的性能。macOS提供了丰富的性能分析工具&#xff0c;如Instruments、gprof、Perf、以及NVIDIA和Intel的专用工具。下面详细介绍了实现思想和操作方法。 1. 性能分析的目标 CPU…

WPS计算机二级•幻灯片的基础操作

听说这是目录哦 PPT的正确制作步骤&#x1f6e3;️认识PPT界面布局&#x1f3dc;️PPT基础操作 快捷键&#x1f3de;️制作PPT时 常用的快捷技巧&#x1f3d9;️快速替换PPT的 文本字体&#x1f303;快速替换PPT 指定文本内容&#x1f305;能量站&#x1f61a; PPT的正确制作步…

vue3组件传值具体使用

问&#xff1a; left.vue文件调用接口获取了后端返回的urlLink字段&#xff0c;我该怎么传递给总的父组件index.vue中&#xff0c;我需要点击父组件的一个按钮来触发跳转&#xff1f; 回答&#xff1a; 在 Vue 3 中使用 TypeScript 和 setup 语法糖时&#xff0c;可以通过 e…

easyexcel读取写入excel easyexceldemo

1.新建springboot项目 2.添加pom依赖 <name>excel</name> <description>excelspringboot例子</description><parent> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId&…

考研机试题:打印数字菱形

描述 打印一个由数字 0∼n 构成的菱形。 其中 n 位于正中心&#xff0c;数字靠近边缘时逐个递减&#xff0c;直至为 0。 例如&#xff0c;当 n5时&#xff0c;图形如下所示&#xff1a; 00 1 00 1 2 1 00 1 2 3 2 1 00 1 2 3 4 3 2 1 0 0 1 2 3 4 5 4 3 2 1 00 1 2 3 4 3 2 …

Neural networks 神经网络

发展时间线 基础概念 多层神经网络结构 神经网络中一个网络层的数学表达 TensorFlow实践 创建网络层 神经网络的创建、训练与推理 推理 推理可以理解为执行一次前向传播 前向传播 前向传播直观数学表达 前向传播直观数学表达的Python实现 前向传播向量化实现 相关数学知识…

【探索 Kali Linux】渗透测试与网络安全的终极操作系统

探索 Kali Linux&#xff1a;渗透测试与网络安全的终极操作系统 在网络安全领域&#xff0c;Kali Linux 无疑是最受欢迎的操作系统之一。无论是专业的渗透测试人员、安全研究人员&#xff0c;还是对网络安全感兴趣的初学者&#xff0c;Kali Linux 都提供了强大的工具和灵活的环…

AR智慧点巡检系统探究和技术方案设计

一、项目背景 随着工业生产规模的不断扩大和设备复杂度的提升&#xff0c;传统的人工点巡检方式效率低下、易出错&#xff0c;难以满足现代化企业对设备运行可靠性和安全性的要求。AR&#xff08;增强现实&#xff09;技术的发展为点巡检工作带来了新的解决方案&#xff0c;通…