饥人谷技术博客

Vue组件传值

2019-01-24  本文已影响41人  西域战神

目前流行组件化开发,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">
          &nbsp;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)
   }
 }
}
传递和接收的值
上一篇下一篇

猜你喜欢

热点阅读