1.组件的使用
当创建出Vue项目时,我们就已经有了一组件HelloWorld
,我这里简化一下
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
在App.Vue中的使用
<template>
<img alt="Vue logo" src="./assets/logo.png">
<!-- 使用组件 -->
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
//引入组件
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
//组件的注册
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
使用的几个关键点就是import
,以及注册
-
父子组件
- App.vue对于HelloWorld组件来说就是父组件,自己就是子组件
-
全局注册和局部注册
-
组件在当前Vue应用全局可用
-
import { createApp } from 'vue' import App from './App.vue' import HelloWorld from "@/components/HelloWorld"; App.component('HelloWorld', HelloWorld) createApp(App).mount('#app')
-
-
局部注册,只能在父组件中使用
- 参考上面
-
2.组件之间的传参
父组件传子组件
子组件需要显式声明需要传入的props
举例
<template>
<div>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
//这里声明
props: {
msg: String
}
}
</script>
然后父组件就可以通过msg="Welcome to Your Vue.js App"
传参,或者可以传动态的:msg=message
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld :msg="message"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
data(){
return{
message:"Hello World!"
}
},
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
-
传不同类型的数据
-
Boolean
-
<!-- 仅写上 prop 但不传值,会隐式转换为 `true` --> <BlogPost is-published /> <!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind --> <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 --> <BlogPost :is-published="false" /> <!-- 根据一个变量的值动态传入 --> <BlogPost :is-published="post.isPublished" />
-
-
Array
-
<!-- 虽然这个数组是个常量,我们还是需要使用 v-bind --> <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 --> <BlogPost :comment-ids="[234, 266, 273]" /> <!-- 根据一个变量的值动态传入 --> <BlogPost :comment-ids="post.commentIds" />
-
-
Object
-
<!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind --> <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 --> <BlogPost :author="{ name: 'Veronica', company: 'Veridian Dynamics' }" /> <!-- 根据一个变量的值动态传入 --> <BlogPost :author="post.author" />
-
-
-
对于父组件传来的值,子组件可以进行校验
-
Vue 组件可以更细致地声明对传入的 props 的校验要求。比如我们上面已经看到过的类型声明,如果传入的值不满足类型要求,Vue 会在浏览器控制台中抛出警告来提醒使用者。这在开发给其他开发者使用的组件时非常有用。
-
下面是一些参数类型校验实例
-
props: { msg: { type: String, default: 'Hello', required:true }, book:{ type:Object, default(){ return{ book:{ id:1, name:"新华字典" } } }, required: false }, list:{ type:Array, default() { return undefined; } } } }
-
-
子组件传父组件
子组件有时候也需要向父组件传参,这时候我们可以通过事件监听达到目的
举例子
<template>
<div>
<p>{{msg}}</p>
//设置提交的按钮
<button @click="sendParent">提交数据给父组件</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return{
message:'HelloWorld'
}
},
props: {
msg: {
type: String,
default: 'Hello',
required:true
},
},
methods:{
//使用this.$emit来进行数据传参
sendParent(){
//this.$emit('事件的名称','发送的事件参数')
this.$emit('inject',this.message);
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
父组件通过监听事件的发生来获取数据
<template>
<img alt="Vue logo" src="./assets/logo.png">
<!--拿到子组件的数据,通过自定义的事件-->
<!--2.在父组件,通过v-on监听子组件中自定义的事件-->
<HelloWorld :msg="message" @inject="getChildMsg"/>
<p>{{Hello}}</p>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
data(){
return{
message:"Hello World!",
Hello:'',
}
},
methods:{
//这里对获取的数据进行处理
getChildMsg:function (value){
console.log(value)
this.Hello = value;
}
},
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
3.插槽的使用
这是组件的一种使用,先来定义一个组件
<template>
<div>
<h2>我是显示的内容</h2>
<div>
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Content",
}
</script>
<style scoped>
</style>
这里的<slot></slot>
是插槽的出口,也就是我们需要填的坑,再来看看在父组件中怎么填
<Content><button>按钮</button></Content>
<Content><input placeholder="nihao"></Content>
<!--如果有多个值,将会一起作为替换元素-->
<Content>><button>按钮</button><input placeholder="nihao"></Content>
然后有一个组件中有多个插槽的这种情况,我们的解决方案是具名插槽,简单来说,就是加个名字
<template>
<div>
<h2>我是显示的内容</h2>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Content",
}
</script>
<style scoped>
</style>
父组件中的使用
<Content>
<template v-slot:header>
<h2>我是标题</h2>
</template>
<template v-slot:default>
<div>我是内容</div>
</template>
<template v-slot:footer>
<div>末尾</div>
</template>
</Content>
还有缩写形式
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template>
节点都被隐式地视为默认插槽的内容。所以上面也可以写成:
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<!-- 隐式的默认插槽 -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
不过要注意的是:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
在父组件中进行的数据操作,影响不到子组件,也就是作用域不同。