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>
组件之间传递数据:
父传子:使用
props
在Vue.js中,
props
是父组件向子组件传递数据的一种方式。父组件可以通过在子组件标签中定义属性来传递数据,这些属性在子组件内部可以通过props
对象访问。这种方式是单向数据流,确保了数据的流向是从父组件到子组件,有助于避免组件之间的耦合。
子传父:使用自定义事件 (
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>
代码解释
父组件(ParentComponent.vue):
在模板中,使用
<Child :onFnEvent="fn" />
标签引入子组件,并使用:onFnEvent="fn"
来监听子组件触发的事件。当子组件触发事件时,父组件的
fn
方法会被调用,并接收子组件传递的数据。
message
数据属性用于存储从子组件接收到的数据,并在模板中显示。子组件(Child.vue):
在模板中,调用
onFnEvent
方法并传递数据'测试数据'
。定义一个名为
onFnEvent
的prop
,类型为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>
代码解释
父组件(ComponentA.vue):
在模板中,使用
<ComponentB>
标签引入子组件,并为header
和main
插槽传递内容。使用
<template v-slot:header>
和<template v-slot:main>
来指定内容应该填充到哪个插槽中。
ComponentB
组件被注册在父组件的components
对象中,使其可以在父组件的模板中使用。子组件(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>
代码解释
父组件(ComponentA.vue):
在模板中,使用
<componentB>
标签引入子组件,并为slotProps
插槽传递内容。使用
<template v-slot="slotProps">
来指定内容应该填充到哪个插槽中,并从子组件接收数据。
message
数据属性用于存储要传递给子组件的内容。
ComponentB
组件被注册在父组件的components
对象中,使其可以在父组件的模板中使用。子组件(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.name
是undefined
。
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>
异步组件:
使用
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或者字体图标等.
相关文章:

Vue基础(2)
19、组件之间传递数据 组件与组件之间不是完全独立的,而是有交集的,那就是组件与组 件之间是可以传递数据的 传递数据的解决方案就是 props ComponentA.vue <template><!-- 使用ComponentB组件,并传递title属性 --><h3>…...

(长期更新)《零基础入门 ArcGIS(ArcScene) 》实验七----城市三维建模与分析(超超超详细!!!)
城市三维建模与分析 三维城市模型已经成为一种非常普遍的地理空间数据资源,成为城市的必需品,对城市能化管理至关重要。语义信息丰富的三维城市模型可以有效实现不同领域数据与IS相信息的高层次集成及互操作,从而在城市规划、环境模拟、应急响应和辅助决策等众多领域公挥作用、…...

war包 | Docker部署flowable-ui
文章目录 引言I war包部署flowable-ui下载war包配置Tomcat访问 flowable-uiII Docker启动flowable-ui并修改配置Docker启动flowable-ui修改配置访问Flowable UI界面。III 知识扩展加速源docker run -i -t -d 参数引言 Flowable 支持 BPMN 2.0 行业标准,同时提供了一些 Flowab…...
Java数据结构方面的面试试题以及答案解析
Java数据结构是在计算机中存储和组织数据的方式,用于高效地处理和管理数据。 以下是一些常见的Java数据结构: 数组(Array):一种线性数据结构,允许通过索引快速访问元素。它存储固定大小的相同类型的元素集…...

Qt 5.14.2 学习记录 —— 십구 事件
文章目录 1、事件的概念2、处理事件3、鼠标事件1、鼠标单击和双击2、鼠标移动3、鼠标滚轮滚动 4、键盘事件5、定时器事件6、窗口移动和大小改变事件 1、事件的概念 用户进行操作时会产生事件,事件可以关联处理函数。Qt封装了操作系统的事件机制,然后进一…...

国产编辑器EverEdit - 命令窗口应用详解
1 命令窗口应用详解 1.1 应用场景 有时需要在EverEdit中执行一些命令行工具,甚至想把当前文档做为参数,传递给命令进行一些文本分析,比如:一些常用的文本处理工具,gawk.exe等。 1.2 使用方法 命令窗口的使用在官方手…...

iOS开发设计模式篇第二篇MVVM设计模式
目录 一、什么是MVVM 二、MVVM 的主要特点 三、MVVM 的架构图 四、MVVM 与其他模式的对比 五、如何在iOS中实现MVVM 1.Model 2.ViewModel 3.View (ViewController) 4.双向绑定 5.文中完整的代码地址 六、MVVM 的优缺点 1.优点 2.缺点 七、MVVM 的应用场景 八、结…...

【深度学习】3.损失函数的作用
损失函数的作用 假设把猫这张图片分成四个像素点,分别为:56、231、24、2(实际应该是三维的,因为还有颜色通道的维度,这里简化成二维)。 像素点拿到以后,进行三分类,粉红色为第一组W…...

深入MapReduce——计算模型设计
引入 通过引入篇,我们可以总结,MapReduce针对海量数据计算核心痛点的解法如下: 统一编程模型,降低用户使用门槛分而治之,利用了并行处理提高计算效率移动计算,减少硬件瓶颈的限制 优秀的设计,…...

小黑日常积累:学习了CROSS APPLY字段,将sqlserver中字段通过分隔符拆分并统计
问题 字段中的元素是通过分隔符进行拼接的,我需要统计元素的个数,例如: 代码 样例表创建 -- 创建样例表 create table #Tmp_Table (ID int IDENTITY (1,1) not null,Strs nvarchar(50),primary key (ID) ); insert into #Tmp_Table (Strs) VALUES…...
WebSocket知识点笔记(一)
WebSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。它使得客户端和服务端之间的消息传递更加高效,允许服务器主动向客户端推送数据。 一.WebSocket全双工通信 WebSocket提供了真正的双向通信,客户端和服务端可以同时发送和接收消息 …...

安宝特方案 | AR在供应链管理中的应用:提升效率与透明度
随着全球化的不断深入和市场需求的快速变化,企业对供应链管理的要求也日益提高。如何在复杂的供应链环境中提升效率、降低成本,并确保信息的透明度,成为了各大行业亟待解决的问题。而增强现实(AR)技术,特别…...
基于Springboot + vue实现的美发门店管理系统
💖学习知识需费心, 📕整理归纳更费神。 🎉源码免费人人喜, 🔥码农福利等你领! 💖常来我家多看看, 📕网址:扣棣编程, 🎉感谢支持常陪伴, 🔥点赞关注别忘记! 💖山高路远坑又深, 📕大军纵横任驰奔, 🎉谁敢横刀立马行? 🔥唯有点赞+关注成! �…...
springboot中配置logback-spring.xml
一、在src/main/resources目录下,也就是在classpath路径下创建logback-spring.xml 注:springboot框架自动配置,如果更换名称,可在配置文件指定该文件即可 <?xml version"1.0" encoding"UTF-8"?> <…...

从63 秒到 0.482 秒:深入剖析 MySQL 分页查询优化
在日常开发中,数据库查询性能问题就像潜伏的“地雷”,总在高并发或数据量庞大的场景下引爆。尤其是当你运行一条简单的分页查询时,结果却让用户苦苦等待,甚至拖垮了系统。这种情况你是否遇到过? 你可能会想࿱…...
细说机器学习算法之过拟合与欠拟合
系列文章目录 第一章:Pyhton机器学习算法之KNN 第二章:Pyhton机器学习算法之K—Means 第三章:Pyhton机器学习算法之随机森林 第四章:Pyhton机器学习算法之线性回归 第五章:Pyhton机器学习算法之有监督学习与无监督…...

C/C++ 虚函数
虚函数的定义 虚函数是指在基类内部声明的成员函数前面添加关键字 virtual 指明的函数虚函数存在的意义是为了实现多态,让派生类能够重写(override)其基类的成员函数派生类重写基类的虚函数时,可以添加 virtual 关键字,但不是必须这么做虚函…...
【3GPP】【5G】注销流程(Deregistration procedures)
1. 欢迎大家订阅和关注,精讲3GPP通信协议(2G/3G/4G/5G/IMS)知识点,专栏会持续更新中.....敬请期待! 目录 3.1.2 Deregistration procedures 3.1.2.1 UE-initiated Deregistration 3.1.2.2 Network-initiated Deregistration 3.1.2 Deregistration procedures 注销流程…...
【小游戏篇】三子棋游戏
硬控我一上午,小编还是太菜了,大家可以自行升级电脑难度,也可以升级游戏到五子棋 1.game.h #pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 3 #define COL 3//初始化棋盘 void InitBoa…...
7-Zip Mark-of-the-Web绕过漏洞复现(CVE-2025-0411)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...