具有可选值prop

时间:2019-05-24 20:20:23

标签: vue.js

我正在编写一个可重用的组件。这基本上是一个包含标题和正文的部分,如果单击标题,正文将展开/折叠。

我想允许组件的使用者使用v-model将布尔值绑定到它,以便它可以在所需的任何条件下展开/折叠,但是在我的组件内,用户可以单击以展开/崩溃。

我已经开始工作了,但是它要求组件的用户使用v模型,如果他们不使用,则该组件将无法工作。

我实质上希望消费者决定他们是否关心能够查看/更改组件的状态。如果没有,则不必向组件提供v-model属性。

这是我组件的简化版本:

<template>
    <div>
        <div @click="$emit('input', !value)">            
            <div>
                <slot name="header">Header</slot>
            </div>
        </div>
        <div :class="{ collapse: !value }">        
            <div class="row">
                <div class="col-xs-12">
                    <div>
                        <slot></slot>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script lang="ts">
    import { Vue, Component, Prop } from "vue-property-decorator";   


    @Component
    export default class CollapsibleSection extends Vue {
        @Prop({ default: true }) public value: boolean;
    }
</script>

更新:

我想出了一个可以在功能上满足我的要求的解决方案。它比我想要的要冗长一些,因此,如果有人有一个更简洁的解决方案,我希望阅读一下,如果它能以较少的代码/标记满足我的要求,我将很高兴将其标记为可接受的答案。 >

<template>
    <div>
        <div @click="toggle">            
            <div>
                <slot name="header">Header</slot>
            </div>
        </div>
        <div :class="{ collapse: !currentValue }">        
            <div class="row">
                <div class="col-xs-12">
                    <div>
                        <slot></slot>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script lang="ts">
    import { Vue, Component, Prop, Watch } from "vue-property-decorator";   


    @Component
    export default class CollapsibleSection extends Vue {
        @Prop({ default: true }) public value: boolean;

        public currentValue = true;

        public toggle() {
            this.currentValue = !this.currentValue;
            this.$emit('input', this.currentValue);
        }

        public mounted() {
            this.currentValue = this.value;
        }

        @Watch('value')
        public valueChanged() {
            this.currentValue = this.value;
        }
    }
</script>

1 个答案:

答案 0 :(得分:1)

您的更新有效并且总体上具有正确的要旨,但是最好使用计算属性而不是监视程序。有关更多信息,请参见the docs for computed properties and watchers

我在下面的代码段中排除了类符号,以便使其可以在现场运行。

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

  <nav class="navbar navbar-expand-sm navbar-dark bg-dark fixed-top">
  <a class="navbar-brand " href="#">Example</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
      <div class="collapse navbar-collapse justify-content-center" id="navbarNavDropdown">
          <ul class="navbar-nav">
            <li class="nav-item active mx-2">
              <a class="nav-link" href="index.html">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item dropdown mx-2">
              <a class="nav-link dropdown-toggle" href="#" id="DropDown1" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Link 1</a>
              <div class="dropdown-menu" aria-labelledby="DropDown1">
                <a class="dropdown-item" href="#">Dropdown1</a>
                <a class="dropdown-item" href="#">Dropdown2</a>
                <a class="dropdown-item" href="#">Dropdown3</a>
                <a class="dropdown-item" href="#">Dropdown4</a>
              </div>
            </li>
            <li class="nav-item dropdown mx-2">
              <a class="nav-link dropdown-toggle" href="#" id="DropDown2" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Link2</a>
              <div class="dropdown-menu" aria-labelledby="DropDown2">
                <a class="dropdown-item " href="#">Dropdown1 <span class="sr-only">(current)</span></a>
                <a class="dropdown-item" href="#">Dropdown2</a>
                <a class="dropdown-item" href="#">Dropdown3</a>
                <a class="dropdown-item" href="#">Dropdown4</a>
                <a class="dropdown-item" href="#">Dropdown5</a>
                <a class="dropdown-item" href="#">Dropdown6</a>
                <a class="dropdown-item" href="#">Dropdown7</a>
                <a class="dropdown-item" href="#">Dropdown8</a>
              </div>
            </li>
            <li class="nav-item mx-2">
              <a class="nav-link" href="#">Link3</a>
            </li>
            <li class="nav-item mx-2">
              <a class="nav-link" href="#">Link4</a>
            </li>
            <li class="nav-item mx-2">
              <a class="nav-link" href="#">Link5</a>
            </li>
            <li class="nav-item mx-2">
              <a class="nav-link" href="#">Link6</a>
            </li>
          </ul>
        </div>
  </nav>
    <header>
    </header>
    <main>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer faucibus quam eros, quis elementum metus suscipit quis. Etiam ultrices pharetra diam, sed tempus mauris tincidunt sit amet. Vivamus vestibulum sollicitudin bibendum. Nam egestas, lectus vitae semper blandit, elit sapien venenatis diam, quis vehicula sem neque vel tellus. Suspendisse nec venenatis metus, ac blandit lacus. Etiam eu velit convallis, auctor turpis eget, faucibus orci. Vestibulum ac justo porta, congue lectus fringilla, sagittis metus. Sed orci velit, placerat eu interdum eget, volutpat in urna. Fusce quis tellus non lorem imperdiet blandit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>

<p>Aliquam aliquam commodo nulla, nec porta augue efficitur a. Etiam maximus, ligula vitae feugiat malesuada, magna est ultricies nunc, sit amet efficitur metus metus vel lectus. Nunc eleifend orci nec orci faucibus congue. In sodales pretium tempor. Pellentesque sed risus risus. Aenean vulputate euismod eleifend. Donec vitae tincidunt felis, quis euismod neque. Nam at urna convallis, tincidunt arcu quis, commodo urna. Quisque ultrices interdum erat vel suscipit. Morbi sed ex dignissim, posuere elit ac, sodales est.</p>

<p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Nunc dictum ac purus at accumsan. Ut consequat efficitur nisi. Nam tempor, justo at tempus pretium, nunc dolor iaculis magna, eget mattis sapien metus nec neque. Quisque consequat dolor lacus. Fusce vestibulum accumsan arcu eget varius. Suspendisse rutrum elit felis, at bibendum neque sagittis non. Aliquam ut nibh eget mi eleifend congue quis eleifend turpis. Etiam placerat scelerisque enim, ut dictum magna tempor sed. Ut tempus, ante sed vehicula porttitor, justo lectus malesuada est, sed suscipit nisl metus ac lorem. Duis hendrerit sodales risus id laoreet. Aenean quis felis eu diam lobortis gravida. Aenean sem mi, sodales vel dictum eget, malesuada quis lacus.</p>

<p>Phasellus quis augue magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse a sagittis ante. Nunc rutrum lacus imperdiet, varius ipsum ut, tempus dui. Donec vel ligula lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin semper augue ut nisi rutrum, vitae eleifend nisl gravida. Etiam cursus turpis pulvinar, finibus tortor pretium, fringilla libero. Vivamus tempus feugiat orci eget facilisis. Etiam efficitur dapibus porta. Vivamus venenatis leo mauris. Donec eleifend mi a enim sagittis sollicitudin.</p>

<p>Cras sed mollis neque. Nam nibh purus, commodo quis sem in, porta egestas erat. Praesent eleifend venenatis sem, in pulvinar est dignissim in. Mauris nulla augue, laoreet vel tortor at, accumsan pharetra urna. Sed a volutpat metus. Praesent cursus turpis id augue venenatis, nec dapibus tortor molestie. Maecenas tincidunt, velit at tincidunt pretium, purus urna tempor sapien, vitae efficitur nisi sem eu erat. Praesent in ullamcorper turpis. Nullam bibendum mi vel nibh egestas pellentesque.</p>
    </main>
    <footer>
    </footer>
Vue.component('expandable', {
  props: {
    value: {
      // Just to be explicit, not required
      default: undefined,
      validator(value) {
        return typeof value === 'boolean' || typeof value === 'undefined';
      },
    },
  },
  template: `
    <div class="expandable">
      <p @click="toggle()">toggle</p>
      <slot v-if="isOpen" />
    </div>
  `,
  data() {
    return {
      internalValue: true,
    };
  },
  computed: {
    isOpen() {
      return (typeof this.value !== 'undefined') ? this.value : this.internalValue;
    },
  },
  methods: {
    toggle() {
      this.internalValue = !this.internalValue;
      this.$emit('input', !this.isOpen);
    }
  }
});

new Vue({
  el: '#app',
  data() {
    return {
      isOpen: false,
    }
  }
})
.expandable {
  border: 2px solid blue;
  margin-bottom: 1rem;
}