组件注册
组件注册有两种方式:
- 全局注册
可以使用Vue应用实例的.component()
方法,让组件在当前Vue应用中全局可用,.component()
方法可以被链式调用。全局注册的组件可以在此应用的任意组件的模版中使用。import { createApp } from 'vue' import { MyComponent } from './MyComponent.vue'const app = createApp({ }) app.component('MyComponent',MyComponent)
- 局部注册
局部注册的组件需要在它的父组件中显示导入,并且只能在父组件中使用,依赖关系更加明确。<script> import MyComponent from './MyComponent'export default{components:{MyComponent} } </script><template><MyComponent /> </template>s
Props
一个组件需要显示声明它所接受的props。声明props的方式有两种:
- 字符串数组
export default{props:['animal','zoo'],created(){//props 会暴露到 this 上console.log(this.animal);console.log(this.zoo);} }
- 对象的形式
export default{props:{title:string,age:number} }
静态Prop、动态Prop
- 静态Prop传参形式
<child-component title="this is title" />
- 动态Prop传参形式,使用
v-bind
或缩写:
来进行动态绑定<child-component :title="自定义的变量"/>
事件
触发与监听事件
- 触发(子组件):在组件模版表达式中,可以直接使用
$emit
方法触发自定义事件//1. 第一种触发方式 <button @click="$emit('click')">触发click事件</button> //2. 第二种触发方式,函数触发, this.$emit export default{methods:{submit(){this.$emit('click');}} }
- 父组件可以通过
v-on
或@
来监听事件//1. 触发 <child-component @click="alert(1)" /> //2. 事件监听器也支持 .once 修饰符 <child-component @click.once="alert(1)" />
事件参数
可以给触发的事件传入参数,父组件可以处理传入的参数
- 子组件传入参数
<button @click="emit('click',1,2)">传入参数给父组件</button>
- 父组件处理参数
<child-component @click="fun1"/>//处理参数的方法 methods:{fun1:function(var1,var2){console.log(var1);console.log(var2);} }
插槽 Slots
- 父组件传入,插槽内容可以是任意合法的模版内容,不局限于文本,可以传入多个HTML元素,甚至组件
<child-component>传入内容 </child-component>
- 子组件插槽占位
<h1><slot></slot> </h1>
插槽渲染作用域
插槽可以访问到父组件的数据作用域,因为插槽内容本身是在父组件中定义的。插槽无法访问子组件的数据。
插槽默认内容
如果父组件没有提供任何内容,可以为插槽指定默认内容
<button><slot>默认内容</slot>
</button>
具名插槽
- 子组件为插槽指定名称,没有提供
name
的<slot>
会隐式地命名为default<div><slot name="header"></slot><slot name="footer"></slot><slot></slot> </div>
- 父组件指定插槽名称传入内容,
v-slot
简写#
<child-component><template #header>This is header</template><template #footer>This is footer</template><template #default>This is default</template> </child-component>
动态插槽名
可以使用动态的插槽名,传给子组件内容
<child-component><template v-slot:[defineSlotName]></template><template #[defineSlotName]></template>
</child-component>
作用域插槽
某些场景下插槽的内容想要同时使用父组件域内和子组件域内的数据,子组件可以在渲染时将一部份数据提供给插槽
- 默认插槽
//子组件插槽插入数据 <div><slot :name="zqq" :age="18"></slot> </div> //父组件使用 <child-component v-slot="vslot">{{ vsolt.name }} {{ vsolt.age }} </child-component>
- 具名作用域插槽
//子组件插槽传入数据,name是vue特别保留的attribute,不会作为props传递给插槽 <slot name="header" message="hello"> </slot> //父组件使用 <child-component><template #header="data">{{ data s}}</template> </child-component>
依赖注入
一个父组件相当于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级多深,都可以注入由父组件提供给整条链路的依赖。关键字:provide
和inject
。
- provide(提供),为后代组件提供数据
//为后代组件提供数据 export default{privode:{message:'hello'} } //为后代组件提供data()定义的数据属性,以函数形式使用provide export default{data(){return{message:'hello'}},provide:(){return{message:this.message;}} }//在应用层为全部组件提供依赖 import { createApp } from 'vue'const app = createApp({}) // message是注入的名称,hello是值 app.provide('message','hello');
- Inject(注入),子组件注入父组件(隔代父组件也可以)提供的依赖
export default{inject:['message'],data(){return{//注入会在组件自身状态之前被解析,可以通过this访问注入的值localMessage:this.message}} }
注入别名和默认值
export{inject:{// localMessage是自定义的本地别名,后续访问注入的内容,使用this.localMessagelocalMessage:{from:'message',default:'default' //可以指定默认值}}
}
和响应式数据配合使用
为了保证注入方和供给方之间的响应性链接,需要使用computed()函数提供一个计算属性
import default{data(){return{message:'hello'}}provide(){return{message:computed(() => this.message)}}}
}
异步组件
在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件,Vue提供了defineAsyncComponent
方法来实现
const AsyncComp = defineAsynComponet(() => {return new Promise(() =>{//...从服务器获取组件resolve(/*获取到的组件*/);})
})
导入Vue单文件组件
import { defineAsyncComponent } from 'vue'const AsyncComp defineAsyncComponent(() => import('./components/MyComponent.vue'))
最后得到的AsyncComp
是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将受到的props和插槽传给内部组件,所以可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。
异步组件注册
- 全局注册
app.component('MyComponent',defineAsyncComponent(() => import('./components/MyComponent.vue'))
- 局部注册
<script> impoty { defineAsyncComponent } from 'vue'export default{components{MyComponent:defineAsyncComponent(() = import('./components/MyComponent.vue'))} } </script>
加载与错误状态
const AsyncComp = defineAsyncComponent({//加载组件函数loader:() => import(',MyComponent'),//展示加载组件的延迟时间,默认200msdelay:200,//加载失败后展示的组件errorComponent:ErrorComponent,//加载组件超时时间,默认没有超时时间,如果超市,会显示 加载失败展示的组件timeOut: 3000
})