【问题标题】:How To Check A Radio Button in Vue.JS 2 WITHOUT using v-model如何在不使用 v-model 的情况下检查 Vue.JS 2 中的单选按钮
【发布时间】:2019-08-12 09:38:49
【问题描述】:

我正在尝试在 Vue.JS 2 中设置单选按钮列表的选中值。我在这里查看了现有文章并尝试了它们以及几种不同的手动方法,但我根本无法让它工作。

我在这里没有使用 v-model,因为我正在处理表单构建器使用的自定义单选按钮列表控件。由于我正在构建一个嵌套的单选按钮列表来处理可为空的布尔值,这一事实使情况变得更加复杂。抛开复杂性不谈,我的无线电组件看起来像这样......

<template>
  <div class="form__radio-list">
    <span class="form__radio-list__intro">{{ introText }}</span>
    <ul class="form__radio-list__options">
      <li v-for="item in options"
          :key="item.key ? item.key : item"
          class="form__radio-list__options__item">
        <input type="radio"
               :id="item.key ? item.key.toKebabCase() : item.toKebabCase()"
               :name="def"
               :value="item.value != undefined ? item.value : item"
               :disabled="disabled"
               :checked="isChecked(item)"
               @input="onInput"
               @change="$emit('change', $event.target.checked)">
        <label :for="item.key ? item.key : item">{{ item.text ? item.text : item }}</label>
      </li>
    </ul>
  </div>
</template>

<script>

export default {

    props: {
        def: {
            type: String,
            required: true
        },
        introText: {
            type: String,
            default: ''
        },
        options: {
            type: Array,
            required: true
        },
        initialValue: {
            type: [String, Number, Boolean],
            default: null
        },
        disabled: {
            type: Boolean,
            default: false
        }
    },

    data() {
        return {
            value: this.initialValue
        }
    },

    methods: {

        _parseValue() {
            return this.value ? parseInt(this.value) : null
        },

        isChecked(item) {
            const checked = item.value === this.value || item === this.value || item.value == this._parseValue()
            this.$logger.logObject({ item, parentValue: this.value, checked }, 'Checking value for an item')
            return checked
        },

        onInput($event) {
            this.value = $event.target.checked
            this.$emit('input', $event.target.checked)
        }
    }
}

</script>

从日志中我可以看到“checked”的值应该设置正确(但不是)。

我还尝试将输入标记拆分为“v-if”语句,这样我就有一个带有已检查参数集,而一个没有(虽然这感觉很糟糕),并且从 HTML 的角度来看是有效的(已检查 = “已选中”出现在我期望的位置)但是,在浏览器上,这两个选项都没有被选中。

我正在通过一个看起来像这样的布尔组件渲染器使用该组件...

<template>
  <hh-radio class="form__radio-list--yes-no"
            :def="def"
            :intro-text="introText"
            :options="options"
            :initial-value="initialValue"
            :disabled="disabled"
            @change="$emit('change', $event)"
            @input="$emit('input', $event)" />
</template>

<script>

export default {

    props: {
        def: {
            type: String,
            required: true
        },
        introText: {
            type: String,
            default: ''
        },
        initialValue: {
            type: [String, Boolean],
            default: null
        },
        disabled: {
            type: Boolean,
            default: false
        }
    },

    computed: {

        options() {
            return [{
                key: 'yes',
                text: 'Yes',
                value: true
            }, {
                key: 'no',
                text: 'No',
                value: false
            }]
        }
    }
}

</script>

然后最终以这样的形式消费...

  <hh-yes-no class="editable-segment-field__bool"
             :def="pvc-enabled"
             :initial-value="pvc.value"
             @input="onInput" />

值传递似乎工作正常 - 我遇到的关键问题是它不会从任何现有数据中指定当前选定的项目。

我在这里尝试过建议 - Vue.JS radio input without v-model 和这里 - Vue.JS checkbox without v-model,但没有取得多大成功。

使用下面给出的示例,我已尝试尽可能地将其剥离,在确定问题根源时添加组件中的动态元素。

我现在有一个更简单的组件,看起来像这样......

<template>
  <div :class="`form__radio-list ${(this.def ? `form__radio-list--${this.def} js-${this.def}` : '' )}`">
    <span class="form__radio-list__intro">{{ introText }}</span>
    <ul class="form__radio-list__options">
      <li class="form__radio-list__options__item">
        <input id="awesome"
               type="radio"
               name="isawesome"
               :checked="radio === 'Awesome'"
               value="Awesome"
               @change="radio = $event.target.value">
        <label for="awesome">Awesome</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="super"
               type="radio"
               name="isawesome"
               :checked="radio === 'Super Awesome'"
               value="Super Awesome"
               @change="radio = $event.target.value">
        <label for="super">Super</label>
      </li>
    </ul>
    <span>Selected: {{ value }} | {{ radio }}</span>
  </div>
</template>

<script>

export default {

    props: {
        def: {
            type: String,
            required: true
        },
        introText: {
            type: String,
            default: ''
        },
        initialValue: {
            type: [String, Boolean],
            default: null
        },
        disabled: {
            type: Boolean,
            default: false
        }
    },

    // delete this
    data() {
        return {
            value: this.initialValue,
            radio: 'Awesome'
        }
    },

    computed: {

        options() {
            return [{
                key: 'yes',
                text: 'Yes',
                value: true
            }, {
                key: 'no',
                text: 'No',
                value: false
            }]
        }
    }
}

</script>

一旦我将name="isawesome" 添加到单选按钮项目中,我就设法让它失败。似乎当您引入“名称”时,出现了问题。当然,我需要“名称”来防止多个单选按钮列表相互交互,或者这是我不知道的 Vue 处理的东西。

【问题讨论】:

  • 它是 html:当您拥有具有(相同)name attr 的收音机时,您定义一个隐式收音机组,其中最大 1 可以在给定时间检查 mdn-doc/input/radio
  • 是的@birdspider,这就是为什么我想在我的通用单选列表组件上命名,这样我就可以在每个页面上有多个单选按钮列表。问题是没有项目会检查是否指定了名称。

标签: vue.js vuejs2


【解决方案1】:

这是一个工作示例:

new Vue({
  el: "#app",
  data: {
   radio: 'Awesome'
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <span>Vue is:</span> <br>

  <label>Awesome
  <input 
    type="radio"
    :checked="radio === 'Awesome'" 
    value="Awesome"
    @change="radio = $event.target.value"
  >
  </label>
  
   <label>Super Awesome
  <input 
    type="radio" 
    :checked="radio === 'Super Awesome'"
    value="Super Awesome"
    @change="radio = $event.target.value"
  >
  </label>
  
  <hr>
  
  <span>Selected: {{radio}}</span>
</div>

【讨论】:

  • 我已经使用它通过操纵您的示例并合并我的元素来解决问题的根源,直到我可以让它再次失败 - 见上文。
  • 我没听懂你。我的例子工作正常。如果您无法调整更改,请创建一个 codepen、jsFiddle 或 codesandbox 示例,让我尝试使其工作。
  • 我无法在 Codepen 上复制它,因为它必须以不同的方式编写,而且当你这样做时,它似乎开始工作了! @birdspider 在另一个答案上做了一个很棒的模型,这很有效。我已经将代码几乎逐字逐句提取到模板文件中,但它不再起作用了。
  • 我在 Codepen codepen.io/tiefling/pen/eqoGgQ 上设置了它,它也可以工作,所以将它作为模板不是问题。我想知道 ES6 Babel 翻译是否在某个地方出现问题。
【解决方案2】:

这似乎是 Vue.js 的一个错误/奇怪之处。使用 roli roli 的示例,我能够同时采用他的示例和我的要求并不断调整,直到它们在中间相遇,这样我就可以通过消除过程找出问题。

这是包含两个元素的组件的副本。正如@birdspider 上面评论的那样,我不希望这可以在 HTML 中工作。然而,在 Vue 中,它确实......

<template>
  <div :class="`form__radio-list ${(this.def ? `form__radio-list--${this.def} js-${this.def}` : '' )}`">
    <span class="form__radio-list__intro">{{ introText }}</span>
    <ul class="form__radio-list__options">
      <li class="form__radio-list__options__item">
        <input id="yes"
               type="radio"
               :checked="value === true"
               :value="true"
               @change="value = $event.target.value">
        <label for="yes">Yes</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="no"
               type="radio"
               :checked="value === false"
               :value="false"
               @change="value = $event.target.value">
        <label for="no">No</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="awesome"
               type="radio"
               :checked="radio === 'Awesome'"
               value="Awesome"
               @change="radio = $event.target.value">
        <label for="awesome">Awesome</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="super"
               type="radio"
               :checked="radio === 'Super Awesome'"
               value="Super Awesome"
               @change="radio = $event.target.value">
        <label for="super">Super</label>
      </li>
    </ul>
    <span>Selected: {{ value }} | {{ radio }}</span>
  </div>
</template>

<script>

export default {

    props: {
        def: {
            type: String,
            required: true
        },
        introText: {
            type: String,
            default: ''
        },
        initialValue: {
            type: [String, Boolean],
            default: null
        },
        disabled: {
            type: Boolean,
            default: false
        }
    },

    data() {
        return {
            value: this.initialValue,
            radio: 'Awesome'
        }
    }
}

</script>

这将完全正常并呈现为 2 个单独的单选按钮列表 - 一个代表是/否,一个代表真棒/超级棒。如果您尝试在单选输入中添加“名称”标签,那么单选按钮组中将不再设置选中状态。

---- 更新----

这似乎是一个错误,Vue 应该简单地忽略添加“名称”的尝试,但事实并非如此。但是,如果您在 codepen 中创建 ES5 样式组件,则情况并非如此(因此,我无法在 codepen 中重现此内容。)

使用 ES6 样式文件,此组件不会设置任何检查值(此简化示例的一半归功于 @birdspider)...

<template>
  <div>
    <ul class="form__radio-list__options">
      <li class="form__radio-list__options__item">
        <input id="awesome" type="radio" name="isawesome"
               :checked="radio === 'Awesome'"
               value="Awesome"
               @change="onChange($event.target.value)">
        <label for="awesome">Awesome</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="super" type="radio" name="isawesome"
               :checked="radio === 'Super Awesome'"
               value="Super Awesome"
               @change="onChange($event.target.value)">
        <label for="super">Super</label>
      </li>
    </ul>
    <ul class="form__radio-list__options">
      <li class="form__radio-list__options__item">
        <input id="awesome" type="radio" name="other"
               :checked="radio2 === 'other'"
               value="other"
               @change="onChange2($event.target.value)">
        <label for="awesome">other</label>
      </li>
      <li class="form__radio-list__options__item">
        <input id="super" type="radio" name="other"
               :checked="radio2 === 'another'"
               value="another"
               @change="onChange2($event.target.value)">
        <label for="super">another</label>
      </li>
    </ul>
  </div>
</template>

<script>

export default {

    data() {
        return {
            radio: 'Awesome',
            radio2: 'another'
        }
    },

    methods: {

        onChange(e) {
            this.radio = e
        },
        onChange2(e) {
            this.radio2 = e
        }
    }
}

</script>

(如果有人能告诉我如何让它像这样在 Codepen 或 JS Fiddle 中运行,那就太好了!)

如果我删除名称属性,那么它会起作用。

如果您在 Codepen 中将本质上相同的东西作为单个 Vue 实例而不是组件文件放入,那么它也可以。

【讨论】:

  • idk,但是拥有name 在这个mockup 中并没有做任何奇怪的事情,因为每个值更改都由vue@ 事件和 :checked 绑定处理
  • 如果您将“名称”属性添加到单选按钮,则在我上面的代码中初始加载时不会设置选中的值。现在我真的很困惑!也许它特定于我的 Vue 版本。
  • 当你设置 value="true" 时它应该是:value="true"
  • 如果你给单选按钮添加一个名称属性,一切正常
猜你喜欢
  • 2016-08-28
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 2019-03-29
  • 2019-04-25
  • 2020-02-23
  • 2021-11-18
  • 2019-06-28
相关资源
最近更新 更多