• VUE 组件


    一、什么是组件:

    • 在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例

    • 在Vue中,组件是可复用的 Vue 实例,且带有一个名字。

    • 组件是构成页面中独立结构单元,组件主要以页面结构形式存在,不同组件也具有基本交互功能。

    • 如下图所示,每个图书表项就是一个Vue组件:
      在这里插入图片描述

    二、组件树概念:

    通常一个页面会以一棵嵌套的组件树的形式来组织。这个思想很重要。
    在这里插入图片描述
    例如:上图左侧是一个页面,右侧是对应的组件树。当前的页面是一个Vue实例(上图组件树的第一层)。页面中有三个组件:页头、侧边栏、内容区(上图组件树的第二层),这三个组件构成了当前页面。其中侧边栏又由两个小侧边栏组成,内容区由三个小内容框组成(上图组件树第三层)。

    三、组件的创建方式:

    使用组件前首先需要创建组件。

    备注:这里我们留个印象,下面的创建方式都是以局部组件为例,我主要想讲的是使用template模板和不使用template模板的区别。(你要是觉得乱就忽略这句话,等到看完所有内容再回来看这句话)

    1.直接创建组件:

    <script>
    	//创建组件com1
    	var com1 = {
    		//template中是组件内容,可以是多个html标签潜逃而成,但是根标签只能有一个
    	    template: "
    	    			<div>
    						<p>我是组件com1</p>
    						<p>哈哈哈</p>
    					</div>
    	    		  "
    	}
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果大概就是这样的:
    在这里插入图片描述

    可以看出这种创建组件的方式非常乱,所以vue提供了下面这种方式。

    2.使用template模板创建组件:

    Vue提供了template模板来定义组件内容,可以在该标签中书写HTML代码,然后通过id值绑定到组件内的template属性上,这样就有利于在编辑器中显示代码提示和高亮显示,不仅改善了开发体验,也提高了开发效率。

    <script>
    	//创建组件com1
    	var com1 = {
    		//使用id与template模板绑定
    	    template: '#com1template'
    	}
    script>
    <html>
    	
    	<template id="com1template">
    		
    		<div>
    			<p>我是组件com1p>
    			<p>哈哈哈p>
    		div>
    	template>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    四、组件的注册方式及使用:

    为了能使用这些组件,组件必须先注册以便 Vue 能够识别。

    1.局部注册:

    通过Vue实例的components属性来实现局部注册,注册后只能在该Vue实例中使用,其他Vue实例想使用该组件必须也使用components属性来注册该组件。

    <script>
    	//创建组件com1
    	var com1 = {
    	    template: '

    我是组件

    '
    } //创建Vue实例vm1 var vm1 = new Vue({ el: '#app1', // 通过components属性在vm1实例中注册局部组件com1,并起名myCompent,这样组件com1就可以在vm1实例中使用了。 components: { my-component: com1 } }) //创建Vue实例vm2 var vm2 = new Vue({ el: '#app2' })
    script> <html> <div id="app1"> <my-component>my-component> div> <div id="app2"> <my-component>my-component> div> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.全局注册:

    Vue.component()方法用于全局注册组件,全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中

    <script>
    	//创建组件com1并全局注册
    	Vue.component(
    		//这就是组件的名字,即
    		'com1', 
    		{
    			template: '

    我是组件

    '
    } ) //创建Vue实例vm1 var vm1 = new Vue({ el: '#app1' }) //创建Vue实例vm2 var vm2 = new Vue({ el: '#app2' })
    script> <html> <div id="app1"> <com1>com1> div> <div id="app2"> <com1>com1> div> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    备注:看完全局注册你可能会有疑问:我没有见过这种组件创建的方式呀?上面讲的组件创建方式和这个不一样呀?这时候你再回去看(三)中的备注可能就会理解了.

    五、组件的属性:

    上面我们学到了组件的创建、注册与使用方法,学到了使用template属性,接下来我们再看一下组件内部还有什么属性。

    • 组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。多了template属性,但是没有el属性。
    //这里以创建组件并全局注册为例
    Vue.component('my-component', {
    	template:'',
    	//与Vue实例不同的是,在组件中data必须是一个函数
        data: function () {
            return {
                shuxing: ''
            }
        },
        methods: {
            // ... ...
        },
        computed: {
            // ... ...
        },
        created: function () {
            // ... ...
        },
        props:[]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    六、组件的命名:

    组件有两种命名方式:短横线分隔命名、驼峰命名。
    注意:组件命名是在注册的时候命名,使用组件的时候也是使用注册的名字,而不是创建的组件对象的名字。

    <script>
    //创建组件并全局注册例子:
    Vue.component('my-component-name', { /* ... */ })
    Vue.component('MyComponentName', { /* ... */ })
    
    //创建组件并局部注册例子:
    var com1 = {
        /*...*/
    }
    //创建Vue实例vm1
    var vm1 = new Vue({
        el: '#app1',
        //注册组件并给组件命名:
        components: { my-component: com1 }  
        components: { myComponent: com1 }  
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    不管使用哪种方式注册,使用时都是使用驼峰命名:my-component

    <html>
    	<my-component>my-component>
    html>
    
    • 1
    • 2
    • 3

    七、组件组件之间数据传递:

    在这里插入图片描述

    1.父组件向子组件传值 - Props:

    props用来接收父组件中定义的数据,其值为数组。

    (1)静态传值:
    <html>
    
    <div class="container" id="app">
    	
        <blog-post 
             title="博文1" 
             content="西游记">
        blog-post>
    	
        <div id="blog-post-demo">
            <blog-post 
              	title="博文2" 
              	content="水浒传">
            blog-post>
        div>
    div>
    
    <template id="blog-post-template">
        <div>
            <p>{{title}}p>
            <p>{{content}}p>
        div>        
    template>
    html>
    
    <script>
    //创建组件并全局注册
    Vue.component('blog-post', {
    	//接收父组件传来的数据
      	props: ['title', 'content'],
      	template: '#blog-post-template’
    })
    
    
    let app = new Vue({
      el: '#app'
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    (2)动态传值:

    使用vue指令将父组件data内的属性值传给子组件。

    <html>
    
    <div class="container" id="app">
    	
        <blog-post 
            v-for="post in posts"
    		v-bind:title="post.title"
            v-bind:content="post.content"
    <template id="blog-post-template">
        <div>
            <p>{{title}}p>
            <p>{{content}}p>
        div>        
    template>
    html>
    
    <script>
    //创建组件并全局注册
    Vue.component('blog-post', {
    	//接收父组件传来的数据
      	props: ['title', 'content'],
      	template: '#blog-post-template’
    })
    
    
    let app = new Vue({
      el: '#app',
        data: {
        posts: [
          {title: '博文1', content: '西游记'},
          {title: '博文2', content: '水浒传'}
        ]
      }
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    效果:
    在这里插入图片描述

    2.子组件向父组件传值 - $emit:

    $emit(“b”)表示向父组件抛出事件b。

    <html>
    
    <div class="container" id="app">
    	
        <div>
            <blog-post 
            	@b="a()"
            	>
            blog-post>
        div>
    div>
    
    <template id="blog-post-template">
        <div>
        	<button @click="$emit('b')">button>
        div>        
    template>
    html>
    
    <script>
    //创建组件并全局注册
    Vue.component('blog-post', {
    	//接收父组件传来的数据
      	props: ['title', 'content'],
      	template: '#blog-post-template’
    })
    
    
    let app = new Vue({
      el: '#app',
      methods:{
    	   a(){
    	        alert("你点击了子组件");
    	   }
      }
    })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    效果:点击子组件的按钮会执行父组件的a()函数。

    八、案例:实现图书列表界面:

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" >
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js">script>
        <title>Documenttitle>
        <style type="text/css" rel="stylesheet">
            .text-secondary {
                line-height: 1em;
                font-size: 0.8em;
                border-bottom: 1em;
            }
            #table_book{
                font: Arial, 微软雅黑;
            }
            a:hover {
                text-decoration: underline solid rgb(23, 82, 192);
            }
            a:link {
                text-decoration: none;
            }
            .borderprimary{
                border:solid 1px blue !important;
                /* 这里要加一个 !important表示最大优先级,该样式会覆盖原先的样式*/
            }
        style>
    head>
    <body>
        
        <div id="table_book" class="container">
            <div class="row">
                <one-book  
                    v-for="(book,index) in books"
                    :book="book"
                    @delete="deleteBook(index)"
                    >one-book>
            div>
        div>
        <template id="book_temp">
            <div class="col-md-4 g-2 gy-md-3" >
                <div class="border" v-bind:class={borderprimary:!deleteCanHide}>
                    <div class="row" @mouseenter="showDelete" @mouseleave="hideDelete">
                        <img class="col-4" v-bind:src="book.img_url" width="100%" height="100%">
                        <div class="col-8">
                            <p class="fs-5"><a href="book.jd_link" class="fs-5">{{book.title}}a>p>
                            <p class="text-secondary">{{book.author}}p>
                            <p class="text-secondary">出版社:{{book.publisher}}p>
                            <p class="text-secondary">出版日期:{{book.publish_date}}p>
                            <p class="text-secondary" style="color:red; width:10;">定价:¥{{book.price}}p>
                            <div align="right">
                                
                                <input type="button" class="btn btn-primary" v-bind:class={invisible:deleteCanHide} value="删除" @click="$emit('delete')"/>
                            div>
                        div>
                    div>
                div>
            div>
        template>
        <script>       
            Vue.component("one-book",{
                template:'#book_temp',
                props:['book'],
                data(){
                    return{
                        deleteCanHide:true,
                    }
                },
                methods:{
                    hideDelete(){
                        this.deleteCanHide = true
                    },
                    showDelete(){
                        this.deleteCanHide = false
                    }
                }  
            })
            var app = new Vue({
                el:'#table_book',
                created(){
                    fetch("/books.json")
                    .then(function(response){
                        return response.json();
                    })
                    .then(function(response){
                        app.books = response;
                    })
                },
                data:{
                    books:'',
                },
                methods:{
                    deleteBook(index){
                        this.books.splice(index, 1);//books数组中从index位置开始删除1个数据
                    }
                }
            })
        script>       
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
  • 相关阅读:
    从零实现ORM框架GeoORM-对象表结构映射-02
    华为od面试记录
    Day13——滑动窗口最大值&&前 K 个高频元素(未解决)
    客观题【笔试】
    vue基于promise可以用于浏览器和node.js的网络请求库【axios封装-收藏版】
    Spark Streaming(二)
    Springboot整合整合Swagger3
    wget命令
    CVPR 2022 | 网络中批处理归一化估计偏移的深入研究
    Numpy入门[4]——数组类型
  • 原文地址:https://blog.csdn.net/m0_53881899/article/details/127804622