Vue组件传值

作者: 西域战神 | 来源:发表于2019-01-24 15:51 被阅读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)
       }
     }
    }
    
    传递和接收的值

    相关文章

      网友评论

        本文标题:Vue组件传值

        本文链接:https://www.haomeiwen.com/subject/votujqtx.html