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.rhkb.cn/news/6388.html

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

相关文章

Java操作Excel导入导出——POI、Hutool、EasyExcel

目录 一、POI导入导出 1.数据库导出为Excel文件 2.将Excel文件导入到数据库中 二、Hutool导入导出 1.数据库导出为Excel文件——属性名是列名 2.数据库导出为Excel文件——列名起别名 3.从Excel文件导入数据到数据库——属性名是列名 4.从Excel文件导入数据到数据库…

08-ArcGIS For JavaScript-通过Mesh绘制几何体(Cylinder,Circle,Box,Pyramid)

目录 概述代码实现1、Mesh.createBox2、createPyramid3、Mesh.createSphere4、Mesh.createCylinder 完整代码 概述 对于三维场景而言&#xff0c;二位的点、线、面&#xff0c;三维的圆、立方体、圆柱等都是比较常见的三维对象&#xff0c;在ArcGIS For JavaScript中我们知道点…

DAY6,使用互斥锁 和 信号量分别实现5个线程之间的同步

题目 请使用互斥锁 和 信号量分别实现5个线程之间的同步 代码&#xff1a;信号量实现 void* task1(void* arg); void* task2(void* arg); void* task3(void* arg); void* task4(void* arg); void* task5(void* arg);sem_t sem[5]; //信号量变量int main(int argc, const …

19_PlayerPres持久化_创建角色窗口

创建脚本 编写脚本 using UnityEngine; //功能 : 角色创建界面 public class CreateWnd : WindowsRoot{protected override void InitWnd(){base.InitWnd();//TODO//显示一个随机名字} }创建角色窗口CreateWnd.cs应该在玩家点击 进入游戏 按钮后显示 所以在 登录窗口LoginWnd…

热更新杂乱记

热更新主要有一个文件的MD5值的比对过程&#xff0c;期间遇到2个问题&#xff0c;解决起来花费了一点时间 1. png 和 plist 生成zip的时候再生成MD5值会发生变动。 这个问题解决起来有2种方案&#xff1a; &#xff08;1&#xff09;.第一个方案是将 png和plist的文件时间改…

【2024年华为OD机试】 (C卷,100分)- 用户调度问题(JavaScriptJava PythonC/C++)

一、问题描述 问题描述 在通信系统中&#xff0c;有 n 个待串行调度的用户&#xff0c;每个用户可以选择 A、B、C 三种调度策略。不同的策略会消耗不同的系统资源。调度规则如下&#xff1a; 相邻用户不能使用相同的调度策略&#xff1a;例如&#xff0c;如果第 1 个用户选择…

FPGA中场战事

2023年10月3日,英特尔宣布由桑德拉里维拉(Sandra Rivera)担任“分拆”后独立运营的可编程事业部首席执行官。 从数据中心和人工智能(DCAI)部门总经理,转身为执掌该业务的CEO,对她取得像AMD掌门人苏姿丰博士类似的成功,无疑抱以厚望。 十年前,英特尔花费167亿美元真金白银…

从手动到智能:自动化三维激光扫描

三维扫描&#xff0c;是通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维数字化存档、逆向设计、产品开发、直接3D打印制造或辅助加工制造等一系列的应用。 传统的…

电容的一些常用数值

如果是滤高频信号的小电容一般采用100nF 如果是滤低频信号的大电容一般采用10uF(10000nF) 比如这个LDO降压 两个一起用滤波效果会更好 如果想要供电引脚悬空&#xff0c;按理不能悬空&#xff0c;所以应该接大电阻接地&#xff0c;一般采用5.1KΩ 比如这个6Pin USB-TypeC的…

编写子程序

实验内容、程序清单及运行结果 编写子程序&#xff08;课本实验10&#xff09; 1.显示字符串 问题显示字符串是现象工作中经常用到的功能&#xff0c;应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口&#xff0c;使调用者可以决定显示的位置&#xff0…

亚马逊新店铺流量怎么提升?自养号测评新趋势

在竞争激烈的电商市场中&#xff0c;亚马逊新店铺如何在众多竞争者中脱颖而出&#xff0c;提升流量成为一大难题。对于新手卖家来说&#xff0c;掌握正确的流量提升策略至关重要。本文将为您揭秘亚马逊新店铺流量提升的方法&#xff0c;助您快速打开市场&#xff0c;实现业绩增…

FPGA自分频产生的时钟如何使用?

对于频率比较小的时钟&#xff0c;使用clocking wizard IP往往不能产生&#xff0c;此时就需要我们使用代码进行自分频&#xff0c;自分频产生的时钟首先应该经过BUFG处理&#xff0c;然后还需要进行时钟约束&#xff0c;处理之后才能使用。

JQuery基本介绍和使用方法

JQuery基本介绍和使用方法 W3C 标准给我们提供了⼀系列的函数, 让我们可以操作: ⽹⻚内容⽹⻚结构⽹⻚样式 但是原⽣的JavaScript提供的API操作DOM元素时, 代码⽐较繁琐, 冗⻓. 我们可以使⽤JQuery来操作⻚⾯对象. jQuery是⼀个快速、简洁且功能丰富的JavaScript框架, 于20…

Go语言中的值类型和引用类型特点

一、值类型 值类型的数据直接包含值&#xff0c;当它们被赋值给一个新的变量或者作为参数传递给函数时&#xff0c;实际上是创建了原值的一个副本。这意味着对新变量的修改不会影响原始变量的值。 Go中的值类型包括&#xff1a; 基础类型&#xff1a;int&#xff0c;float64…

15-spring整合mybatis方式一

spring整合mybatis 方式一【重要】 步骤: 1.导入相关jar包 junit mybatis mysql数据库 spring相关的 aop织入 mybatis-spring 【new】 junit junit 4.12 mysql mysql-connector-java 8.0.23 org.mybatis mybatis 3.5.2 org.springframework spring-webmvc 5…

豆包MarsCode:小C的类二进制拼图

问题描述 思路分析 1. 类二进制数字定义 从题目中我们可以知道&#xff0c;类二进制数字是仅由 0 和 1 组成的数字。比如&#xff1a;1, 10, 100, 101, 110 等等&#xff0c;这些数字都是合法的类二进制数字。换句话说&#xff0c;类二进制数字可以看作是 “二进制表示法” 对…

中国综合算力指数(2024年)报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p39061 在全球算力因数字化技术发展而竞争加剧&#xff0c;我国积极推进算力发展并将综合算力作为数字经济核心驱动力的背景下&#xff0c;该报告对我国综合算力进行研究。 中国算力大会发布的《中国综合算力指数&#xff08;2024年…

Vue中设置报错页面和“Uncaught runtime errors”弹窗关闭

文章目录 前言操作步骤大纲1.使用Vue自带的报错捕获机制添加报错信息2.在接口报错部分添加相同机制3.把报错信息添加到Vuex中方便全局使用4.添加报错页面备用5.app页面添加if判断替换报错界面 效果备注&#xff1a;vue项目中Uncaught runtime errors:怎样关闭 前言 在开发Vue项…

单调栈详解

文章目录 单调栈详解一、引言二、单调栈的基本原理1、单调栈的定义2、单调栈的维护 三、单调栈的应用场景四、使用示例1、求解下一个更大元素2、计算柱状图中的最大矩形面积 五、总结 单调栈详解 一、引言 单调栈是一种特殊的栈结构&#xff0c;它在栈的基础上增加了单调性约束…

算法题之栈与队列:理论基础与常用操作接口

栈与队列 &#xff08;1&#xff09;理论基础 栈&#xff1a;先进后出的数据结构 队列&#xff1a;先进先出的数据结构 栈提供push 和 pop 等等接口&#xff0c;所有元素必须符合先进后出规则&#xff0c;所以栈不提供走访功能&#xff0c;也不提供迭代器(iterator)。 不像是…