vue学习笔记(六) ----- vue组件
一、模块化与组件化
- 模块化的定义
 
模块化在Node中是一个规范,定义一些模块的相关的规则,从代码角度上来说,方便做区别,如果不使用模块化,写在js文件中不利于后期维护和扩展,从代码的层面上就把相关的功能脱离出来,所以模块化从从代码的角度触发,分析项目,把项目中一些功能类型的代码,单独抽离为一个个的模块,那么为了保证大家以相同的方式去封装模块,于是我们就创造了CommentJS规范
- 模块化的优点
 
在我们项目中,如果需要是实现相同的功能,就不需要再重写,所以模块化从一定程度上提高我们的开发效率,有一些相关模块,直接调用就可以了,方便项目开发,和后期的维护与扩展
- 组件化:
 
把页面中样式差不多的东西抽为单独的小组件,把需要经常复用的东西封装为一个单独的,今后需要用的时候直接拿就可以,不用再重写,从ui的角度触发去考虑问题,把页面中代码结构类似的区域抽离出来,封装成一个单独的小组件 ;前端的组件化,方便UI组件的重用;
- 组件化的优点:
 
随着项目规模的发展,我们手中的组件会越来越多,我们今后一个页面的ui,几乎都可以从手中拿现成的组件拼接出来,方便项目的开发和维护
二、创建全局组件的方式
1. 创建全局组件的方式一
- 先调用 
Vue.extend()得到组件的构造函数 
 var com1 = Vue.extend({
        template: '<h2>这是创建的第一个全局组件</h2>'
        // template 属性,表示这个组件的 UI 代码解构
})
- 通过
vue.component('组件的名称',组件的构造函数)来注册全局组件 
    Vue.component('mycom1', com1)
    //com1就是组件的构造函数
注意:
组件的名称如果是驼峰命名,那么引入的时候表名称得加连字符-
1.如果 Vue.component('myCom1','com1')
对应的组件标签是
2. 如果是Vue.component('myCom1Test','com1')
对应组件标签为:
3. 如果Vue.component('my-com1','com1')
对应组件标签为:
- 把注册好的组件名称,以标签的形式引入到vm实例区域的页面中即可
 
<div id="app">
<!--    引入全局的vue组件-->
    <mycom1></mycom1>
</div>
来吧展示:

2. 创建全局组件的方式二
- 直接使用
vue.component('组件的名称','组件对象') 
// Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象
 Vue.component('mycom2', {
     template:'<h2>这是直接使用 Vue.component 创建出来的组件</h2>'
})
- 把注册好的组件名称,以标签的形式引入到vm实例区域的页面中即可
 
<div id="app">
    <mycom2></mycom2>
</div>
来吧展示:

注意:
1.template 属性中,不能单独放一段文本,必须用标签包裹起来;
2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹;
Vue.component('mycom2', {
     template:'<div><p>嘿嘿嘿嘿嘿</p><h2>这是直接使用 Vue.component 创建出来的组件</h2><h1>哈哈哈哈</h1> </div>'
 })

3. 创建全局组件的方式三
- 给
template添加一个id选择器 
Vue.component('mycom3', {
        template: '#tpl'
})
- 定义一个 template 标签元素
使用 Vue 提供的 template 标签,可以定义组件的UI模板解构 
<div id="app">
   <mycom3></mycom3>
</div>
<template id="tpl">
    <h2>这是创建全局组件的第三种方式</h2>
</template>

注意:
template标签中里面也必须有唯一的一个根元素进行包裹
也就是如果没有根元素包裹,那么下面代码是执行不出来了会报错
<template id="tmpl">
        <h2>这是创建全局组件的第三种方式</h2>
        <p>哟哟哟哟哟哟</p>
</template>
正确写法:
<template id="tmpl">
    <div>
        <h2>这是创建全局组件的第三中方式</h2>
        <p>嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿</p>
    </div>
</template>

既然是全局组件,那么就可以重复调用,栗子:
<div id="app">
<mycom3></mycom3>
</div>
<div id="app2">
    <mycom3></mycom3>
</div>
<template id="tmpl">
        <h2>这是创建全局组件的第三中方式</h2>
</template>
<script>
    Vue.component('mycom3', {
        template: '#tmpl'
    })
    var vm = new Vue({
        el: '#app',
    });
    var vm2 = new Vue({
        el: '#app2',
    });
</script>

三、创建私有组件
创建一个私有组件
<div id="app">
    <mycom4></mycom4>
</div>
var vm = new Vue({
      el: '#app',
      data: {},
      methods: {},
      components: {
      // 定义实例中私有组件的   组件的名称   和组件的 解构
        'mycom4': {
          template: '<h6>这是定义的私有组件</h6>'
        }
      }
});
创建多个私有组件:
<div id="app">
    <mycom4></mycom4>
    <mycom5></mycom5>
</div>
components:{
            mycom4:{
                template:'<h2>这是我定义的私有组件1</h2>'
            },
            mycom5:{
                template:'<h2>这是我定义的私有组件2</h2>'
            }
         }

四、组件中相应数据和展示方法
 Vue.component('mycom', {
        template: '<h3 @click="show">这是自定义的全局组件 ------ {{ msg }}</h3>',
        data: function () { //
            // 在 组件中,可以有自己的私有数据
            // 但是,组件的 data 必须是一个 function
            // 并且内部 return 一个 数据对象
            return {
                msg: '我是组件的内部data'
            }
        },
        methods: { // 尝试定义组件的私有方法
            show() {
                // console.log('出发了组件的私有show方法!')
                alert('我是组件内部的方法')
            }
        }
    })

思考:
为什么要把 组件中的 data 定义为一个function呢?
因为这样做的话,每当我们在页面上引用一次组件,必然会先调用 这个 data function,
从而得到一个当前组件私有的 数据对象;
五、切换组件
1. 结合flag标识符和 v-if 与 v-else 实现组件的切换
<div id="app">
<!--    使用按钮去控制显示login和res-->
    <input type="button" value="显示登录" @click="flag=true"/>
    <input type="button" value="显示注册" @click="flag=false"/>
  <login v-if="flag"></login>
<!--    当flag:true的时候显示login-->
<!--    当flag:false的时候显示res-->
    <res v-else="flag"></res>
</div>
<script>
    Vue.component('login', {
        template: '<h2>登录</h2>'
    })
    Vue.component('res', {
        template: '<h2>注册</h2>'
    })
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
            el: '#app',
            data:{
                flag:false
            },
            methods:{}
        })
</script>

2. 切换多个组件
<div id="app">
<!--想要显示哪个组件就在:is属性的后面传入(字符串)=====> '组件的名字'-->
   <component :is="'com1'"></component>
   <component :is="'com3'"></component>
</div>
Vue.component('com1', {
        template: '<h2>我是第1个组件</h2>'
    })
    Vue.component('com2', {
        template: '<h2>我是第2个组件</h2>'
    })
    Vue.component('com3', {
        template: '<h2>我是第3个组件</h2>'
    })
    Vue.component('com4', {
        template: '<h2>我是第4个组件</h2>'
 })

进行多组件的切换
<div id="app">
<!--点击a链接,修改component的值
component标签结合is属性进行组件的切换-->
    <a href="#" @click="comname='com1'">显示组件1</a>
    <a href="#" @click="comname='com2'">显示组件2</a>
    <a href="#" @click="comname='com3'">显示组件3</a>
    <a href="#" @click="comname='com4'">显示组件4</a>
    <component :is="comname"></component>
</div>
 var vm = new Vue({
        el: '#app',
        data:{
            comname:'com1'
        },
//当vue解析文件到component标签时,如果有:is属性就会解析后面的字符串"comname"
//然后去data中寻找这个变量
//comname:'com1'
//正好是一个字符串的变量的名称,就会显示名称叫com1的组件
        methods:{}
 })

3.为组件切换添加动画
 <transition>
        <component :is="comname"></component>
    </transition>
<style>
        .v-enter,
        .v-leave-to{
            opacity:0;
            transform: translate(100px);
        }
        .v-enter-active,
        .v-leave-active{
            transition: all 0.4s ease;
        }
</style>

如上图效果显示,有标准流的影响,所以要脱离标准流的影响,让离开的组件脱离标准流
<style>
.....
.v-enter-active,
        .v-leave-active{
            transition: all 0.4s ease;
            position: absolute;
 }
 </style>

如图动画效果是先进入再离开,如果想要实现先离开再进入,则只需要在transition中添加mode="out-in"
 <transition mode="out-in"> -
        <component :is="comname"></component>
 </transition>

如果想要实现离开往左走,进入往右走的效果,则:
<style>
       .v-enter {
            /* 即将进入时候的坐标 */
            opacity: 0;
            transform: translateX(100px);
        }
        .v-leave-to {
            /* 离开时候,最终到达的位置 */
            opacity: 0;
            transform: translateX(-100px);
        }
</style>

六、父组件通过属性绑定向子组件传递数据
- 把要传递给子组件的数据,作为自定义属性,通过
v-bind绑定到子组件身上 
 <com :sonmsg="pmsg"></com>
- 在子组件中,不能直接使用父组件传递过来的数据,需要先用
props来接收一下 
   props: ['sonmsg']
- 在接收父组件传递过来的
props的时候,一定要和父组件中传递过来的自定义属性名称保持一致 
 template: '<h2>我是子组件-----{{sonmsg}}</h2>',
具体代码如下:
<body>
<div id="app">
    <com :sonmsg="pmsg"></com>
<!--    以属性绑定的方式将父组件中的值传递给子组件-->
<!--    这里相当于把 '我是父组件中的数据'放在这边 也就是 msg123='我是父组件中的数据'-->
<!--    但是如果子组件想用msg需要在子组件中定义一下-->
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
           pmsg:'我是父组件中的数据'
        },
        methods: {},
        components: { // 定义私有组件
            'com': { // 在Vue中,默认,子组件无法直接获取父组件中的数据
                template: '<h2>我是子组件-----{{sonmsg}}</h2>',
                props: ['sonmsg']
               // 在Vue中,只有 props 是数组,其它带 s 后缀的属性都是 对象
            }
        }
    });
</script>
</body>

七、父组件向子组件传递对象
- 把要传递给子组件的对象,作为自定义属性,通过
v-bind绑定到子组件身上 
  <com1 :msgobj123="msgObj"></com1>
- 在子组件中,不能直接使用父组件传递过来的对象,需要先用
props来接收一下 
 props: ['msgobj123']
- 在接收父组件传递过来的
props的时候,一定要和父组件中传递过来的自定义属性名称保持一致 
 template: '<h3>后面传递的是父组件中对象 ---- {{ JSON.stringify(msgobj123) }}</h3>'
template: '<h3>哈哈 {{ JSON.stringify(msgobj) }}</h3>',
具体代码如下:
<body>
<div id="app">
    <com1 :msgobj123="msgObj"></com1>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msgObj: {
                id:1,
                name:'千夏Chinatsu',
                age:18
            }
        },
        methods: {},
        components: {
            'com1': {
                template: '<h3>后面传递的是父组件中对象 ---- {{ JSON.stringify(msgobj123) }}</h3>',
                props: ['msgobj123']
            }
        }
    });
</script>
</body>

八、父组件向子组件传递方法
- 把要传递给子组件的方法,通过
v-on绑定事件到子组件身上 
<com v-on:func="show()"></com>
- 在子组件中,不能直接使用父组件传递过来的方法,需要先用
$emit()来接收一下 
  this.$emit('func')
- 在接收父组件传递过来的
$emit()中,一定要和父组件中传递过来的方法名称保持一致 
具体代码:
<body>
<div id="app">
    <com v-on:func="show()"></com>
</div>
<script>
    var vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(){
                console.log('触发了父组件中的show()方法')
            }
        },
        components: {
            'com': {
                template: '<input type="button" value="这是子组件的按钮" @click="btnClick()"/>',
                methods:{
                    btnClick(){
                        // console.log('hhhh')
                        this.$emit('func')
                    }
                }
            }
        }
    })
</script>
</body>

总结:
1.如果要向子组件传递 data 中的数据,则 使用 属性绑定的形式v-bind:
2. 如果要向子组件传递 methods 中的 方法,则 使用 事件绑定的形式v-on:
九、子组件向父组件传递数据
<body>
<div id="app">
<!--    方式一:-->
    <com v-on:func="show"></com>
<!--    $emit('func',1)后面要传递参数-->
<!--   方式二:-->
<!--    <com v-on:func="show(2)"></com>-->
<!--    然后$emit('func')后面就不用传递参数-->
</div>
<script>
    var vm = new Vue({
        el:'#app',
        data:{},
        methods:{
            show(arg){
                console.log('触发了父组件中的show()方法' + arg)
                // '--------'
            }
        },
        components: {
            'com': {
                template: '<input type="button" value="这是子组件的按钮" @click="btnClick()"/>',
                data:function(){
                    return{
                        sonmsg:'这是子组件中的数据'
                    }
                },
                methods:{
                    btnClick(){
                        this.$emit('func','嘿嘿嘿嘿嘿')
                    }
                }
            }
        }
    })
</script>
</body>

所以可以直接在show()方法中传入子组件中的data数据
methods:{
            show(arg){
                console.log('触发了父组件中的show()方法' +'--------'+ arg)
                // '--------'
            }
        },
components: {
            'com': {
                template: '<input type="button" value="这是子组件的按钮" @click="btnClick()"/>',
                data:function(){
                    return{
                        sonmsg:'这是子组件中的数据'
                    }
                },
                methods:{
                    btnClick(){
                        // console.log('hhhh')
                        this.$emit('func','嘿嘿嘿嘿嘿')
                        // this.$emit('func',this.sonmsg)
                    }
                }
            }
        }

把子组件传递过来的数据,保存到 父组件的  data 中
methods: {
        show(arg) {
          // console.log('触发了父组件中的show()方法' +'--------'+ arg)
          // 把子组件传递过来的数据,保存到 父组件的  data 中
          this.msgFormSon = arg
          console.log(this.msgFormSon)
        }
 },
总结:
子组件向父组件传值,本质上,还是调用了父组件传递过来的方法
只不过,子组件在调用的时候,把 数据 当作参数,传给这个方法了;
十、练习列表案例(结合父子组件传值)
<body>
  <div id="app">
    <!-- 评论框区域 -->
    <cmt-box @func="addNewCmt"></cmt-box>
    <ul>
      <cmt-item v-for="(item, i) in list" :item="item" :key="i"></cmt-item>
    </ul>
  </div>
  <script>
    Vue.component('cmt-item', {
      template: `<li>
        <h3>评论人:{{ item.name }}</h3>
        <h5>评论内容:{{ item.content }}</h5>
      </li>`,
      props: ['item']
    })
    Vue.component('cmt-box', {
      template: `<div>
      <label>评论人:</label>
      <br>
      <input type="text" v-model="name">
      <br>
      <label>评论内容:</label>
      <br>
      <textarea v-model="content"></textarea>
      <br>
      <input type="button" value="发表评论" @click="postComment">
    </div>`,
      data: function () {
        return {
          name: '',
          content: ''
        }
      },
      methods: {
        postComment() { // 发表评论
          // console.log('ok')
          const cmt = { name: this.name, content: this.content }
          // 子组件中,调用父组件传递过来的方法,然后可以把 子组件的数据,当作参数,传递给父组件的方法去使用
          this.$emit('func', cmt)
          this.name = this.content = ''
          // console.log(cmt)
        }
      }
    })
    var vm = new Vue({
      el: '#app',
      data: {
        list: [
          { name: 'zs', content: '沙发' },
          { name: 'ls', content: '板凳' },
          { name: 'qqq', content: '凉席' },
          { name: 'eee', content: '砖头' }
        ]
      },
      methods: {
        addNewCmt(cmt) { // 添加新评论
          // console.log(cmt)
          this.list.push(cmt)
        }
      }
    });
  </script>
</body>
十一、使用rel属性来获取页面中的元素
<body>
<div id="app">
 <input value="按钮" type="button" @click="show()"/>
    <!--<h2 id="myh2">{{msg}}</h2>-->
    <!--加入ref属性-->
     <h2 id="myh2" ref="hhh">{{msg}}</h2>
</div>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
        msg:'嘿嘿嘿嘿嘿'
        },
        methods:{
            show(){
            //原生想要获取h2中的数据的方法
               // var res = document.getElementById('myh2').innerHTML
               //console.log(res)
                console.log(this)
                console.log(this.$refs.hhh)
                console.log(this.$refs.hhh.innerHTML)
            }
        }
       })
</script>
</body>
在h2标签中没有加入ref属性的打印console.log(this)结果
在h2标签加入ref属性的打印console.log(this)结果
所以可以通过rel可以很方便的来获取元素
 console.log(this)
 console.log(this.$refs.hhh)
 console.log(this.$refs.hhh.innerHTML)

十二、使用rel属性来获取页面中的组件
所以可以根据msg去修改组件内部的数据或者调用子组件中的方法
<body>
<div id="app">
    <input value="按钮" type="button" @click="getCom()" />
    <com1 ref="xxxxx"></com1>
</div>
<script>
    Vue.component('com1', {
        template:'<h2>这是一个小组件---{{msg}}</h2>',
        data:function () {
            return {
                msg:'这是组件内部数据'
            }
        },
        methods:{
            show(){
                console.log('子组件中的方法被调用了')
            }
        }
    })
    var vm = new Vue({
        el:'#app',
        data:{
            msg:'这是父组件的数据'
        },
        methods:{
            getCom(){
                // console.log(this)
                this.$refs.xxxxx.msg = '组件内部数据被修改了'
                this.$refs.xxxxx.show()
            }
        }
    })
    //页面上可以为很多元素创建ref的引用
</script>
</body>

十三、在vue组件中data和props的区别
data在组件中,要被定义成一个function,并且要返回一个对象props在组件中,要被定义成数组,其中,数组的值都是字符串名,表示从父组件传递过来的数据props中的数据,不要直接拿来修改,如果想要修改,必须在data上重新定义一个属性,然后把属性的值从this.props直接拿过来data上的数据,都是组件自己私有的,数据都是可读可写的props都是外界传递过来的数据,数据只能读取,不能重新写入
vue学习笔记(六) ----- vue组件的更多相关文章
- vue学习笔记(六)表单输入绑定
		
前言 在上一章vue学习笔记(四)事件处理器这一篇博客的内容中,我们已经了解vue是如何绑定事件的,而本篇博客主要讲解的是vue中表单输入的绑定,通常我们自己提交信息的时候都是通过表单将信息到服务器的 ...
 - Vue学习笔记之Vue组件
		
0x00 前言 vue的核心基础就是组件的使用,玩好了组件才能将前面学的基础更好的运用起来.组件的使用更使我们的项目解耦合.更加符合vue的设计思想MVVM. 那接下来就跟我看一下如何在一个Vue实例 ...
 - 【Vue学习笔记】——   vue的基础语法 { }
		
学习笔记 作者:oMing vue v-on: 简称 @ <div id='app'> <button v-on:click='Show1'> </button> ...
 - vue学习笔记(二)vue的生命周期和钩子函数
		
前言 通过上一章的学习,我们已经初步的了解了vue到底是什么东西,可以干什么,而这一篇博客主要介绍vue的生命周期和它常用的钩子函数,如果有学过java的园友可能有接触到在学习servlet的时候学过 ...
 - vue学习笔记:vue的认识与特点与获取
		
Vue了解 Vue:读作 view Vue是一个渐进式框架 与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计. Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整 ...
 - Vue学习笔记六:v-model 数据双向绑定
		
目录 v-model简介和适用范围 新建HTML 所见即所得 v-model模拟简易计算器 v-model简介和适用范围 Vue的一大特点之一就是数据的双向绑定,v-model就是实现这个功能的指令, ...
 - vue学习笔记—bootstrap+vue用户管理
		
vue,读音view,简单易用的前端框架.特点如下: 1.一个mvvm的前端框架,内部做好了html中dom对象和后台用js语言定义的变量的双向绑定 2.中国人尤雨溪维护的个人项目,中文资料多,和go ...
 - Vue学习笔记之Vue指令系统介绍
		
所谓指令系统,大家可以联想咱们的cmd命令行工具,只要我输入一条正确的指令,系统就开始干活了. 在vue中,指令系统,设置一些命令之后,来操作我们的数据属性,并展示到我们的DOM上. OK,接下来我们 ...
 - Vue学习笔记之Vue学习前的准备工作
		
0x00 起步 1.扎实的HTML/CSS/Javascript基本功,这是前置条件. 2.不要用任何的构建项目工具,只用最简单的<script>,把教程里的例子模仿一遍,理解用法.不推荐 ...
 - VUE学习笔记之vue cli 构建项目
		
一.环境搭建: 1.安装node.js 从node.js官网下载并安装node,安装过程很简单,一路"下一步"就可以了.安装完成之后,打开命令行工具(win+r,然后输入cmd), ...
 
随机推荐
- python类,魔术方法等学习&&部分ssti常见操作知识点复习加深
			
python类学习&&部分ssti常见操作知识点复习加深 在做ssti的模块注入的时候经常觉得自己python基础的薄弱,来学习一下,其实还是要多练习多背. 在python中所有类默认 ...
 - Linux等待队列(Wait Queue)
			
1. Linux等待队列概述 Linux内核的等待队列(Wait Queue)是重要的数据结构,与进程调度机制紧密相关联,可以用来同步对系统资源的访问.异步事件通知.跨进程通信等.在Linux中,等待 ...
 - Python-变量-字符串
			
str 字符串如何表示字符串? 单行 单引号 '' 如果字符串中有单引号就需要双引号表示,反之亦然 双引号 " " 换行表示 \ one_str = "简洁胜于优雅&qu ...
 - Django 联合唯一UniqueConstraint
			
from django.db import models class UserAttention(models.Model): watcher = models.ForeignKey('user.Us ...
 - 零基础学习Kmeans聚类算法的原理与实现过程
			
内容导入: 聚类是无监督学习的典型例子,聚类也能为企业运营中也发挥者巨大的作用,比如我们可以利用聚类对目标用户进行群体分类,把目标群体划分成几个具有明显特征区别的细分群体,从而可以在运营活动中为这些细 ...
 - VUE第一个项目怎么读懂
			
VUE介绍 VUE是前端开发框架. 原始的前端开发需要工程师写html.写css.写javascript(js).js是脚本语言,浏览器可以运行js来执行一些js支持的动作,例如点击反馈,下拉菜单.操 ...
 - 099 01 Android 零基础入门  02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类
			
099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类 本文知识点:编写并测试Subject类 说明: ...
 - SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期
			
写在前面 通过前几篇文章的学习,我们从大体上了解了shiro关于认证和授权方面的应用.在接下来的文章当中,我将通过一个demo,带领大家搭建一个SpringBoot整合Shiro的一个项目开发脚手架, ...
 - ORA-00019: maximum number of session licenses exceeded 超出最大会话许可数
			
ORA-00019: maximum number of session licenses exceededORA-00019: 超出最大会话许可数 Cause: All licenses ...
 - linux块设备驱动---程序设计(转)
			
块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为:int register_blkdev(unsigned i ...