Vue组件

Vue创建组件

什么是组件

什么是组件?组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样地方功能,就可以去调用对应的组件即可。

组件化和模块化的区别:

  • 模块化:是从代码逻辑的角度进行划分的,方便代码分层开发,保证每个功能模块的只能单一;
  • 组件化:是从UI界面的角度进行划分的;前端的组件化,方便了UI组件的重用;

文档

更多文档将在我的公众号 程序员涂陌 中陆续发布,请持续关注!

程序员涂陌
qrcode_for_gh

捐赠

Alipay WechatPay
alipay_258px
wechat_258px

定义Vue组件

方式一

1、使用Vue.extend来创建全局的Vue组件
2、通过template属性来指定组件要展示的HTML结构
3、通过Vue.component()定义全局组件
4、在HTML指定位置通过Tag标签的形式应用你的组件,组件的名称即是tag标签的名称

<div id="app">
    <!-- 组件的名称即为对应tag标签的名称 -->
    <mycom1></mycom1>
</div>

<script>
    // 创建组件
    var com1 = Vue.extend({
        template: '<h3>这是使用Vue.extend 创建的组件</h3>'
    });

    // 使用Vue.component('组件的名称', 创建出来的组件模板对象),定义全局组件
    Vue.component('mycom1', com1);
</script>

注意

  • Vue.component()定义组件名称的时候有两种命名方式:1、驼峰命名:Xxx;2、xxx。注意,使用驼峰命名时,tag标签不能使用驼峰名称,应将相应的大写字母替换为-加小写字母,例如:Vue.component('myCom', com1),那么tag标签应为:<my-com></my-com>

方式二

<!-- 组件的名称即为对应tag标签的名称 -->
<mycom1></mycom1>

<script>

    // 使用Vue.component('组件的名称', 创建出来的组件模板对象),定义全局组件
    Vue.component('mycom1', Vue.extend({
        template: '<h3>这是使用Vue.extend 创建的组件</h3>'
    }));
</script>

方式二就像是方式一的简化版,但是注意:
template中定义的内容只能存在一个根节点元素,即上面例子中template中不能出现和<h3>平级的标签。
比如下面这种写法就是错误的

Vue.component('mycom1', Vue.extend({
    template: '<h3>这是使用Vue.extend 创建的组件</h3><span></span>'
}));

解决办法就是,外层嵌套一个根标签就行了:

Vue.component('mycom1', Vue.extend({
    template: '<div><h3>这是使用Vue.extend 创建的组件</h3><span></span></div>'
}));

方式三

1、JavaScript中仍使用Vue.component来定义全局组件,和方式二相似,但是里面不再是template: 'HTML结构'了,而是引用一个外部标签的id值,即template:'id'

2、在被Vue实例控制的app外面,定义<template id="id">你的HTML结构</template>>

这种方式的好处就是是就组件代码都是定义在HTML结构中的,有智能代码提示;而JavaScript中定义组件仅是写一个引用。

实例:

<div id="app">
    <!-- 页面引用 -->
</div>


<template id="tmp">
    <!-- 比如仅存在一个根节点元素 -->
    <div>
        <h1></h1>>
        <h2></h2>
    </div>
</template>

//JavaScript部分
Vue.component('mycom', {
    template: '#tmp'
});

定义私有组件

除了上面讲到的定义全局组件,我们也可以定义私有组件,使用components: {}函数。

如:

<div id="app">
    <tem></tem>
</div>
<template id="tmp">
    <h3>这是私有组件</h3>
</template>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
new Vue({
    el: '#app',
    data: {},
    methods: {},
    components: {
        tem: {
            template: '#tmp'
        }
    }

});
</script>

组件元素

组件的data

在组件中,同样可以有自己的data数据,但是用法和Vue实例中的data用法有所不同:

  1. 组件中的data必须是一个方法,即
data: function(){ }
  1. 组件中的data方法必须返回一个Object对象
data: function(){
    return object
}

实例:

<div id="app">
    <mycom1></mycom1>
</div>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
Vue.component('mycom1', Vue.extend({
    data: function(){
        return {
            msg: '这是组件的data'
        }
    },
    template: '<h3>这是使用Vue.extend 创建的组件-- {{msg}}</h3>'
}));

new Vue({
    el: '#app',
    data: {},
    methods: {},
    components: {
    }
});
</script>

组件的切换

在遇到登录注册表单时,通常我们需要对两个按钮进行切换实现显示不同的表单,那么Vue中的组件切换正符合了这个功能要求。

方式一

可以使用Vue提供的v-ifv-else来实现两个组件间的切换,但是,仅支持切换两个组件

实例:

<div id="app">
    <a href="#" @click.prevent="flag=true">登录</a>
    <a href="#" @click.prevent="flag=false">注册</a>

    <login v-if="flag"></login>
    <register v-else="flag"></register>
</div>
<template id="login">
    <h3>这是登录表单</h3>
</template>
<template id="register">
    <h3>这是注册表单</h3>
</template>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
// 创建登录组件
Vue.component('login', {
    template: '#login'
});

// 创建注册组件
Vue.component('register', {
    template: '#register'
})

new Vue({
    el: '#app',
    data: {
        flag: true
    },
    methods: {}

});
</script>

定义flag参数,当flag=true就显示组件,当flar=false就隐藏组件

方式二

Vue提供了component来展示对应名称的组件。其中component是一个占位符,:is属性,可以用来指定要展示的组件名称

实例:

<div id="app">
    <a href="#" @click.prevent="comName='login'">登录</a>
    <a href="#" @click.prevent="comName='register'">注册</a>

    <component :is="comName"></component>
</div>
<template id="login">
    <h3>这是登录表单</h3>
</template>
<template id="register">
    <h3>这是注册表单</h3>
</template>
<script type="text/javascript" src="../lib/vue.js"></script>
<script type="text/javascript">
// 创建登录组件
Vue.component('login', {
    template: '#login'
});

// 创建注册组件
Vue.component('register', {
    template: '#register'
})

new Vue({
    el: '#app',
    data: {
        comName: 'login'
    },
    methods: {}
});
</script>

即使用Vue提供的component,它能够实现自动对组件进行展示和隐藏,通过:is='组件名称'

父子组件间传值

父组件给子组件传值

父组件给子组件传值,即实现在子组件中调用父组件中的methods或是获取父组件中的data.

传参数

<body>
    <!-- 父组件实例 -->
    <div id="app">
        
        <!-- 子组件实例 -->
        <com1></com1>
    </div>

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            msg: '这是父组件data值'
        },
        methods: {
            show(){
                console.log("这是父组件的show方法");
            }
        },

        // 子组件
        components: {
            com1: {
                template: '<h2>这是子组件</h2>'
            }
        }
    });
    </script>
</body>

如上,当我们直接在子组件中引用父组件data中定义的msg数据,将上面的修改为:

com1: {
    template: '<h2>这是子组件--{{msg}}</h2>'
}

那么就会报错。所以就证实了默认在子组件中不能访问父组件中的datamethods

为了解决子组件获取父组件数据,Vue提供了以下方式获取:

  • 1、父组件在引用子组件的时候,通过属性绑定的方式v-bind:,把需要传递给子组件的数据以属性绑定的形式传递到子组件内部,供子组件使用。

  • 2、在子组件中,通过props: []获取到父组件传递过来的数据;这样就完成了父组件向子组件传值

实例

<body>
    <!-- 父组件实例 -->
    <div id="app">
        
        <!-- 子组件实例 -->
        <com1 :fatoson="msg"></com1>
    </div>

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            msg: '这是父组件data值'
        },
        methods: {},

        // 子组件
        components: {
            com1: {
                template: '<h2>这是子组件--{{fatoson}}</h2>',
                props: ['fatoson']
            }
        }
    });
    </script>
</body>

如上,我们在子组件实例中使用了v-bind绑定了一个参数fatoson,其值是:msg即在父组件data中定义的值;那么就相当于父组件的一个data数据被Vue绑定到了子组件实例中,且父组件data值的别名是fatoson,那么在子组件中通过props: []属性就能获取到这个别名,然后就实现了父组件向子组件传值。需要注意以下:

  • 1、我们可以将为子组件绑定的参数名称是父组件值的别名。即此时msg相当于fatoson
  • 2、注意命名中若是驼峰命名,在HTML中必须用-替换。
  • 3、注意props是Vue为父组将向子组件传值提供的一个参数,且他是唯一的数组类型的。
  • 4、注意子组件通过props获取到的父组件的值是只读的,即不能修改。

传方法

上面讲了父组件给子组件传递普通的参数,下面我们将了解到父组件怎样给子组件传递方法。

<body>
    <!-- 父组件实例 -->
    <div id="app">
        
        <!-- 子组件实例 -->
        <com1 @open="show"></com1>
    </div>
    <template id="tmp">
        <div>
            <h2>这是子组件</h2>
            <input type="button" @click="myclick" value="子组件按钮,点击触发父组件方法"/>
        </div>
    </template>

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            msg: '这是父组件data值'
        },
        methods: {
            show(){
                console.log("这是父组件的show方法");
            }
        },

        // 子组件
        components: {
            com1: {
                template: '#tmp',
                props: ['fatoson'],
                methods: {
                    myclick(){
                        this.$emit('open');
                    }
                }
            }
        }
    });
    </script>
</body>

解释:

  • 1、这里子组件的template数据引用外部的<template></template>中的HTML代码。
  • 2、与传值思路相同,传递方法也需要在子组件实例中使用v-on@来绑定方法,方法别名@open,方法的值是show是在父组件中定义的方法名。
  • 3、与传值思路相同,传值使用了props来接受传递的参数,那么传方法提供了$emit()元素

综合

上面讲的父组件向子组件传递方法,那么既然是方法就肯定能传递方法参数。我们只需要在父组件方法中指定值名称即可

@子组件接收的方法别名="父组件中的方法(父组件中的参数值或data)"
<body>
    <!-- 父组件实例 -->
    <div id="app">
        
        <!-- 子组件实例 -->
        <com1 @open="show(fatosonval)"></com1>
    </div>
    <template id="tmp">
        <div>
            <h2>这是子组件</h2>
            <input type="button" @click="myclick" value="子组件按钮,点击触发父组件方法"/>
        </div>
    </template>

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            fatosonval: {
                id: '1',
                name: '涂陌'
            }
        },
        methods: {
            show(data){
                console.log(data);
            }
        },

        // 子组件
        components: {
            com1: {
                template: '#tmp',
                methods: {
                    myclick(){
                        this.$emit('open');
                    }
                }
            }
        }
    });
    </script>
</body>
1.png

子组件给父组件传值

即实现在父组件中调用子组件中的方法

<body>
    <!-- 父组件实例 -->
    <div id="app">
        
        <!-- 子组件实例 -->
        <com1 @open="show"></com1>
    </div>
    <template id="tmp">
        <div>
            <h2>这是子组件</h2>
            <input type="button" @click="myclick" value="子组件按钮,点击触发父组件方法"/>
        </div>
    </template>

    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            fatosonval: null
        },
        methods: {
            show(data){
                console.log(data);
            }
        },

        // 子组件
        components: {
            com1: {
                template: '#tmp',
                data(){
                    return {
                        sonval: { name: 'TyCoding', age: 19 }
                    }
                },
                methods: {
                    myclick(){
                        this.$emit('open', this.sonval);
                    }
                }
            }
        }
    });
    </script>
</body>

之前我们实现父组件向子组件传值的时候,需要在@open()中指定父组件中的data,而子组件给父组件传值的时候就不需要再指定了,而是直接在调用子组件中的open(这是父组件方法的别名),将子组件的值写进$emit('方法别名', data参数)中即可。

2.png

Vue获取DOM元素和组件

首先我们需要明白的就是Vue并不提倡我们操作DOM元素,Vue的宗旨就是让我们只关心业务逻辑。

那么通常我们需要获取一个如<h2></h2>中的值,采用原生JS通常需要先为tag标签定义一个id属性,然后通过JS代码document.getElementById('id').innterText来获取到<h2>中的文本数据,而Vue也实现了操作原生DOM的功能:

* 在需要获取的HTML标签中指定`ref`属性,其值可自定义。
* 在Vue实例中,使用`this.$refs.指定的值`来获取DOM对象,进行操作。
<h2 ref="h2">这是h2的文本数据</h2>>

console.log(this.$refs.h2.innerText);

通过$refs还能轻易获取子组件中的data和methods数据

首先需要为子组件引用实例定义ref="com1"属性,然后在Vue实例中通过this.$refs.com1即可获取子组件中的所有对象,即还能获取到子组件中的datamethods

实例:

<body>
    <!-- 父组件实例 -->
    <div id="app">
        <!-- 子组件实例 -->
        <com1 ref="com1"></com1>
        <input type="button" @click="show" value="获取元素">

        <h2 ref="h2">这是父组件</h2>
    </div>
    <template id="tmp">
        <div>
            <h2>这是子组件</h2>
        </div>
    </template>
    <script type="text/javascript" src="../lib/vue.js"></script>
    <script type="text/javascript">
    new Vue({
        el: '#app',
        methods: {
            show(){
                // console.log(this.$refs.h2.innerText);
                // console.log(this.$refs.com1); //获取子组件中的所有实例对象
                // console.log(this.$refs.com1.sonval); //获取子组件中定义的data值
                console.log(this.$refs.com1.sonshow()); //调用子组件中定义的方法

            }
        },

        // 子组件
        components: {
            com1: {
                template: '#tmp',
                data() {
                    return {
                        sonval: { name: 'TyCoding', age: 19 }
                    }
                },
                methods: {
                    sonshow() {
                        console.log('子组件的方法');
                    }
                }
            }
        }
    });
    </script>
</body>


交流

如果大家有兴趣,欢迎大家加入我的Java交流群:671017003 ,一起交流学习Java技术。博主目前一直在自学JAVA中,技术有限,如果可以,会尽力给大家提供一些帮助,或是一些学习方法,当然群里的大佬都会积极给新手答疑的。所以,别犹豫,快来加入我们吧!


联系

If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容