【vue】组件复用:父子组件传值记录

【代码背景】

        前端工作中经常需要用到相似的功能模块,例如对话框,大量重复单个页面的做法虽然简单粗暴但既不符合代码复用的指导原则也不利于后期维护,更重要的是浪费时间且不优雅,因此可以把大量的重复功能模块封装成一个组件,要使用的时候直接引用就可以了。

【代码目标】

        实现两个页面:HomePage.vue和NavBar.vue共用一个修改用户密码的对话框ModifyPswd.vue,并实现父->子以及子->父的双向传值。

【代码实现】

ModifyPswd.vue

<template>
  <!-- 对话框-用户修改密码 -->
  <el-dialog title="修改密码" :visible.sync="modifyPswdDialogVisible" width="35%" @close="closeDialog">
    <el-form ref="modifyPswdFormRef" :model="modifyPswdForm" :rules="modifyPswdFormRules" label-width="120px">
      <el-form-item label="工号">
        <el-input v-model="modifyPswdForm.user_id" disabled style="width: 280px" />
      </el-form-item>
      <el-form-item label="姓名" prop="user_name">
        <el-input v-model="modifyPswdForm.user_name" disabled style="width: 280px" />
      </el-form-item>
      <el-form-item label="旧密码" prop="old_pswd">
        <el-input v-model="modifyPswdForm.old_pswd" style="width: 280px" type="password" clearable />
      </el-form-item>
      <el-form-item label="新密码" prop="new_pswd">
        <el-input v-model="modifyPswdForm.new_pswd" style="width: 280px" type="password" clearable />
      </el-form-item>
      <el-form-item label="再输入密码" prop="new_pswd_ag">
        <el-input v-model="modifyPswdForm.new_pswd_ag" style="width: 280px" type="password" clearable />
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="cancelmodifyPassword">取 消</el-button>
      <el-button type="primary" @click="modifyPassword">确 定</el-button>
    </span>
  </el-dialog>
</template>
<script>
  export default {
    name: 'Index',
    props: {
      isOpen: {
        type: Boolean,
        default () {
          return false
        }
      }
    },
    data () {
      return {
        modifyPswdDialogVisible: false, // 用户修改密码框是否可见
        modifyPswdForm: {
          user_id: '',
          user_name: '',
          old_pswd: '',
          new_pswd: '',
          new_pswd_ag: ''
        },
        modifyPswdFormRules: { // 复杂密码验证规则
          old_pswd: [
            {
              required: true,
              validator: this.validatePass,
              change: 'blur'
            }
          ],
          new_pswd: [
            {
              required: true,
              validator: this.validatePass,
              change: 'blur'
            }
          ],
          new_pswd_ag: [
            {
              required: true,
              validator: this.validatePass2,
              change: 'blur'
            }
          ]
        }
      }
    },
    watch: {
      isOpen (val) {
        this.modifyPswdDialogVisible = val// 监听变更并同步到modifyPswdDialogVisible上
      }
    },
    created () {
      console.log('子组件开始加载')
      console.log(this.isOpen)
      this.modifyPswdForm.user_id = window.sessionStorage.getItem('user_id') // 填充工号
      this.modifyPswdForm.user_name = window.sessionStorage.getItem('user_name') // 填充姓名
      this.modifyPswdDialogVisible = this.isOpen
    },
    methods: {
      // 验证复杂密码
      validatePass (rule, value, callback) {
        // const regEn = /(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[\W_]).{8,12}/
        const regEn = /^(?![A-Za-z0-9]+$)(?![a-z0-9\W]+$)(?![A-Za-z\W]+$)(?![A-Z0-9\W]+$)[a-zA-Z0-9\W]{8,10}$/
        if (value === '') {
          callback(new Error('请输入密码'))
          // password 是表单上绑定的字段
        } else if (!regEn.test(value)) {
          callback(new Error('必须包含数字、大写字母、小写字母、特殊符号,长度在8-10位!'))
        } else {
          callback()
        }
      },
      // 验证两次密码一致
      validatePass2 (rule, value, callback) {
        if (value === '') {
          callback(new Error('请再次输入密码'))
          // password 是表单上绑定的字段
        } else if (value !== this.modifyPswdForm.new_pswd) {
          callback(new Error('两次输入密码不一致!'))
        } else {
          callback()
        }
      },
      // 确认修改
      modifyPassword () {
        this.$refs.modifyPswdFormRef.validate(async (valid) => {
          if (valid) {
            alert('调用接口修改密码!')
            // 修改密码成功后
            // 关闭修改对话框
            this.modifyPswdDialogVisible = false
            // 执行退出
            await this.$store.dispatch('user/logout')
            this.$router.push(`/login`)
          }
        })
      },
      // 取消修改
      cancelmodifyPassword () {
        this.$refs.modifyPswdFormRef.resetFields()
        this.modifyPswdDialogVisible = false
      },
      // 通知父组件已关闭对话框
      closeDialog () {
        this.$emit('close')
      }
    }
  }
</script>

HomePage.vue

<template>
  <div class="dashboard-container">
    <el-button type="primary" @click="modifyPswd">打开对话框</el-button>
    <!--修改用户密码对话框-->
    <modify-pswd :is-open="modifyPswdDialogVisible" @close="closeDialog" />
  </div>
</template>
<script>
  import ModifyPswd from '@/components/ModifyPswd/index'
  export default {
    name: 'HomePage',
    components: {
      'modify-pswd': ModifyPswd
    },
    data () {
      return {
        // - 对话框 -
        modifyPswdDialogVisible: false // 修改密码框是否可见
      }
    },
    created () {},
    methods: {
      // 修改用户密码
      modifyPswd () {
        this.modifyPswdDialogVisible = true // 打开修改密码框
      },
      // 关闭对话框
      closeDialog () {
        this.modifyPswdDialogVisible = false // 关闭修改密码框
      }
    }
  }
</script>

NavBar.vue

<template>
  <div class="navbar">
    <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />

    <breadcrumb class="breadcrumb-container" />

    <div class="right-menu">
      <el-dropdown class="avatar-container">
        <span>你好!{{ user_name }}<i class="el-icon-caret-bottom" /></span>
        <el-dropdown-menu slot="dropdown" class="user-dropdown">
          <el-dropdown-item @click.native="modifyPsd">
            <span style="display:block;">修改密码</span>
          </el-dropdown-item>
          <el-dropdown-item divided @click.native="logout">
            <span style="display:block;">退出</span>
          </el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
    </div>

    <!--修改用户密码对话框-->
    <modify-pswd :is-open="modifyPswdDialogVisible" @close="closeDialog" />
  </div>
</template>
<script>
  import { mapGetters } from 'vuex'
  import Breadcrumb from '@/components/Breadcrumb'
  import Hamburger from '@/components/Hamburger'
  import ModifyPswd from '@/components/ModifyPswd/index'

  export default {
    components: {
      Breadcrumb,
      Hamburger,
      'modify-pswd': ModifyPswd
    },
    data () {
      return {
        user_name: '',
        modifyPswdDialogVisible: false // 修改密码框是否可见
      }
    },
    computed: {
      ...mapGetters([
        'sidebar'
      ])
    },
    created () {
      this.user_name = window.sessionStorage.getItem('user_name')
    },
    methods: {
      toggleSideBar () {
        this.$store.dispatch('app/toggleSideBar')
      },
      // 退出
      async logout () {
        await this.$store.dispatch('user/logout')
        this.$router.push(`/login`)
      },
      // 修改密码
      modifyPsd () {
        this.modifyPswdDialogVisible = true // 打开修改密码框
      },
      // 关闭对话框
      closeDialog () {
        this.modifyPswdDialogVisible = false // 关闭修改密码框
      }
    }
  }
</script>

【重点说明】

1、父页面引入子组件

import ModifyPswd from '@/components/ModifyPswd/index'

2、注册子组件

components: {
      'modify-pswd': ModifyPswd
},

3、使用子组件

<modify-pswd :is-open="modifyPswdDialogVisible" @close="closeDialog" />

4、父组件给子组件传值:父组件通过:is-open="modifyPswdDialogVisible" 绑定对话框是否打开,注意这里的modifyPswdDialogVisible是父组件的data值,子组件通过props来接收isOpen

props: {
      isOpen: {
        type: Boolean,
        default () {
          return false
        }
      }
    },

然后通过赋值控制对话框的打开关闭事件

this.modifyPswdDialogVisible = this.isOpen

注意这里的modifyPswdDialogVisible是子组件的data值。

这里还有一点值得注意的是,最开始直接在子组件绑定isOpen来控制打开关闭事件

官方表示不建议这么做,因为isOpen是从父组件传过来的值,是个单向传值不允许被重写,因此这里还是改成重新赋值的方式比较好哦。

5、子组件给父组件传值:到目前为止,父组件成功通知子组件打开了对话框,但是关闭对话框以后,发现再点击按钮是打不开对话框的,因为子组件自己关闭以后并没有通知父组件他已经关闭了,父组件的modifyPswdDialogVisible从false变成true之后就一直维持这个状态了,所以在子组件的对话框关闭的时候需要通知父组件。

在子组件中的dialog添加一个@close事件

     // 子组件的close事件,通知父组件调用子组件的close方法
      closeDialog () {
        this.$emit('close')
      }

 使用this.$emit通知调用父组件的“close”方法

// 父组件的close事件
closeDialog () {
    this.modifyPswdDialogVisible = false // 关闭修改密码框
}

 【小结】

 【参考】

基于Vue如何封装组件 https://www.bilibili.com/video/BV1fZ4y1K7WC

感谢B站大佬免费分享~大部分知识都源于B站

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值