This is the fifth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

In the previous series of articles, you’ve seen how to encapsulate Button and Button-group components, and you’ve seen how to encapsulate components. It’s much easier to learn how to encapsulate other components. In this article, let’s learn how to encapsulate a simple Radio component.

1. Get to know Radio components

1. What is the Radio component

The Radio component is a Radio selection from a set of options

2. Radio component basic framework and styling

Create the radio.vue file under Components

<template>
  <label class="lol-radio"
    role="radio"
  >
    <span class="lol-radio_input"
    >
      <span class="lol-radio_inner"></span>
        <input
          type="radio"
          class="lol-radio_original"
        >
      </span>
      <span class="lol-radio_label">
           <slot></slot>
      </span>
  </label>
</template>

<script>

export default {
  name: 'lolRadio',}</script>

<style lang="scss" scoped>
.lol-radio{
  color: #E0CE9C;
  font-weight: 500;
  line-height: 1;
  position: relative;
  cursor: pointer;
  display: inline-block;
  white-space: nowrap;
  outline: none;
  font-size: 14px;
  margin-right: 30px;
  user-select: none;
  &:focus,
  &:hover{
    color: #E8DFCC;
  }
  .lol-radio_input{
    white-space: nowrap;
    cursor: pointer;
    outline: none;
    display: inline-block;
    line-height: 1;
    position: relative;
    vertical-align: middle;
    .lol-radio_inner{
      display: inline-block;
      box-sizing: border-box;
      position: relative;
      border: 2px solid #C59533;
      width: 14px;
      height: 14px;
      background-color: rgba(0.0.0.0);
      transform: rotate(45deg);
      &:after{
        width: 5px;
        height: 5px;
        background-color: #E8DFCC;
        content: "";
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%) scale(0);
        transition: transform .15sease-in; }}.lol-radio_original{
      opacity: 0;
      outline: none;
      position: absolute;
      z-index: -1;
      top: 0;
      left: 0;
      margin: 0; }}.lol-radio_label{
    font-size: 14px;
    padding-left: 10px; }}.lol-radio.is-checked{
  .lol-radio_input{
    .lol-radio_inner{
      border-color: #C79734;
      &:after{
        transform: translate(-50%, -50%) scale(1); }}}.lol-radio_label{
    color: #E8DFCC; }}</style>

Copy the code

3. Register the Radio component

After creating the Radio component, you also need to register it in Mani. Js

import Vue from 'vue'
import App from './App.vue'
// Reference the font icon
import './assets/fonts/iconfont.css'
// Import the Button component
import lolButton from './components/button.vue'
// Import the button-group component
import lolButtonGroup from './components/button-group.vue'
// Import the Radio component
import lolRadio from './components/radio.vue'
 
Vue.config.productionTip = false
 
// Register the component
Vue.component(lolButton.name, lolButton)
Vue.component(lolButtonGroup.name, lolButtonGroup)
Vue.component(lolRadio.name, lolRadio)
 
new Vue({
  render: h= > h(App)
}).$mount('#app')

Copy the code

4. Radio component use

      <lol-radio>1</lol-radio>
      <lol-radio>2</lol-radio>
Copy the code

2. Radio component data bidirectional binding

1. V – introduction of the model

Vue’s V-Model bidirectional binding is introduced when encapsulating the Radio component. The official VUE documentation describes the use of v-Model in custom components very carefully.

By default, v-Models on a component make use of a prop named Value and an event named Input, but input controls of types such as checkboxes, checkboxes, and so on May use value attribute for different purposes. The Model option can be used to avoid such conflicts:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
Copy the code

Now when using v-Model on this component:

<base-checkbox v-model="lovingVue"></base-checkbox>
Copy the code

The value of lovingVue here is going to be passed in to this prop called CHECKED. The lovingVue property will also be updated when

triggers a change event with a new value.

In simple terms, values that are sugar-bound in the parent using v-Model syntax are received by value in the child component

2. The Radio component is bi-directional bound

1. Parent component binding and value passing

Implementing the binding of radio component data requires the value of label and value passed by the parent component, where value is bound using v-Model syntactic sugar.

  <lol-radio v-model="number" label=0>0</lol-radio>
  <lol-radio v-model="number" label=1>1</lol-radio>
Copy the code

2. The child component receives and processes

After receiving the data, the child component processes the data as follows.

  1. When the RADIO component is clicked, the bound data should change to that component’s label value. And bind the value of the input label in the component to the incoming label value.

  2. Declare a computed property, model, bound bidirectionally to the input component. The value of the model we need to get; And the value is called back to the parent through the set method.

  3. At the same time, when we click on the radio component, we should have the selected component add the selected style. We will determine by comparing the label and value, and if they are the same, the selected style will be displayed.


<template>
  <label class="lol-radio" :class="{'is-checked': label == value}">
    <span class="lol-radio_input">
      <span class="lol-radio_inner"></span>
      <input
      type="radio"
      class="lol-radio_original"
      :value="label"
      v-model="model"
      >
    </span>
    <span class="lol-radio_label">
      <slot></slot>
      <template v-if=! "" $slots.default">{{label}}</template>
      </span>
  </label>
</template>

<script>
export default {
  name: 'lolRadio'.props: {
    label: {
      type: [String.Number.Boolean].default: ' '
    },
    value: null
  },

  computed: {
    model: {
      get () {
        return this.value
      },
      set (value) {
        this.$emit('input', value)
      }
    }
  },
}
</script>
Copy the code

3. Disabled status

As with the Button component, disable incoming reception as a property of Radio, dynamically generate styles, and disable input click events


<template>
  <label class="lol-radio" :class="[ {'is-disabled': disabled}, {'is-checked': value === label} ]">
    <span class="lol-radio_input">
      <span class="lol-radio_inner"></span>
      <input
      type="radio"
      class="lol-radio_original"
      :disabled="disabled"
      :value="label"
      v-model="model"
      >
    </span>
    <span class="lol-radio_label">
      <slot></slot>
      <template v-if=! "" $slots.default">{{label}}</template>
      </span>
  </label>
</template>

<script>
export default {
  name: 'lolRadio'.props: {
    label: {
      type: [String.Number.Boolean].default: ' '
    },
    value: null.disabled: {
      type: Boolean.default: false}},computed: {
    model: {
      get () {
        return this.value
      },
      set (value) {
        this.$emit('input', value)
      }
    }
  },
}
</script>
<style>
.lol-radio.is-disabled {
  cursor: not-allowed;
  .lol-radio_input{
    cursor: not-allowed;
    .lol-radio_inner{
      cursor: not-allowed;
      border-color: #5C5B57}}.lol-radio_label{
    color: #5C5B57; }}</style>
Copy the code

end

The simple encapsulation of Radio is complete, but the fact that they are bound to the same V-Model requires that each Radio be bound separately, and solving this problem requires a new component, radio-Group

Your praise is my motivation to continue more!!

respect by myself