IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    通过案例,彻底理解 Vue 中的 sync 修饰符

    小鱼发表于 2023-10-03 15:57:39
    love 0

    sync 修饰符是一个非常重要的知识点,将页面拆分成一个个组件的时候就经常用到 sync 修饰符。比如你做过 vue+element-ui 的管理系统,要对分页组件拆分成一个独立的子组件这个时候一定会使用到 sync 修饰符

    为了深入理解,我们需要两个组件 myDialog.vue(对话框组件) 与 test.vue。其中 myDialog.vue 为子组件, test.vue为父组件。需要完成的功能:当我们点击父组件的显示按钮会弹出对话框组件。并且当我们点对话框的“确定”或“取消”按钮也要将子组件隐藏。实际效果就是模仿 element-ui 制作一个自己的 dialog 组件。

    • myDialog.vue 子组件
    <template>
      <div>
        <div>
          <h1>Hello</h1>
          <div>
            <button>取消</button>
            <button>确定</button>
          </div>
        </div>
      </div>
    </template>
    ​
    <script>
    export default {
      name: 'myDialog',
    }
    </script>
    • test.vue 父组件
    <template>
      <div>
        <button>点击显示对话框</button>
        <my-dialog />
      </div>
    </template>
    ​
    <script>
    import myDialog from './myDialog'
    export default {
      name: 'test',
      components: {
        myDialog,
      },
    }
    </script>

    解决思路:

    • 我们要在父组件中定义一个 isShow 变量默认值为false,并将 isShow 传给对话框组件,整个对话框的显示和隐藏都是由父组件的 isShow 来决定
    • 点击父组件的显示按钮将 isShow 进行取反。
    • 那么点击对话框的“确定”或者“显示”的时候我们就需要改变父组件的 isShow。(给对话框的按钮绑定点击事件,点击利用 发出一个 update 事件)

    补充:你可能会想在子组件中直接修改,父组件传过来的 isShow 岂不是更加简单。但是父组件传给子组件的 prop 是单向数据流,数据是只读的,不允许修改。强行修改不仅没有效果并且控制台会报错

    所以代码可以修改如下:

    <!-- 父组件 -->
    <template>
      <div>
        <button id="btn" @click="isShow = !isShow">点击显示对话框</button>
        <my-dialog :isShow="isShow" @update="isShow = $event" />
      </div>
    </template>
    ​
    <script>
    import myDialog from './myDialog'
    export default {
      name: 'test',
      data() {
        return {
          isShow: false,
        }
      },
      components: {
        myDialog,
      },
    }
    </script>
    ​
    <!-- 对话框组件 -->
    <template>
      <div id="test" v-show="isShow">
        <div class="box">
          <h1>Hello</h1>
          <div>
            <button @click="updateShow">取消</button>
            <button @click="updateShow">确定</button>
          </div>
        </div>
      </div>
    </template>
    ​
    <script>
    export default {
      name: 'myDialog',
      props: {
        isShow: {
          type: Boolean,
          default() {
            return false
          },
        },
      },
      methods: {
        
      },
    }
    </script>

    关于事件中的 $event

    • 如果是js原生事件,那么 $event 为”事件对象“。
    • 如果是子组件利用 $emit() 发出的自定事件,那么 $event 表示自定义事件传过来的参数
    • 所以如上代码可以直接在组件标签上进行赋值:@update="isShow = $event"

    为了更加能够语义化,更加清楚的表示需要修改的数据,可将部分代码修改如下:

    • 子组件
      • updateShow() {
        //你可以将添加的 :isShow 理解为标识
        //这也是在 sync 做铺垫,要使用 sync 子组件比如遵从如下写法(‘update:xx’)
        this.$emit(‘update:isShow’, !this.isShow)
        },
    • 父组件
      • <!– 监听子组件发出的事件也要携带 :isShow 标识 –>
        <my-dialog :isShow=”isShow” @update:isShow=”isShow = $event” />
    • 补充:这里的 update:xx 其中 update 其实不是固定写法,你也可以换成其他字符,比如 u:xx,父子组件都要同时改为 u 。但是!!当你使用 sync 修饰符的时候 update: 就是一个固定的写法,为了方便 update: 我们一般都认为这是固定的写法,不管有没有使用 sync 修饰符

    sync 修饰符:

    sync 修饰符就是用于简化父组件 @update:isShow="isShow = $event" 这一行代码而诞生的。

    使用:

    <my-dialog :isShow.sync="isShow" />

    使用了 sync 修饰符,vue会自动帮你编译出 @update:isShow="isShow = $event" 这一行代码。

    注意!!子组件中的写法还是一样需要携带标识:this.$emit('update:isShow', !this.isShow)

    通过如上的分析你现在一定能理解 element-ui 中 dialog 组件为什么会使用 :visible.sync=""。你也能写出与 element-ui 类似的组件

    <el-dialog
      :visible.sync="dialogVisible"
    </el-dialog>

    最终完整代码

    <!-- 父组件 -->
    <template>
      <div>
        <button id="btn" @click="isShow = !isShow">点击显示对话框</button>
        <my-dialog :isShow.sync="isShow" />
      </div>
    </template>
    <script>
    import myDialog from './myDialog'
    export default {
      name: 'test',
      data() {
        return {
          isShow: false,
        }
      },
      components: {
        myDialog,
      },
    }
    </script>
    ​
    <style>
    #btn {
      background-color: sandybrown;
      color: #fff;
      border: none;
      margin: 50px;
      height: 35px;
      padding: 0 20px;
    }
    </style>
      
    <!-- 子组件 -->
    <template>
      <div id="test" v-show="isShow">
        <div class="box">
          <h1>Hello</h1>
          <div>
            <button @click="updateShow">取消</button>
            <button @click="updateShow">确定</button>
          </div>
        </div>
      </div>
    </template>
    ​
    <script>
    export default {
      name: 'myDialog',
      props: {
        isShow: {
          type: Boolean,
          default() {
            return false
          },
        },
      },
      methods: {
        updateShow() {
          this.$emit('update:isShow', !this.isShow)
        },
      },
    }
    </script>
    ​
    <style>
    #test {
      position: absolute;
      z-index: 10px;
      background-color: rgba(0, 0, 0, 0.3);
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
    }
    #test .box {
      width: 400px;
      height: 300px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      box-shadow: 1px 1px 10px #999;
      background-color: #fff;
    }
    #test .box div {
      position: absolute;
      bottom: 0;
      right: 0;
    }
    #test .box div button {
      width: 80px;
      height: 35px;
      margin-right: 10px;
      border: none;
    }
    </style>


沪ICP备19023445号-2号
友情链接