Vue 组件

官方资源

https://cn.vuejs.org/v2/guide/components.html

https://cn.vuejs.org/v2/guide/components-registration.html

什么是组件

组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。通常一个应用会以一棵嵌套的组件树的形式来组织:

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

组件定义

组件是可复用的 Vue 实例,且带有一个名字。把这个组件作为自定义元素来使用。组件的好处是写一次可以进行任意次数的复用。

全局组件

直接使用 Vue.component() 方法定义组件,这种组件叫做全局组件

例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 使用组件 -->
    <!-- 将组件名直接当做标签名在html代码中使用即可 -->
    <mytemp></mytemp>
    <!-- 组件可以进行任意次数的复用 -->
    <mytemp></mytemp>
</div>
</body>
<script>
    // 定义一个名为 mytemp 的新组件
    Vue.component('mytemp',{
        // template属性的值,作为组件的内容
        // vue 会把这个值替换到html中并会被浏览器渲染
        template:"<h2>我是一个组件</h2>"
    })
    var app = new Vue({
        el: '#app',
    })
</script>
</html>

效果

image-20201024105638230

上面代码中我们直接使用 Vue.component() 方法定义了组件,而这个 mytemp 组件可以用在所有 vue 实例中,

这种组件被称为 全局组件

局部组件

在具体的某个vue实例中,也可以定义组件,但是组件仅会在具体的 vue 实例中起作用,这种组件被称为 局部(私有)组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 使用组件 -->
    <!-- 将组件名直接当做标签名在html代码中使用即可 -->
    <mytemp></mytemp>
</div>
<div id="app2">
    <!-- 不可用 -->
    <mytemp></mytemp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        // app 的私有组件,其他实例对象不可用
        //components 是固定的属性
        components: {
            mytemp: {
                template: "<h2>我是一个局部组件</h2>",
            }
        }
    })
    var app2 = new Vue({
        el: '#app2',
    })
</script>
</html>

效果

image-20201024110002746

使用注意

  • 组件名如果是驼峰法命名,使用组件时要将大写字母改为小写,并且在前面加上 -

  • 组件中的tamplate属性必须有一个唯一的根元素,否则会报错

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!-- 使用组件 -->
    <!-- 将组件名直接当做标签名在html代码中使用即可 -->
    <my-temp></my-temp>
    <!-- 单标签方式使用 -->
    <my-temp/>
</div>
<div id="app2">
    <!-- 不可用 -->
    <my-temp></my-temp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        // app 的私有组件,其他实例对象不可用
        components: {
            // 驼峰法命名
            myTemp: {
                // 必须有唯一的根标签,多标签报错
                template: "<div><h2>我是一个组件</h2><h3>df</h3></div>",
            }
        }
    })
    var app2 = new Vue({
        el: '#app2',
    })
</script>
</html>

组件的使用

下面是使用组件来布局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .top {
             100%;
            height: 80px;
            background-color: #ccc;
        }

        .left {
            margin-top: 20px;
             800px;
            height: 600px;
            background-color: #ccc;
            float: left;
        }

        .right {
            margin-top: 20px;
             400px;
            height: 600px;
            background-color: #ccc;
            float: right;
        }
    </style>
</head>
<body>
<div id="app">
    <tops></tops>
    <lefts></lefts>
    <rights></rights>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        components:{
            tops:{
                template:'<div class="top">我是顶</div>'
            },
            lefts:{
                template:'<div class="left">我是左</div>',
            },
            rights:{
                template:'<div class="right">我是右</div>'
            }
        }
    })
</script>
</html>

效果

image-20201024111724215

组件中的数据及方法

组件是带有名字的可复用的 Vue 实例 ,所以它们与 new Vue 实例对象接收相同的参数选项 datacomputedwatchmethods , 但 el例外;

虽然组件和实例对象可以接收相同的参数选项,但在具体使用中,vue实例对象的 data 与组件中的 data 还是有差异的, 在我们自己写的组件中,data 必须是一个函数

一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回的对象;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <my-temp></my-temp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        components: {
            myTemp: {
                // 一个组件的 data 选项必须是一个函数
                data:function(){
                    // 将 数据 装入 对象 返回
                    return {msg:'我是data选项'}
                },
                // 其他选项的使用不受影响
                methods:{
                    cli(){
                        alert(123);
                    }
                },
                template: "<div @click='cli'>{{msg}}</div>",
            }
        }
    })
</script>
</html>

image-20201024112947025

vue实例也是组件

通过new Vue() 可以得到一个实例对象,其实这个实例对象就是一个特殊的组件,也有 template 参数,也可以当做组件来使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    {{msg}}
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data:{msg:'数据'},
        template:'<h2>组件</h2>'
    })
</script>
</html>

image-20201024113814575

你会发现插值没用了,这是因为

上面的代码中直接为Vue 实例对象传入了 template 参数,那么 vue 会使用template中的数据替换 el 选中的整个 DOM 节点 , 因此 data 选项中的的数据也不会绑定,因为在绑定数据之前,整个 DOM 节点包括节点中 {{msg}} 都会被替换;如果想让数据正常绑定,我们可以在 template 数据中加入 {{msg}}

例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    {{msg}}
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data:{msg:'数据'},
        template:'<h2>组件{{msg}}</h2>'
    })
</script>
</html>

image-20201024113919175

组件之间传值

https://cn.vuejs.org/v2/guide/components.html

组件作用域

注意:组件与组件之间都拥有自己独立的作用域,类似于闭包,他们的data数据不会共享

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <mytemp></mytemp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data:{msg:'数据'},
        components:{
            mytemp:{
                template:'<h2>data:{{msg}}</h2>'
            }
        }
    })
</script>
</html>

image-20201024170424519

运行上面的代码,你会发现,组件 mytemp 并不能获取实例中 data 的数据,这是因为组件与组件之间都拥有各自独立的作用域;

通过 Prop 向子组件传递数据 *

vue 在组件中提供了props 选项,props 接受一个在组件中自定义属性的值;

例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <!--使用组件并自定义属性和属性值-->
    <mytemp cc="makalo最帅"></mytemp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data:{msg:'数据'},
        components:{
            mytemp:{
                template:'<h2>data:{{cc}}</h2>',
                //接收组件自定义属性值
                props:['cc'],
            }
        }
    })
</script>
</html>

image-20201024170735185

知道了props的用法后,怎么才能将vue实例对象中的数据传入组件中呢?我们可以借助 v-bind 指令来进行传值;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 组件</title>
    <!--这里因为方便,我直接使用cdn方式引入-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <mytemp v-bind:cc="msg" v-bind:kk="msg2"></mytemp>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data:{
            msg:'数据',
            msg2:'数据二'
        },
        components:{
            mytemp:{
                template:'<h2>data:{{cc}}<br>{{kk}}</h2>',
                props:['cc','kk'],
            }
        }
    })
</script>
</html>

image-20201024171040014

原文地址:https://www.cnblogs.com/makalochen/p/13870097.html