前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文读懂Vue3组件由浅入深

一文读懂Vue3组件由浅入深

原创
作者头像
QGS
发布2024-01-18 00:13:29
1410
发布2024-01-18 00:13:29
举报
文章被收录于专栏:QGS星球QGS星球

Vue组件

组件的优点:可复用性

组件构成

代码语言:javascript
复制
<template>
</template>
<script>
export default{
}
</script>
<style>
</style>

组件引入

组件的生命周期钩子

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码

创建期:beforeCreate、created

挂载期:beforeMount 、mounted

更新期:beforeUpdate、updated

销毁期:beforeUnmount 、unmountd

代码语言:javascript
复制
<script>
export default{
beforeCreate(){
    console.log("创建之前")
},
created(){
    console.log("创建之后")
},
beforeMount(){
    console.log("挂载之前")
},
mounted(){
    console.log("挂载之后")
},
beforeUpdate(){
    console.log("更新之前")
},
updated(){
    console.log("更新之后")
},
beforeUnmount(){
    console.log("销毁之前")
},
unmountd(){
    console.log("销毁之后")
}
}
</script>

组件生命周期图示
组件生命周期图示

组件嵌套关系

组件允许将ui划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际项目中,组件是层层嵌套的树形结构,每个组件内封装自定义内容与逻辑。

取消main.css依赖

Article.vue

代码语言:javascript
复制
<template>
    <H3>Article</H3>
</template>
<style scoped>
h3{
    width: 80%;
    margin: 0 auto;
    text-align: center;
    line-height: 100px;
    box-sizing: border-box;
    margin-top: 25px;
    background: #bdbaba;    
}
</style>

Item.vue

代码语言:javascript
复制
<template>
    <H3>Item</H3>
</template>
<style scoped>
h3{
    width: 80%;
    margin: 0 auto;
    text-align: center;
    line-height: 100px;
    box-sizing: border-box;
    margin-top: 25px;
    background: #bdbaba;     
}
</style>

Hrader.vue

代码语言:javascript
复制
<template>
    <H3>Header</H3>
</template>
<style scoped>
h3{
    width: 100%;
    height: 100px;
    border: 5px solid #999;
    text-align: center;
    line-height: 100px;
    box-sizing: border-box;
}
</style>

Main.vue

代码语言:javascript
复制
<template>
    <div class="main">
        <H3>Main</H3>    
        <Article/>
        <Article/>
        <Article/>
    </div>
</template>
<script>
import Article from "./article.vue"
export default{
    components:{
        Article
    }
}
</script>
<style scoped>
.main{
    float: right;
    width: 85%;
    height: 500px;
    border: 5px solid #999;
    box-sizing: border-box;
    text-align: center;
}
</style>

Aside.vue

代码语言:javascript
复制
<template>
    <div class="aside">
        <H3>Aside</H3>
        <Item/>  
        <Item/>
        <Item/> 
    </div>
</template>
<script>
import Item from './Item.vue';
export default{
    components:{
        Item
    }
}
</script>
<style scoped>
.aside{
    float: left;
    width: 14%;
    height: 500px;
    border: 5px solid #999;
    box-sizing: border-box;
    text-align: center;
}
</style>

效果

组件注册

局部注册(建议使用)

在一个组件中进行注册

全局注册

在main.js中全局注册

全局注册很方便,但是在全局注册中,没有被使用的组件无法在生成打包的时候被自动移除(“tree-shaking”),依然出现在打包后的js文件中。

在项目嵌套较多的时候,全局注册的依赖关系不明确,可能影响应用长期维护性。

组件数据传递props

组件之间是可以传递数据,而传递数据的解决方案是props,注:props传递数据只能父级传递子级。

组件传递的数据类型:数字、对象、数字等。任何类型的值都可以作为props的值传递

组件间传递数据应用场景: 父传子

Parent.vue

代码语言:javascript
复制
<template>
    <h3>Parent</h3>
    <input v-model="msg">
    <Child :title="msg" test="数据"/>
</template>
<script>
import Child from './Child.vue';
export default{
    data(){
        return{
            msg:""
        }
    },
    components:{
        Child
    }
}
</script>


Child.vue
<template>
    <h3>Child</h3>
    <p> {{ title }} </p>
    <p>{{ test }}</p>
</template>
<script>
export default{
    data(){
        return{
        }
    },
    //接收数据
    props:["title","test"]
}
</script>

传递效果

传递数组,对象

Parent.vue

代码语言:javascript
复制
<template>
    <h3>Parent</h3>
    <input v-model="msg">
    <Child :title="msg" test="数据" :names="names" :user="user" :number1="number1"/>
</template>
<script>
import Child from './Child.vue';
export default{
    data(){
        return{
            msg:"",
            names:["张三","李四","王五"],
            user:{
                name:"张三",
                age:20
            },
            number1:123
        }
    },
    components:{
        Child
    }
}
</script>

Child.vue

代码语言:javascript
复制
<template>
    <h3>Child</h3>
    <p> {{ title }} </p>
    <p>{{ test }}</p>
    <p v-for="(name,index) of names" :key="index">{{ index }} : {{ name }}</p>
    <p>{{ user.name }} {{ user.age }}</p>
</template>
<script>
export default{
    data(){
        return{
        }
    },
    //接收数据
    props:["title","test","names","user"]
}
</script>

传递对象

类型验证
代码语言:javascript
复制
<template>
    <h3>Child</h3>
    <p> {{ title }} </p>
    <p>{{ test }}</p>
    <p v-for="(name,index) of names" :key="index">{{ index }} : {{ name }}</p>
    <p>{{ user.name }} {{ user.age }}</p>
</template>
<script>
export default{
    data(){
        return{
        }
    },
    //接收数据
    props:{
        title:{
            type:[String,Number,Array,Object]
        },
        names:{
            type:Array
        },
        user:{
            type:Object,
            //必选项
            required:true
        },
        test:{
            type:String
        },
        number:{
            type:Number,
            default:0
        }
    }
}
</script>

Props实现子传父

组件数据传递$emit

组件模板表达式中,可以使用$emit方法触发自定义事件

组件间传递数据应用场景:子传父

Child.vue

代码语言:javascript
复制
<template>
    Child
    <button @click="clickEventHandle">向父组件发送数据</button>
</template>
<script>
export default{
    data(){
        return{
            msg:"传递数据"
        }
    },
    methods:{
        clickEventHandle(){
            this.$emit("eventDemo",this.msg)
        }
}
}
</script>

Parent2.vue

代码语言:javascript
复制
<template>
<Child @eventDemo="getHandle"/>
</template>
<script>
import Child from "./Child.vue"
export default {
    components:{
        Child
    },
    methods:{
        getHandle(data){
            console.log(data)
        }
    }
}
</script>

组件+v-model

查询:<input type="text" v-model="search">

代码语言:javascript
复制
watch:{
        search(newValue,oldValue){
            this.$emit("searchEvent",newValue)
        }
    },

透传

透传attribute指的是传递给一个组件,没有被该组件声明为props或emits的arrtibute或者v-on事件监听器。最常见的例子就是class、id、style。

一个组件以单个元素为根做渲染时,透传的attribute会自动被添加到根元素上

App.vue

Attr.vue

代码语言:javascript
复制
<template>
    <h2>透传属性测试</h2>
</template>
<style>
.colorDemo{
    color: aqua;
}
</style>

效果

禁用透传attribute

代码语言:javascript
复制
export default{
    inheritAttrs:false
}

Slots插槽

插槽 slot 通常用于两个父子组件之间,最常见的应用就是使用一些 UI 组件库中的弹窗组件时,弹窗组件的内容是可以自定义,这就是使用了插槽的原理。

SlotsDemo.vue

代码语言:javascript
复制
<template>
    <slots></slots>
</template>
<script>
export default{
}
</script>

<slot>元素是一个插槽出口(slot outlet),表示父类提供的插槽内容渲染的位置

插槽的作用域

插槽内容可以访问父组件的数据作用域,插槽的内容本身就是在父组件模板中定义

默认值

在父组件没有传递数值的情况下显示

代码语言:javascript
复制
<template>
    <slots>默认值</slots>
</template>

具名插槽

给插槽提供名字

App.vue

代码语言:javascript
复制
<SlotsDemo>
    <template v-slot:h1>
      <h2>标题</h2>
    </template>
    <template v-slot:h2>
      <p>{{msg}}</p>
    </template>
  </SlotsDemo>

SlotsDemo.vue

代码语言:javascript
复制
<template>
    <slot name="h1">默认值</slot>
    <slot name="h2">默认值</slot>
</template>

v-slot简写#

代码语言:javascript
复制
<template #h1>
      <h2>标题</h2>
    </template>
    <template #h2>
      <p>{{msg}}</p>
    </template>

插槽数据传递

插槽的内容可能同时获取给父组件作用域和子组件作用域的数据,可以类似props,在插槽的出库是传递arrtibutes

将子组件的数据传递给父组件

子组件

代码语言:javascript
复制
<template>
    <slot  :childmsg="childmsg"></slot>
</template>
<script>
export default{
        data(){
            return{
                childmsg:"child"
            }
        }
}
</script>

父组件

代码语言:javascript
复制
 <SlotsDemo v-slot="slotProps">
{{ slotProps.childmsg }}+{{ msg }}
  </SlotsDemo>

具名+插槽数据传递

子组件

代码语言:javascript
复制
<template>
    <slot name="h1">默认值</slot>
    <slot name="h2" :childmsg="childmsg"></slot>
</template>

父组件

代码语言:javascript
复制
<SlotsDemo >
    <template #h1>
      <h2>标题</h2>
    </template>
    <template #h2="slotProps">
      <p> {{ slotProps.childmsg }}+ {{msg}}</p>
    </template>
  </SlotsDemo>

axios网络请求渲染数据

Axios,是一个基于promise 的网络请求库,作用于node.js和浏览器中,它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生node.js http模块, 而在客户端 (浏览端) 则使用XMLHttpRequest。

项目下安装axios依赖

yarn add axios

npm install --save axios

组件引用

import axios from 'axios'

CompnentLife.vue

代码语言:javascript
复制
<template>
    <!--
     创建期:beforeCreate、created
     挂载期:beforeMount 、mounted
     更新期:beforeUpdate、updated
     销毁期:beforeUnmount 、unmountd
     -->
    <p ref="life">组件生命周期</p>
     <p v-for="(info,index) in dataInfo" :id="index">{{info}}</p>
</template>

<script>
import axios from 'axios'
     export default{
          data(){
               return{
                       dataInfo: []
        }

          },
          mounted(){
               console.log(this.$refs.life);
               axios({
                       method:"get",
                       url:"http://localhost:8007/OS/getOSInfo",
               // changeOrigin:true  允许跨域
            }).then(res=>{
                       console.log(res.data)
                       this.dataInfo=res.data;
            })
          }
     }
</script>

效果

vue全局绑定axios
代码语言:javascript
复制
// import './assets/main.css'

import { createApp } from 'vue'
             import App from './App.vue'
//引入
             import Item from './components/Item.vue'
             import axios from 'axios'

     axios.defaults.baseURL = "http://localhost:8007"
             const app =createApp(App);
//全局挂载axios
     app.config.globalProperties.$axios=axios

//注入 (展示名,注入名)
app.component("Item",Item)
             app.mount('#app');

CompnentLife.vue

代码语言:javascript
复制
<script>
import axios from 'axios'
export default{
    data(){
        return{
            dataInfo: []
        }
    },
        mounted(){
            console.log(this.$refs.life);
            axios({
                method:"get",
                url:"/OS/getOSInfo",
                // changeOrigin:true  允许跨域
            }).then(res=>{
                console.log(res.data)
                this.dataInfo=res.data;
            })
        }
}
</script>

可能遇到问题

Access to XMLHttpRequest at 'http://localhost:8007/OS/getOSInfo' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决办法1

后端加上@CrossOrigin 注解//表示都允许跨域访问

@CrossOrigin //表示都允许跨域访问

动态组件

代码语言:javascript
复制
<template>
<component :is="tabComponent"></component>
<button @click="changeComponent">切换组件</button>
</template>
<script >
import ComponentsA from "./components/ComponentsA.vue"
import ComponentsB from "./components/ComponentsB.vue"
export default{
  data(){
    return{
      tabComponent:"ComponentsA"
    }
  },
  methods:{
    changeComponent(){
      // 三元运算符
      this.tabComponent= this.tabComponent =="ComponentsA"? "ComponentsB" : "ComponentsA"
    }
  }

当使用<component :is="tabComponent"></component>在多个组件间切换时,被切换掉的组件会被卸载。可以通过<keep-alive>组件前置被切换掉的组件依然保持“存活状态”

代码语言:javascript
复制
<KeepAlive>
<component :is="tabComponent"></component>
</KeepAlive>

异步组件

Vue提供了defineAsyncComponent实现异步组件功能。

import ComponentsA from "./components/ComponentsA.vue"

//异步加载组件

代码语言:javascript
复制
const ComponentsB =defineAsyncComponent(()=>
  import("./components/ComponentsB.vue")
).catch(function(error){
  console.log(error);
})

异步组件的优势

1.减少应用程序的初始加载时间

异步组件只有在需要使用该组件时才会进行加载,可以减少应用程序的初始加载时间,提高用户体验。

2.提高应用程序的性能

异步组件可以将组件的加载和渲染分开进行,可以提高应用程序的性能,避免不必要的渲染。

3.优化代码的可维护性

异步组件可以将组件按需加载,可以优化代码的可维护性,减少代码的复杂度。

异步组件的注意事项

1.异步组件的加载时间

异步组件是按需加载的,因此在使用异步组件时,需要考虑组件的加载时间。如果组件的加载时间过长,会对应用程序的性能和用户体验产生影响。

2.异步组件的错误处理

在使用异步组件时,需要对组件加载过程进行错误处理,避免出现错误导致应用程序无法运行。可以通过 catch() 方法来捕获异步加载组件时的错误。

依赖注入-透传

prop逐级透传可以用provide和inject解决这一问题。一个父组件相对于其所有的子组件,会作为依赖提供者。任何子组件树,无论层级多深,都可以注入由父组件提供给整条链路的依赖

App.vue

代码语言:javascript
复制
<template>
        <Parent/>
        </template>

        <script >
import Parent from "./components/Parent.vue"
        export default{

        provide:{
        messages:"app组件"
        },
        }
</script>

Parent.vue

代码语言:javascript
复制
<template>
<h3>Parent</h3>
<Child></Child>
</template>
Child.vue
<template>
    Child
<p>{{ messages }}</p>
</template>

<script>
export default{
        inject:["messages"],
        }
</script>

动态穿透

代码语言:javascript
复制
<template>
        <Parent/>
        </template>

        <script >
import Parent from "./components/Parent.vue"
provide(){
        return{
        messages: this.messages
        }

        },
        data(){
        return{
        messages:"app组件"
        }
        },
</script>

全局数据

app.provide("golabData","全局数据")

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件的生命周期钩子
  • 组件嵌套关系
  • 组件注册
  • 组件数据传递props
    • 传递数组,对象
      • 类型验证
        • Props实现子传父
        • 组件数据传递$emit
        • 组件+v-model
        • 透传
        • Slots插槽
          • 插槽的作用域
            • 默认值
              • 具名插槽
                • 插槽数据传递
                  • 具名+插槽数据传递
                    • axios网络请求渲染数据
                      • 组件引用
                      • vue全局绑定axios
                      • 可能遇到问题
                  • 动态组件
                  • 异步组件
                  • 依赖注入-透传
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档