2.组件基础
2-1父传子props
父传子:水往低处流(单向绑定的原则),子不能修改父传过来的属性,它是只读的,但是可以使用监听和计算属性进行修改
父组件
<template>
<div>
<navbar mytitle="电影" isShow="false"></navbar>
<navbar mytitle="影院"></navbar>
//动态绑定状态
<navbar :mytitle="parentTitle"></navbar>
</div>
</template>
<script>
import Navbar from './Navbar.vue'
export default {
data() {
return {
//状态
parentTitle: "父组件定义的一个状态",
}
},
components: {
Navbar
}
}
</script>
子组件
<template>
<div>
//显示内容
<p>{{ mytitle }}</p>
<button @click="handler()" v-if="isShow">按钮</button>
</div>
</template>
<script>
export default {
// props: ["mytitle","left","right"],
//通过props接受父组件传过来的内容
props:{
mytitle: String,
isShow:{
type:Boolean,
default:true,
// required:true
}
},
methods: {
handler() {
// 无法直接访问状态和修改状态
console.log(this.parentTitle)
}
},
}
</script>
2-2属性验证&默认属性
export default {
props: {
// 基础类型检查
//(给出 `null` 和 `undefined` 值则会跳过任何类型检查)
propA: Number,
// 多种可能的类型
propB: [String, Number],
// 必传,且为 String 类型
propC: {
type: String,
required: true
},
// Number 类型的默认值
propD: {
type: Number,
default: 100
},
// 对象类型的默认值
propE: {
type: Object,
// 对象或者数组应当用工厂函数返回。
// 工厂函数会收到组件所接收的原始 props
// 作为参数
default(rawProps) {
return { message: 'hello' }
}
},
// 自定义类型校验函数
propF: {
validator(value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
}
}
}
2-3子传父:$emit
如果 在vue中要用sass,需要安装这个模块,npm i sass
在子页面通过$emit进行传值,在父页面通过event事件进行获取值
子组件
<template>
<div>
//,在父页面通过event事件进行获取值,
//不要写小括号,会有一个event事件
<Child @event="handleEvent"></Child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data() {
return {
isShow: true
}
},
components: {
Child
},
methods: {
//,在父页面通过event事件进行获取值
handleEvent(event) {
console.log("父组件",event);
}
},
}
</script>
子组件
<template>
<div>
<button @click="send()">子传父</button>
</div>
</template>
<script>
export default {
data() {
return {
childTitle:"子组件的状态"
}
},
methods: {
send() {
进行传值给父组件 event必须和父页面的一致 this.$emit("event",this.childTitle)
}
},
}
</script>
2-4$refs-父组件的强权
- ref如果绑定在dom节点上,拿到的就是 原生dom节点
- ref如果绑定在组件上,拿到的就是 组件对象,可以实现通信功能
父组件
<template>
<div>
$ref
<filed label="用户名" type="text" ref="username"></filed>
<filed label="密码" type="password" ref="password"></filed>
<button @click="login">登录</button>
<button @click="rest" >重置</button>
</div>
</template>
<script>
import filed from './filed-父子通信.vue'
export default {
components: {
filed
},
methods: {
login() {
//通过$refs获取子组件的值
console.log(this.$refs.username.value,this.$refs.password.value);
},
rest() {
this.$refs.username.value="",
this.$refs.password.value=""
}
},
}
</script>
子组件
<template>
<div>
<label for="">{{ label}}</label>
<input :type="type" v-model="value">
</div>
</template>
<script>
export default {
props: ["label", "type"],
data() {
return {
value:""
}
},
}
</script>
2-5 KaTeX parse error: Expected 'EOF', got '&' at position 7: parent&̲root - 子组件的无法无天
<template>
<div>
parent
<Child></Child>
<div v-show="isShow">
sidebar
</div>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
data() {
return {
parentTitle: "父组件11111",
isShow: true
}
},
}
</script>
子组件
<template>
<div>
Child
<button @click="handleClick">$parent</button>
</div>
</template>
<script>
export default {
methods: {
handleClick() {
//----------------子组件无法无天-----------------
//在子组件中通过`$parent`访问父组件,通过`$root`访问根组件
console.log(this.$parent.parentTitle,this.$root);
this.$parent.isShow=!this.$parent.isShow;
}
},
}
</script>
2-6.跨级通信provide和inject
provide
和 inject
是 Vue.js 中用于跨组件通信的一对高级特性。它们允许祖先组件(提供者)向所有后代组件(使用者)传递数据,而不需要通过 props 或事件的方式。
provide ,inject 搭配组合式api使用,具备响应性
provide ,inject 搭配选项式使用, 没有响应性, 把app组件实例
父组件
<!--
provide ,inject 搭配组合式api使用,具备响应性
provide ,inject 搭配选项式使用, 没有响应性, 把app组件实例
-->
<template>
<div>
<navbar></navbar>
<tabber></tabber>
</div>
</template>
<script>
import navbar from './Navbar.vue'
import tabber from './Tabber.vue'
export default {
components: {
navbar,
tabber
},
// 是一个函数
provide() {
return {
app:this
}
},
data() {
return {
title:"首页"
}
},
}
</script>
navbar
<template>
<div style="text-align: center;">
{{ app.title}}
</div>
</template>
<script>
export default {
inject: ['app'],
}
</script>
tabber
<template>
<ul>
<li v-for="(item, index) in list" :key="index" @click="handlerClick(item.name)">
{{ item.name }}
</li>
</ul>
</template>
<script>
export default {
inject:["app"],
data() {
return {
list: [
{ name: "首页" },
{ name: "分类" },
{ name: "购物车" },
{ name: "我的" }
]
}
},
methods: {
handlerClick(val) {
this.app.title=val
}
},
}
</script>
<style scoped>
ul{
list-style: none;
display: flex;
position: fixed;
bottom: 0;
width: 100%;
}
li{
flex: 1;
text-align: center;
height: 60px;
line-height: 60px;
}
</style>
2-7动态组件 - 墙头草
在切换时创建新的组件实例通常是有意义的,但在这个例子中,我们的确想要组件能在被“切走”的时候保留它们的状态。要解决这个问题,我们可以用 `` 内置组件将这些动态组件包装起来:
<!-- 动态组件方式
它允许你根据当前组件的状态或其他条件,动态地选择渲染不同的组件
include="Home":这句话的意思,就是Home这个页面,在里面定义了一个名字为Home的,改页面的将会有缓存,没有加的则没有
include,可以包含多个
-->
<keep-alive include="List">
<component :is="obj[title]"></component>
</keep-alive>
<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>
<!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>
<!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>
2-8异步组件(按需加载)
在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent
方法来实现此功能:
//----------------异步组件(按需加载)提高性能-----------------
import { defineAsyncComponent } from 'vue'
components: {
navbar,
tabber,
Center,
// 这样定义以后,这两个页面,在一开始不会加载,直到使用了之后才会有缓存
// **加载与错误提示**
Home: defineAsyncComponent( () => import('./components/Home.vue')),
List: defineAsyncComponent({
// // 加载组件
loader: () => import('./components/List.vue'),
// 加载异步组件时使用的组件
loadingComponent: LoadingComponent,
// 展示加载组件前的延迟时间,默认为 200ms
delay: 0,
// 加载失败后展示的组件
errorComponent: ErrorComponent,
// 如果提供了一个 timeout 时间限制,并超时了
// 也会显示这里配置的报错组件,默认值是:Infinity
timeout: 3000
}),
},