Vue组件传值
目前流行组件化开发,vue组件间传值是一个非常常用的功能,有时候仅仅是父子和兄弟之间简单的传值,我们就没有必要直接引入vuex来进行管理。
1.父子间传值
1.1 子组件向父组件传值
子组件通过触发事件给父组件的方式进行传值
我们先来看一个右侧划出分享链接的例子。
首先我们来看一下需求,我们需要点击按钮后,右侧出现一个弹窗。先创建一下基本的页面。
我们可以调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件:
<template>
<v-app class="demo-wrapper">
<v-flex xs12>
<v-card
dark
color="primary"
>
<v-card-text class="px-0 card-content">
这是一些展示性的demo
</v-card-text>
</v-card>
</v-flex>
<v-btn color="info" class="click-button">点我</v-btn>
</v-app>
</template>
然后我们写一下右侧划出的组件的样式
<template>
<div class="wrapper">
<span class="title">
文件转发
</span>
<hr>
<div class="share-file">
<div class="share-file-option">
<span class="share-file-option-text">
转发形式:
</span>
<VRadioGroup
v-model="radioGroup"
:disabled="isCreate"
class="share-file-option-radio"
>
<VRadio
:label="`不加密任何人访问链接即可查看、下载`"
:value="0"
/>
<VRadio
:label="`输入提取密码才能查看、下载,更加私密安全`"
:value="1"
/>
</VRadioGroup>
</div>
<div class="secret">
<div class="secret-expire">
<span class="secret-expire-text">
有效期:
</span>
<span class="secret-expire-text-day">
7天过后即失效
</span>
<VBtn
color="#2F9AFF"
class="secret-expire-link-button"
:style="canCreate"
@click="handleCreateLink"
>
创建链接
</VBtn>
</div>
<div
v-if="isCreate"
class="share-info"
>
<div class="link-wrapper">
<div class="secret-qcode">
<!-- <img
src="https://i.loli.net/2018/12/20/5c1b2a3dc2f67.png"
alt=""
> -->
<VueQRCodeComponent
:size="size"
:text="qrCode"
class="secret-qcode-content"
/>
</div>
<p class="secret-copy-text">
分享链接已复制
</p>
<p class="secret-copy-text-info">
通过QQ、微信、微博、QQ空间转发给好友吧
</p>
</div>
<div class="share-link">
<input
class="share-link-input"
type="text"
:placeholder="this.qrCode!==''?this.qrCode: 'https://www.baidu.com...7天有效'"
>
<div
v-clipboard:copy="qrCode"
v-clipboard:success="onCopy"
class="share-link-copy"
>
复制链接
</div>
</div>
</div>
</div>
<div
v-if="radioGroup === 1 && isCreate === true"
class="share-info-wrapper"
>
<div class="share-info-wrapper-pass">
<span class="share-info-wrapper-text">
提取密码:
</span>
<input
v-model="fileKey"
type="text"
class="share-info-wrapper-input"
>
</div>
<CancelButton
class="share-info-wrapper-cancel-btn"
@click="handleCancel"
/>
</div>
<CancelButton
v-if="radioGroup !== 1 || isCreate===false"
class="share-info-wrapper-cancel-btn cancelBtn"
@click="handleCancel"
/>
</div>
</div>
</template>
然后我们在父组件中注册FileShare这个组件
import FileShare from '@/demo/FilePreview'
export default {
components: {
FileShare
}
}
<v-btn color="info" class="click-button">点我</v-btn>
<FileShare/>
然后就可以看到这个刚刚引入的组件了。
分享组件
现在我们需要通过点击'点我'按钮,使这个组件出现。我们首先要给组件一个判断是否出现的状态。
data () {
return {
canShow: false
}
}
<FileShare v-if="canShow"/>
我们通过按钮的点击事件,将canShow变为true,让组件出现
handleClick () {
this.canShow = true
}
我们的需求是点击子组件的取消按钮,将父组件中的canShow变为false,我们需要通过自定义事件来实现。
我们先给子组件绑定自定义事件'handleSlide'
<FileShare @handleSlide="handleSlide" v-if="canShow"/>
接着,在子组件'取消’按钮的事件中,加下如下代码
handleCancel () {
this.$emit('handleSlide', 'close')
},
然后再父组件中定义handleSlide事件:
handleSlide (msg) {
console.log('in handleSlide')
console.log(msg)
this.canShow = false
}
当我们点击取消按钮后,子组件会消失,同时我们可以从控制台接收到刚刚在子组件传过来的'close'.
接收到的事件的值
1.2 父组件向子组件传值
父组件通过prop向子组件传值,Prop是你可以在组件上注册的一些自定义特性。当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性。一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
我们通过一个自制button组件的方式来了解这一特性。
<template>
<button class="g-button" :class="{[`icon-${iconposition}`]:true}"
@click="$emit('click')">
<!-- <svg v-if="icon" class="icon"><use :xlink:href="`#i-${icon}`"></use></svg> -->
<g-icon class="icon" v-if="icon && !loading" :name="icon"></g-icon>
<g-icon class="loading icon" v-if="loading" name="loading"></g-icon>
<div class="content">
<slot></slot>
</div>
</button>
</template>
<script>
import Vue from 'vue'
import Icon from './icon'
Vue.component('g-icon', Icon)
export default {
}
</script>
<style lang="scss" scoped>
@keyframes spin {
0% { transform: rotate(0deg);}
100% {transform: rotate(360deg);}
}
.g-button{
font-size: var(--font-size);
height: var(--button-height);
padding: 0 1em;
font:inherit;
border-radius: var(--button-radius);
border: 1px solid var(--border-color);
background: var(--button-bg);
display: inline-flex;
justify-content: center;
align-items: center;
vertical-align: middle;
&:hover{
border-color: var(--border-color-hover);
}
&:hover{
background-color: var(--button-active-bg);
}
&:focus{
outline: none;
}
>.content{
order:2;
}
>.icon {
order:1;
margin-right: .1em;
}
&.icon-right {
> .icon{
order:2;
margin-left: .1em;
margin-right:0;
}
>.content{
order:1;
}
}
.loading {
animation: spin 2s infinite linear;
}
}
</style>
我们在引用组件后,向组件传递各种想要传递的值,如下代码:
<div class="box">
<g-button icon="setting">love js</g-button>
<g-button
icon="setting"
:loading="isLoading"
@click="isLoading = !isLoading"
>js love</g-button
>
<g-button icon="setting" iconposition="right">love js</g-button>
<g-button-group>
<g-button icon="left" iconposition="left">上一步 </g-button>
<g-button>more</g-button>
<g-button icon="right" iconposition="right">下一步</g-button>
</g-button-group>
</div>
然后,我们需要在子组件button中通过定义props来接受父组件传过来的值(可以定义props的默认值,类型以及validator来避免传过来的脏数据或者其他报错)
export default {
props: {
icon:{},
loading: {
type: Boolean,
default: false
},
iconposition:{
type: String,
default: 'left',
validator (value) {
return value === 'left' || value === 'right'
}
}
}
}
最终我们可以看到传过去值以后,button的变化:
button
2.兄弟组件传值
兄弟组件传值一般通过创建一个新的vue实例,然后通过这个vue实例进行事件的传递,通常也被称为事件总线。方法很简单,首先创建一个全局的Vue实例,然后某个组件提交一个‘事件1',另一个组件监听一下'事件1'.
我们首先创建搜索框和搜索选项两个组件
搜索框组件和搜索选项组件
<div class="wrapper">
<SearchWrapper class="searchWrapper" />
<SearchInfo class="searchInfo" />
</div>
搜索框
<div class="wrapper">
<SearchBar class="search-bar"
@keyup.enter.native="handleSearch" />
<SearchButton content="搜索"
class="search-button"
@click.native="handleSearch" />
</div>
搜索选项
<div class="wrapper">
<ul>
<li class="li-content">
<span class="title">
常用搜索
</span>
<span v-for="(item,index) of hotKeys"
:key="index+item+index"
class="search-word"
@click="handleSearchWord(item)">
{{ item }}
</span>
</li>
<li class="li-content">
<span class="title">
时间选择
</span>
<ElDatePicker v-model="startDate"
size="small"
type="date"
placeholder="选择日期"
class="datePicker"
@change="handleStartChange" />
<ElDatePicker v-model="endDate"
size="small"
type="date"
placeholder="选择日期"
class="datePicker-end"
@change="handleEndChange" />
</li>
</ul>
</div>
然后我们需要新建一个全局的vue实例
import Vue from "vue"
export default new Vue()
然后在搜索信息组件和搜索框组件中引用这个vue实例。
在搜索信息组件中我们给开始时间和结束时间绑定了change事件,在值发生变化后,通过eventVue事件触发方式,将值传递出去
import eventVue from '@/apis/eventVue'
export default {
data () {
return {
startDate: '',
endDate: ''
}
}
methods: {
handleStartChange () {
console.log('传递出去开始时间')
if (this.startDate !== '') {
eventVue.$emit('changeStart', formatDate(this.startDate))
}
},
handleEndChange () {
console.log('传递出去结束时间')
if (this.startDate !== '') {
eventVue.$emit('changeEnd', formatDate(this.endDate))
}
},
}
}
然后我们在搜索框组件中来接收这些事件(在按下搜索按钮后接收),首先我们先要定义一下接收的值,同时也要引用一下eventVue实例。
import eventVue from '@/apis/eventVue'
export default {
data () {
return {
startDate: '',
endDate: ''
}
},
methods: {
handleSearch () {
eventVue.$on('changeStart', (date) => {
this.startDate = date
}
})
eventVue.$on('changeEnd', (date) => {
this.endDate = date
})
console.log('刚刚接收到的开始时间')
console.log(this.startDate)
console.log('刚刚接收到的结束时间')
console.log(this.endDate)
}
}
}
传递和接收的值