[Vue] : 组件

定义Vue组件

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

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

全局组件定义的三种方式

  1. 使用Vue.extend配合Vue.component方法:
  • 1.1 使用Vue.extend来创建全局的Vue组件
  • 1.2 通过template属性,指定了组件要展示的HTML结构,模板内容必须有且只能有唯一的一个根元素。
  • 1.3 使用Vue.component('组件的名称', 创建出来的组件模板对象)
var com1 = Vue.extend({
    template: '<h1>这是通过Vue.extend()方式创建的组件</h1>'
})

Vue.component('myCom1', com1)
  • 1.4 如果要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中即可
  • 1.5 如果使用Vue.component定义全局组件的时候,组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母,两个单词之前,使用-链接
  • 1.6 如果不使用驼峰,则直接拿名称来使用即可
<div id="app">
    <my-com1></my-com1>
</div>

也可以直接写成

Vue.component('myCom1', Vue.extend({
    template: '<h1>这是通过Vue.extend()方式创建的组件</h1>'
}))
  1. 直接使用 Vue.component 方法:
Vue.component('myCom2', {
    template: '<h1>第二个参数直接传个对象</h1>'
})
  • 也可以改为
var tmpObj = {
    template: '<h1>第二个参数直接传个对象</h1>'
}

Vue.component('myCom2', tmpObj)
  1. 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构
<template id="tmpl">
    <div>
        <h1>通过 template 在组件外部定义的模板</h1>
        <h4>哈哈</h4>
    </div>
</template>

同时,需要使用 Vue.component 来定义组件:

Vue.component('myCom1', {
    template: '#tmpl'
})

注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

定义私有组件

定义实例内部私有组件,子组件内部还可以继续定义子组件

var vm = new Vue({
    el: '#app',
    data: {
    },
    components: {
        login: {
            template: '<div><h1>登录</h1><child-com></child-com></div>',
            components: {
                childCom: {
                    template: '<h3>登录子组件的子组件</h3>'
                }
            }
        }
    }
})

也可将模板写在html结构中,实例内部写成template: '#login'

或者将模板对象定义到实例外部,内部通过'组件的名称': 组件的模板对象的方式定义私有组件。如果组件名称与组件模板对象同名,可以简写。

var login = {
    template: '<h1>1234</h1>'
}

var vm = new Vue({
    el: '#app',
    components: {
        // '组件的名称': 组件的模板对象
        // 'mylogin': login
        login
    }
})

在组件内部

<template id="login">
    <h1>登录</h1>
</template>

组件中datamethods

  1. 在组件中,data需要被定义为一个方法,这个方法内部必须返回一个对象。
  2. 组件中 的data 使用方式,和实例中的 data 使用方式完全一样。
Vue.component('account', {
    template: '#tmpl',
    data() {
        return {
            msg: '大家好!'
        }
    },
    methods:{
        login(){
            alert('点击了登录按钮');
        }
    }
});

计数器示例

注意:data如果return dataObj,会导致多个计数器共用dataObj对象,因此需要return { count: 0 },才能保证各个计数器之间互不影响

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="lib/vue-2.4.0.js"></script>
</head>

<body>
  <div id="app">
    <counter></counter>
    <hr>
    <counter></counter>
  </div>

  <template id="tmpl">
    <div>
      <input type="button" value="+1" @click="increment">
      <h3>{{count}}</h3>
    </div>
  </template>

  <script>
    var dataObj = { count: 0 }

    Vue.component('counter', {
      template: '#tmpl',
      data() {
        // return dataObj
        return { count: 0 }
      },
      methods: {
        increment() {
          this.count++
        }
      }
    })

    var vm = new Vue({
      el: '#app'
    })
  </script>
</body>

</html>

切换组件

定义登录和注册组件

Vue.component('login', {
    template: '<h3>登录组件</h3>'
})

Vue.component('register', {
    template: '<h3>注册组件</h3>'
})

通过flag配合v-if v-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></register>
</div>

使用:is属性来切换组件

使用component标签,来引用组件,并通过:is属性来指定要加载的组件

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

组件切换的动画效果

  • 使用transition包裹要实现动画的组件
  • 定义v-enter, v-leave-to, v-enter-active, v-leave-active样式
  • 设置transition mode属性设置组件切换时候的模式,否则两个动画会同时执行
<div id="app">
    <a href="#" @click.prevent="comName='login'">登录</a>
    <a href="#" @click.prevent="comName='register'">注册</a>
    <transition mode="out-in">
        <component :is="comName"></component>
    </transition>
</div>

父组件向子组件传值

  1. 父组件可以在引用子组件的时候, 通过属性绑定v-bind:的形式, 把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用。
<div id="app">
    <com1 v-bind:parentmsg="msg"></com1>
</div>
  1. 子组件一定要使用props属性来定义父组件传递过来的数据
var vm = new Vue({
    el: '#app',
    data: {
        msg: '这是父组件的数据'
    },
    components: {
        com1: {
            template: '<h1>子组件 -- {{parentmsg}}</h1>',
            props: ['parentmsg']
        }
    }
})

子组件中的data中的数据和props中的数据的区别:

  • 子组件中的data数据,并不是通过 父组件传递过来的,而是子组件自身私有的,组件中的所有props中的数据,都是通过父组件传递给子组件的
  • data上的数据,都是可读可写的;props中的数据,都是只读的,无法重新赋值

父组件向子组件传递方法

  • 父组件向子组件传递方法,使用的是v-on事件绑定机制;
  • 子组件在自定义的myclick方法中,通过this.$emit('事件属性')的方式调用父组件传递过来的方法
<body>
  <div id="app">
    <!-- 用func接收父组件的show方法 -->
    <com2 @func="show"></com2>
  </div>

  <!-- 定义了子组件模板 -->
  <template id="tmpl">
    <div>
      <h1>这是子组件</h1>
      <input type="button" value="子组件按钮,点击调父组件show方法" @click="myclick">
    </div>
  </template>

  <script>
    // 定义了一个字面量类型的组件模板对象
    var com2 = {
      template: '#tmpl',
      methods: {
        myclick() {
          this.$emit('func')
        }
      }
    }

    var vm = new Vue({
      el: '#app',
      methods: {
        show() {
          console.log('这是父组件的show方法')
        }
      },
      components: {
        com2
      }
    })
  </script>
</body>

子组件向父组件传值

  1. 原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
  2. 父组件将方法的引用传递给子组件,其中,getMsg是父组件中methods中定义的方法名称,func是子组件调用传递过来方法时候的方法名称
  3. 子组件内部通过this.$emit('方法名', 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app">
    <com2 @func="getMsg"></com2>
</div>

<!-- 定义了子组件模板 -->
<template id="tmpl">
    <div>
        <h1>这是子组件</h1>
        <input type="button" value="按钮" @click="myclick">
    </div>
</template>

<script>
    // 定义了一个字面量类型的组件模板对象
    var com2 = {
        template: '#tmpl',
        data() {
            return {
                sonMsg: { id: 1, name: '张三' }
            }
        },
        methods: {
            myclick() {
                this.$emit('func', this.sonMsg)
            }
        }
    }

    var vm = new Vue({
        el: '#app',
        data: {
            parentMsg: null
        },
        methods: {
            getMsg(data) {
                this.parentMsg = data
                console.log(this.parentMsg)
            }
        },
        components: {
            com2
        }
    })
</script>

使用 this.$refs 来获取DOM元素和组件

  • 获取DOM元素
<h3 ref="myh3">这是一个H3</h3>

在Vue实例中,使用this.$refs.myh3 获取到DOM元素,与document.getElementById('myh3') 等效

  • 获取组件
<div id="app">
    <input type="button" value="获取组件" @click="getElement">
    <com1 ref="mycom"></com1>
</div>

<template id="tmpl">
    <div>
        <h3>子组件</h3>
    </div>
</template>
<script>

    var com1 = {
        template: '#tmpl',
        data(){
            return {
                msg:'子组件的msg'
            }
        },
        methods: {
            show(){
                console.log('子组件的show方法')
            }
        }
    }
    var vm = new Vue({
        el: '#app',
        data: {
        },
        methods:{
            getElement() {
                // 获取子组件的data数据
                console.log(this.$refs.mycom.msg)
                // 调用子组件的方法
                this.$refs.mycom.show()
            }
        },
        components:{
            com1
        }
    })
</script>
posted @ 2019-06-24 00:16  moon1992  阅读(214)  评论(0编辑  收藏  举报