深入浅出学Vue(四) | Vue组件的使用

本文深入探讨Vue组件,包括组件的注册(全局与局部)、Data和Methods的使用、组件切换(v-if与component标签)、Prop和传值问题、插槽的运用以及动态组件和异步组件的概念。详细讲解了如何通过Prop传递数据、子组件如何向父组件传值以及如何利用ref操作DOM。此外,还介绍了具名插槽、动态组件的缓存和异步组件的加载策略。

初识组件

可以通过一个简单的组件来认识组件。

  1. 新建组件

    Vue.component('mycomponent', {
        data: function(){
            return {
                number: 0
            }
        },
        template: '<button v-on:click="number++">值为{{number}}</button>'
    })
    
    • Vue.component( ‘组件名称’,{组件内容} )
    • data组件数据,必须使用函数的形式返回,这样多个组件才不会使用同一个data,避免相互影响。
    • template组件的html内容,即展示的内容。
  2. 使用组件

    注意:组件必须放在实例创建前

    <div id="app">
    	<mycomponent></mycomponent>
    </div>
    
    • 直接用名称定义即可

组件注册

注意:组件只可以有一个外标签,意味着当我们需要使用多个标签时,应该使用一个外标签将其包裹。

全局组件

使用Vue.extend()方法

<div id="app">
    <mycomponent></mycomponent>
</div>
<script type="text/javascript">
    var com1 = Vue.extend({
        template: '<h1>hello,组件</h1>'
    })
    Vue.component('mycomponent', com1)
    var app = new Vue({
        el: '#app'
    })
</script>

简写

<div id="app">
    <mycomponent></mycomponent>
</div>
<script type="text/javascript">
    Vue.component('mycomponent', {
        template: '<h1>hello,组件</h1>'
    })
    var app = new Vue({
        el: '#app'
    })
</script>

通过template绑定外部标签

  • 好不容易从前端的html标签拼接中逃离出来,又要继续使用?当然不是
<div id="app">
    <mycomponent></mycomponent>
</div>
<template id="com">
    <h1>hello,组件</h1>
</template>
<script type="text/javascript">
    Vue.component('mycomponent', {
        template: '#com'
    })
    var app = new Vue({
        el: '#app'
    })
</script>

将组件绑定给变量(简化逻辑)

<div id="app">
    <com></com>
    <com></com>
</div>
<template id="com">
    <div>
        <h1>{{count}}</h1><br>
        <button type="button" v-on:click="add">+1</button>
    </div>
</template>
<script type="text/javascript">
    let component1 = {
        template: '#com',
        data: function(){
            return{
                count: 0
            }
        },
        methods: {
            add(){
                this.count++
            }
        }
    }
    Vue.component('com', component1)
    var app = new Vue({
        el: '#app'
    })
</script>

局部组件

局部绑定html标签

<div id="app">
    <com></com>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        components: {
            com: {
                template: '<h1>hello,组件</h1>'
            }
        }
    })
</script>

局部绑定外部template

<div id="app">
    <com></com>
</div>
<template id="com">
    <h1>hello,组件</h1>
</template>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        components: {
            com: {
                template: '#com'
            }
        }
    })
</script>

尽量使用绑定外部template的方式,这样一定程度上可以提高程序的复用性和使逻辑结构更加清晰,特别是当和数据交互时。

将组件绑定给变量(简化逻辑)

<div id="app">
    <com></com>
</div>
<template id="com">
    <h1>hello,组件</h1>
</template>
<script type="text/javascript">
    var com = {
        template: '#com'
    }
    var app = new Vue({
        el: '#app',
        components: {
            com: com
        }
    })
</script>

Data与methods

  • 组件中的Data和methods的使用基本方法和不使用组件相差不大。
  • 区别在于组件中的Data必须以function(){ return{ } }的方式返回,这样每个组件使用的数据将是单独的数据对象,他们之间不会发生冲突。
<div id="app">
    <com></com>
    <com></com>
</div>
<template id="com">
    <div>
        <h1>{{count}}</h1><br>
        <button type="button" v-on:click="add">+1</button>
    </div>
</template>
<script type="text/javascript">
    Vue.component('com',{
        template: '#com',
        data: function(){
            return{
                count: 0
            }
        },
        methods: {
            add(){
                this.count++
            }
        }
    })
    var app = new Vue({
        el: '#app'
    })
</script>

组件切换

使用v-if切换

  • 使用一个flag信号,当模块需要更改的时候只需要改变信号量。
  • 存在局限性,只能在两个组件中切换。
<div id="app">
    <a href="" v-on:click.prevent="flag=true">登录</a>
    <a href="" v-on:click.prevent="flag=false">注册</a>
    <login v-if="flag"></login>
    <register v-else></register>
</div>

<template id="login">
    <div>
        <h1>
            登录模块
        </h1>
    </div>
</template>
<template id="register">
    <div>
        <h1>
            注册模块
        </h1>
    </div>
</template>

<script>
    // 注册
    Vue.component('login', {
        template: '#login'
    })
    // 登录
    Vue.component('register', {
        template: '#register'
    })

    var app = new Vue({
        el: '#app',
        data: {
            flag: true
        }
    })
</script>

使用component标签动态切换

  • component是Vue提供的一个组件标签,我们可以通过这个标签动态的为组件标签赋值,只需要改变组件标签的值就可以改变显示的组件。
<div id="app">
    <a href="" v-on:click.prevent="flag='login'">登录</a>
    <a href="" v-on:click.prevent="flag='register'">注册</a>
    <component v-bind:is="flag"></component>
</div>

<template id="login">
    <div>
        <h1>
            登录模块
        </h1>
    </div>
</template>
<template id="register">
    <div>
        <h1>
            注册模块
        </h1>
    </div>
</template>

<script>
    // 注册
    Vue.component('login', {
        template: '#login'
    })
    // 登录
    Vue.component('register', {
        template: '#register'
    })

    var app = new Vue({
        el: '#app',
        data: {
            flag: 'login'
        }
    })
</script>

Prop与传值问题

组件想要使用父组件的数据,要通过Prop属性来自定义,不然将无法在标签里面使用父组件的数据。

Prop和data的区别

  • Prop是只读不可改的,Prop属性是绑定的父组件的data值,需要在标签再次手动的设置
  • data是可读可修改的,data是属于组件自身的值,使用修改方便

父组件向子组件传值

<div id="app">
    <com v-bind:parent="name"></com>	<!--绑定父组件的数据-->
</div>
<template id="com">
    <div>
        <h1>子组件</h1>
        <a>{{name}}</a>
        <a>{{age}}</a><br>
        父组件名:<a>{{parent}}</a>		<!--使用数据-->
    </div>
</template>
<script type="text/javascript">
    var com = {
        template: '#com',
        data: function() {
            return{
                name: "张三",
                age: 12
            }
        },
        props: ['parent']				//声明
    }
    var app = new Vue({
        el: '#app',
        data: {
            name: "张大大"
        },
        components: {
            com: com
        }
    })
</script>

尝试一下使用方法来改变父组件的值,可以看到,就算是,子组件的改变并不会影响父组件值的更改,只会改变在子组件中的值,一定程度上说,这个更改时无效的。

<div id="app">
    <h1>{{name}}腻子敢改我名?</h1>
    <com v-bind:parent="name"></com>	<!--绑定父组件的数据-->
</div>
<template id="com">
    <div>
        <h1>子组件</h1>
        <a>{{name}}</a>
        <a>{{age}}</a><br>
        父组件名:<a href="" v-on:click.prevent="change">{{parent}}</a>		<!--使用数据-->
        <a>{{parent}}</a>
    </div>
</template>
<script type="text/javascript">
    var com = {
        template: '#com',
        data: function() {
            return{
                name: "张三",
                age: 12
            }
        },
        methods: {
            change: function(){
                this.parent="张大"
            }
        },
        props: ['parent']				//声明
    }
    var app = new Vue({
        el: '#app',
        data: {
            name: "张大大"
        },
        components: {
            com: com
        }
    })
</script>

父组件向子组件传递方法

  • 传递值使用v-bind进行绑定,而传递方法使用v-on进行绑定。
  • 它的使用通过在子组件中定义方法使用this.$emit()去手动触发。
<div id="app">
    <h3>父组件</h3>
    <h1>我是 {{name}},腻子敢改我名?</h1>
    <com v-on:func="changeName"></com>	<!--绑定父组件的数据-->
</div>
<template id="com">
    <div>
        <h3>子组件</h3>
        <button v-on:click="change">大逆不道要改父组件的名字</button>
    </div>
</template>
<script type="text/javascript">
    var com = {
        template: '#com',
        methods: {
            change: function(){
                this.$emit('func')
            }
        }
    }
    var app = new Vue({
        el: '#app',
        data: {
            name: "张大大"
        },
        methods: {
            changeName: function(){
                this.name="张王子"
            }
        },
        components: {
            com: com
        }
    })
</script>

子组件向父组件传值

  • 子组件向父组件传值是通过父组件向子组件传递的方法来进行的。
  • 传递的方法可以携带参数,在子组件赋值后,通过触发回传到外父组件,如果有多个值需要传递,依次在后面加信息即可。
<div id="app">
    <h3>父组件</h3>
    <h1>我是 {{name}},我有个儿子</h1>
    <a>儿子的信息是:{{son}}</a>
    <hr >
    <com v-on:func="changeName"></com>	<!--绑定父组件的数据-->
</div>
<template id="com">
    <div>
        <h3>子组件</h3>
        <button v-on:click="change">告诉他</button>
    </div>
</template>
<script type="text/javascript">
    var com = {
        template: '#com',
        data: function() {
            return{
                my: {
                    name: "张三",
                    age: 12
                }
            }
        },
        methods: {
            change: function(){
                this.$emit('func',this.my)
            }
        },
        props: ['parent']				//声明
    }
    var app = new Vue({
        el: '#app',
        data: {
            name: "张大大",
            son: null
        },
        methods: {
            changeName: function(my){
                this.son=my
            }
        },
        components: {
            com: com
        }
    })
</script>

利用ref获取DOM和组件引用

在Vue中可以使用原生的js来对DOM树进行操作,但是Vue提供一种更简单快捷的方式ref来对需要操作的DOM树进行操作。

利用ref操作DOM

<div id="app">
    <a ref="mya">{{name}}</a>
    <button v-on:click="changeName()">打游戏得到的快乐是空虚的</button>
</div>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: {
            name: "张大大",
        },
        methods: {
            changeName: function(my){
                window.alert(this.$refs.mya.innerText)
                window.alert(this.$refs.mya.innerText)
                window.alert(this.$refs.mya.innerText)
            }
        }
    })
</script>

通过ref进行组件引用

<div id="app">
    <com ref="mycom"></com>
    <button v-on:click="changeName()">打游戏得到的快乐是空虚的</button>
</div>

<template id="com">
    <div>
        <a>{{message}}</a>
    </div>
</template>
<script type="text/javascript">
    let com = {
        template: '#com',
        data: function(){
            return {
                message: "hello"
            }
        },
        methods: {
            change(){
                this.message="olleh"
            }
        }
    }
    var app = new Vue({
        el: '#app',
        methods: {
            changeName: function(my){
                window.alert(this.$refs.mycom.message)
                this.$refs.mycom.change()
            }
        },
        components: {
            com: com
        }
    })
</script>

插槽

组件简单应用

从父组件中向子组件传递一些数据值可以通过prop的方式来传递,但是插槽可以更简单的做到这个一步,只需要在组件中留下一个插槽,在父组件调用组件的地方就可以在组件标签的中间嵌入任何父组件的一切数据或属性。

例:

<div id="app">
    <com>
        <h1>{{msg}}</h1>	<!--显示插槽的内容-->
    </com>
</div>
<template id="com">
    <div>
        <slot></slot>		<!--留下插槽-->
    </div>
</template>
<script>
    var com = {
        template: '#com'
    }
    var app = new Vue({
        el: '#app',
        components: {
            com: com
        },
        data: {
            msg: "组件"
        }
    })
</script>

具名插槽和匿名插槽

当只有一个插槽时,我们不会去定义插槽的名称,这时插槽会有一个默认的匿名插槽去匹配未定义的插槽和插槽内容。

而有多个插槽时,为了能够正常识别使用,会将每一个插槽都命名使用,而父组件根据slot属性匹配对应的插槽。

<div id="app">
    <com>
        <div slot="first">			<!--根据名称定义匹配插槽-->
            <h1>第一个组件{{msg}}</h1>
        </div>
        <hr/>
        <div slot="">
            <h1>未定义名称组件</h1>
        </div>
        <hr/>
        <div slot="last">
            <h1>最后一个组件</h1>
        </div>
    </com>
</div>
<template id="com">
    <div>
        <div>
            <slot name="first"></slot>	<!--定义插槽名称-->
        </div>
        <div>
            <slot></slot>
        </div>
        <div>
            <slot name="last"></slot>
        </div>
    </div>
</template>
<script>
    var com = {
        template: '#com'
    }
    var app = new Vue({
        el: '#app',
        components: {
            com: com
        },
        data: {
            msg: "组件"
        }

    })
</script>

vue新版本语法

在vue@2.6.x之后,slot=插槽名的方式已经被舍弃,虽然还可以正常使用,但是官方文档明确指出被舍弃并且不推荐使用。取而代之的是新的标签v-slot:插槽名的方式,并且必须将这个属性放置在<tempalte v-slot:插槽名>才可以生效。

<div id="app">
    <com>
        <template v-slot:first>			<!--根据名称定义匹配插槽-->
            <h1>第一个组件{{msg}}</h1>
        </template>
        <hr/>
        <template>
            <h1>未定义名称组件</h1>
        </template>
        <hr/>
        <template v-slot:last>
            <h1>最后一个组件</h1>
        </template>
    </com>
</div>
<template id="com">
    <div>
        <div>
            <slot name="first"></slot>	<!--定义插槽名称-->
        </div>
        <div>
            <slot></slot>
        </div>
        <div>
            <slot name="last"></slot>
        </div>
    </div>
</template>
<script>
    var com = {
        template: '#com'
    }
    var app = new Vue({
        el: '#app',
        components: {
            com: com
        },
        data: {
            msg: "组件"
        }

    })
</script>

子组件向父组件传值

在插槽中,不仅父组件向子组件传递值十分方便,子组件向父组件传值十分方便。

只需要在子组件的插槽中使用v-bind:自定义属性名绑定自定义属性名,在父组件就可以通过v-slot="slotProps"来获取所有的传递过来的属性值。

<div id="app">
    <com>
        <template v-slot:first>
            <!--根据名称定义匹配插槽-->
            <h1>第一个组件{{msg}}</h1>
        </template>
        <hr />
        <template v-slot="slotProps">	//接受所有传递过来的属性
            <h1>未定义名称组件</h1>
            <a>{{slotProps.child}}</a>	//获取传递过来的属性
        </template>
        <hr />
        <template v-slot:last>
            <h1>最后一个组件</h1>
        </template>
    </com>
</div>
<template id="com">
    <div>
        <div>
            <p>{{childMsg}}</p>
            <slot name="first"></slot>
            <!--定义插槽名称-->
        </div>
        <div>
            <slot :child="childMsg"></slot>	//绑定要传递的属性
        </div>
        <div>
            <slot name="last"></slot>
        </div>
    </div>
</template>
<script>
    var com = {
        template: '#com',
        data: function() {
            return {
                childMsg: 'hello'
            }
        }
    }
    var app = new Vue({
        el: '#app',
        components: {
            com: com
        },
        data: {
            msg: "组件"
        }
    })
</script>

动态组件与异步组件

动态组件

当我们希望动态的通过一个事件来改变需要显示组件对象时,即切换组件,我们采用的是这种方式:

<div id="app">
    <a href="" v-on:click.prevent="flag='login'">登录</a>
    <a href="" v-on:click.prevent="flag='register'">注册</a>
    <component :is="flag"></component>
</div>
  • 通过componentis属性来动态的更改,这也是组件切换的核心原理动态组件

动态组件的缓存

但是每次切换改变v-bind:is的值都会使重新生成虚拟DOM树并挂载。我们希望当数值未发生更改时,它能够被缓存起来,不需要每次都去重新渲染。

使用<keep-alive>标签可以实现这一需求

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。

例:

Vue.component('async-example', function (resolve, reject) {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
})

这个回调函数resolve会在你从服务器得到组件定义的时候被调用。

  • resolve接受回调组件
  • reject表示调用失败后

而这样的方式去获取组件能够使用的场景时十分有局限性的。而Vue官网推荐我们使用webpack规范的导入来实现这个获取组件的过程。

Vue.component('example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

你也可以在工厂函数中返回一个 Promise,所以把 webpack 2 和 ES2015 语法加在一起,我们可以这样使用动态导入:

Vue.component(
  'async-webpack-example',
  // 这个动态导入会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值