组件:组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。 把项目中的重复使用的UI做成一个独立的组件供项目各个位置使用。 例如:Element、Ant Design等UI,组件。我们也可以自己定义一些组件给自己项目使用。

定义组件

在项目的components目录下创建组件(vue文件)

template标签是必须的,script和style根据需要来

<template>
    <div class="header">
        我是头部
    </div>
</template>
 
<script>
 
</script>
 
<!-- scoped表示下面的样式只在当前组件有效 -->
<style scoped>
    .header {
        height: 50px;
        width: 100%;
        background-color: red;
    }
</style>

使用组件

<template>
  <!-- 第三步:显示组件 -->
  <Header />
</template>
 
<script>
// 第一步:引入组件
import Header from './components/Header.vue'
 
export default {
  data() {
    return {
      
    }
  },
  // 第二步:注入组件
  components:{
    Header
  }
}
</script>
 

组件嵌套

组件Header

<template>
    <div id="header"></div>
</template>
 
<style scoped>
    #header {
        width: 99.5%;
        height: 200px;
        background-color: #e3e3e3;
        border: 5px solid #aeaeae;
        margin-bottom: 20px;
    }
</style>

组件Main

组件Main中嵌套了组件Article

<template>
    <div id="main">
        <Article />
        <Article />
        <Article />
    </div>
</template>
 
<script>
    import Article from './Article.vue'
    export default{
        components:{
            Article
        }
    }
</script>
 
<style scoped>
    #main {
        width: 65%;
        height: 800px;
        background-color: #e3e3e3;
        border: 5px solid #aeaeae;
        float: left;
    }
</style>

组件Article

<template>
    <div id="article"></div>
</template>
 
<style scoped>
    #article {
        width: 85%;
        margin: 20px auto;
        height: 200px;
        background-color: #b9b9b9;
    }
</style>

组件Aside

组件Aside中嵌套了组件Article

<template>
    <div id="Aside">
        <Article />
        <Article />
    </div>
</template>
 
<script>
    import Article from './Article.vue'
    export default{
        components:{
            Article
        }
    }
</script>
 
<style scoped>
    #Aside {
        width: 33%;
        height: 800px;
        background-color: #e3e3e3;
        border: 5px solid #aeaeae;
        float: right;
    }
</style>

App.vue

选项式

<template>
  <Header />
  <Main />
  <Aside />
</template>
 
<script>
  import Header from './components/Header.vue';
  import Main from './components/Main.vue';
  import Aside from './components/Aside.vue';
 
  export default {
    components: {
      Header,
      Main,
      Aside
    }
  }
</script>

组合式

<template>
    <Header/>
    <Main/>
    <Aside />
</template>
 
<script setup>
    import Main from './components/t4/Main.vue';
    import Aside from './components/t4/Aside.vue';
    import Header from './components/t4/Header.vue';
 
 
</script>

全局组件

全局组件可以在页面的任何组件中引用,不需要每个页面都引入一遍

组件

<template>
    <div id="header"></div>
</template>
 
<style scoped>
    #header {
        width: 99.5%;
        height: 200px;
        background-color: #e3e3e3;
        border: 5px solid #aeaeae;
        margin-bottom: 20px;
    }
</style>

main.js

import { createApp } from 'vue'
import App from './App.vue'
 
// 引入组件
import Header from './components/Header.vue'
 
// createApp(App).mount('#app') //原来的的样子
 
const app = createApp(App)
//注册组件
app.component('Header',Header)
 
app.mount('#app')

组件数据传递

父组件传给子组件

父组件

向发送数据的子组件上加上属性,属性名自拟,前面加冒号可以传递data中的动态数据。

选项式

<template>
    <h1>我是父组件</h1>
    <Child msg="你好儿子" :msg2="message" :kc="kc" :user="user"/>
</template>
 
<script>
    import Child from './Child.vue'
    export default{
        data(){
            return {
                message: "儿子这是动态数据",
                kc: ['java','Python','javascript'],
                user: {
                    username: '张三',
                    age: 20
                }
            }
        },
        components: {
            Child
        }
    }
</script>

组合式

<template>
    <h1>我是父组件</h1>
    <Child msg="你好儿子" :msg2="message" :kc="kc" :user="user"/>
</template>
 
<script setup>
    import { ref,reactive } from 'vue';
    import Child from './Child.vue'
   
    let message = ref("儿子这是动态数据");
    let kc = reactive(['java','Python','javascript']);
    let user = reactive({
        username: '张三',
         age: 20
    })
 
</script>

子组件

props属性接受父组件发过来的数据

选项式

<template>
    <h1>我是子组件</h1>
    <h3>子组件接受父亲的数据:{{ msg }}</h3>
    <h3>子组件接受父亲的动态数据:{{ msg2 }}</h3>
    <ul>
        <li v-for="(item,index) in kc" :key="index">{{ item }}</li>
    </ul>
    <p>{{ user.username }}</p>
    <p>{{ user.age }}</p>
</template>
 
<script>
    export default{
        data(){
            return {
 
            }
        },
        props:['msg','msg2','kc','user'],
        mounted(){
            console.log(this.$props.msg)
        }
    }
</script>

组合式

<template>
    <h1>我是子组件</h1>
    <h3>子组件接受父亲的数据:{{ msg }}</h3>
    <h3>子组件接受父亲的动态数据:{{ msg2 }}</h3>
    <ul>
        <li v-for="(item,index) in kc" :key="index">{{ item }}</li>
    </ul>
    <p>{{ user.username }}</p>
    <p>{{ user.age }}</p>
</template>
 
<script setup>
    import { onMounted } from 'vue';
    const props = defineProps(['msg','msg2','kc','user'])
    onMounted(()=>{
        console.log(props.user)
    })
</script>

props中的数据校验

子组件

选项式

<template>
    <h1>我是子组件</h1>
    <p>{{ num }}</p>
    <p>{{ count }}</p>
    <ul>
        <li v-for="(item,index) in kc" :key="index">{{ item }}</li>
    </ul>
</template>
 
<script>
    export default{
        props:{
            // 数据类型校验,String、Number、Array、Object
            num: {
                type: Number,
                //必须传
                required: true
            },
            // 默认值,父组件没有传值可以有默认值
            count: {
                default: 1
            },
            //对象默认值
            kc: {
                default(){
                    return ['空']
                }
            }
        }
    }
</script>

组合式

<template>
    <h1>我是子组件</h1>
    <h3>子组件接受父亲的数据:{{ msg }}</h3>
    <h3>子组件接受父亲的动态数据:{{ msg2 }}</h3>
    <ul>
        <li v-for="(item,index) in kc" :key="index">{{ item }}</li>
    </ul>
    <p>{{ user.username }}</p>
    <p>{{ user.age }}</p>
</template>
 
<script setup>
    import { onMounted } from 'vue';
     // 数据类型校验,String、Number、Array、Object
    const props = defineProps({
        msg: String,
        msg2: String,
        kc: Array,
        user: Object
    })
    onMounted(()=>{
        console.log(props.user)
    })
</script>

子组件传给父子组件

子组件传给父子组件数据,利用自定义事件实现

案例

子组件

选项式

<template>
 
    <h1>我是子组件</h1>
    <button @click="test">点击向父组件传参数</button>
   
</template>
 
<script>
    export default{
        data(){
            return {
 
            }
        },
        emits: ['testEvent'],
        methods:{
            test(){
	            // testEvent为自定事件,后面的为需要传递的数据
                this.$emit('testEvent','你好爸爸')
            }
        }
    }
</script>

组合式

<template>
    <h1>我是子组件</h1>
    <button @click="test">点击向父组件传参数</button>
    <button @click="$emit('testEvent2','你好')">点击向父组件传参数</button>
</template>
 
<script setup>
    const emit = defineEmits(['testEvent','testEvent2']);
    function test(){
        emit('testEvent','你好爸爸')
    }
</script>

父组件

选项式

<template>
 
    <h1>我是父组件</h1>
    <h3>来自子组件的数据:{{ msg }}</h3>
    <Child @testEvent="p_test"/>
    
</template>
 
<script>
    import Child from './Child.vue'
    export default{
        data(){
            return {
                msg: ""
            }
        },
        components: {
            Child
        },
        methods: {
            p_test(data){
                //data 为来自子组件的数据
                this.msg = data
            }
        }
    }
</script>

组合式

<template>
 
    <h1>我是父组件</h1>
    <h3>来自子组件的数据:{{ msg }}</h3>
    <h3>来自子组件的数据:{{ msg2 }}</h3>
    <Child @testEvent="p_test" @testEvent2="p_test2"/>
    
</template>
 
<script setup>
    import { ref } from 'vue';
    import Child from './Child.vue'
 
    let msg = ref('');
    function p_test(data){
        msg.value = data
    }
    let msg2 = ref('');
    function p_test2(data){
        msg2.value = data
    }
</script>
结合v-model

子组件

选项式

<template>
 
    <h1>我是子组件</h1>
    <input type="text" v-model="msg">
   
</template>
 
<script>
    export default{
        data(){
            return {
                msg: ""
            }
        },
        emits: ['msgEvent'],
        // 侦听
        watch: {
            msg(newValue,oldValue){
                this.$emit("msgEvent",newValue)
            }
        }
    }
</script>

组合式1

<template>
 
    <h1>我是子组件</h1>
    <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
   
</template>
 
<script setup>
    const props = defineProps(["modelValue"]);
    const emit = defineEmits(["update:modelValue"]);
</script>

组合式2

<template>
    <h1>我是子组件</h1>
    <input v-model="test">
</template>
 
<script setup>
    const test = defineModel()
</script>

父组件

<template>
 
    <h1>我是父组件</h1>
    <h3>来自子组件的数据:{{ msg }}</h3>
    <Child @msgEvent="p_test"/>
    
</template>
 
<script>
    import Child from './Child.vue'
    export default{
        data(){
            return {
                msg: ""
            }
        },
        components: {
            Child
        },
        methods: {
            p_test(data){
                //data 为来自子组件的数据
                this.msg = data
            }
        }
    }
</script>

组合式1

<template>
    <h1>我是父组件</h1>
    <h3>来自子组件的数据:{{ inputValue }}</h3>
    <Child v-model="inputValue"/>
</template>
 
<script setup>
    import Child from './Child.vue'
    import { ref } from "vue";
    const inputValue = ref();
</script>

组合式2

<template>
    <h1>我是父组件</h1>
    <h3>来自子组件的数据:{{ msg }}</h3>
    <Child v-model="msg"/>
</template>
 
<script setup>
    import Child from './Child.vue'
    import { ref } from "vue";
 
    const msg = ref();
</script>