Element-ui radio-group

Analyze the

<template> <el-radio-group V-model ="radio"> <el-radio :label="3"> Alternative </el-radio> <el-radio :label="6"> Alternative </el-radio> <el-radio :label="9"> Alternative </el-radio> </el-radio-group> </template> <script> export default {data () {return {radio: 3}; } } </script>Copy the code
  • Note the difference between dynamic v-bind and static bind
> <y-radio label="1"></y-radio>No colon, yesStringtype1+label=11(Print in component Y-radio) ><y-radio :label="1"></y-radio>Plus colon, yesNumbertype1+label=2> Colon to indicate that this is a JavaScript expression and not a string > No colon to indicate that this is a string > V-bind is not used except for string constants. Vue thinks that what is passed to the component via prop is a string constant. What is the significance of v-Bind's design? > All prop forms a one-way downlink binding between their parent prop: updates to the parent prop flow down to the child, but not the other way around. > This prevents accidental changes in the state of the parent component from the child, which can make the data flow of your application difficult to understand. > prop official documentation: HTTPS://cn.vuejs.org/v2/guide/components-props.html
Copy the code

The test code

<template>
    <div>
        <p>Raodio-group Label of a statically bound radio</p>
        <y-radio-group v-model="radioGroupValue">
            <y-radio label="1">male</y-radio>
            <y-radio label="2">female</y-radio>
            <y-radio label="3">The unknown</y-radio>
        </y-radio-group>

        <p>Raodio-group Indicates the label of dynamically bound radio</p>
        <y-radio-group v-model="radioGroupValue">
            <y-radio :label="1">male</y-radio>
            <y-radio :label="2">female</y-radio>
            <y-radio :label="3">The unknown</y-radio>
        </y-radio-group>
    </div>
</template>

<script>

export default {
  data() {
    return {
      radioGroupValue: "1"}; },watch: {
    radioGroupValue() {
      console.log('Parent component radioGroupValue'.this.radioGroupValue)
    }
  }
};
</script>
Copy the code

Component radio – group

<template> <! Radio-group, there's a radio child and the parent is going to pass a V-model value and an input event and the radio-group is going to pass that value to the child radio and the child radio changes that value, To notify the radio-group, the radio-group then tells the parent via input events how to bidirectionally bind the value to the child? -- element-ui2.151.Check whether the parent component is radio-group by tracing up the component radio. If so, set the value of radio-group --><div class="y-radio-group" role="rolegroup">
        <! How does the child radio notify the parent radio-group of the method update value instead of passing it a method update value? Bubble up with the dispatch method mixed with mixins -->
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'YRadioGroup'.componentName: 'YRadioGroup'.props: {
        value: {},},created() {
        /** * this.$on listens for custom events on the current instance. * Events can be emitted by this.$emit. * The callback function receives any additional arguments that are passed in to the event that triggers the function. * In fact, the child component radio calls the parent component radio-group's handleChange method, which is not defined in the radio-group display */
        this.$on('handleChange'.value= > {
            console.log('Radio-group listener handleChange has changed', value);
            // Notify the parent component to update the value of the bidirectional binding
            this.$emit('input', value); })},mounted() {
        console.log('Changed'.this.value, this.$slots); }}</script>
Copy the code
There are two things to note here
  • The parent radio-group passes the value of the V-Model binding to the child radio
  • When the value of the child component radio binding changes, the parent component radio-Group needs to be notified of the update

Component Radio modification

<template>
    <label
        class="y-radio"
        :class="[ {'is-focus': focus}, {'is-checked': model === label} ]"
        role="radio"
        :aria-checked="model === label">
        <span 
            class="y-radio__input"
            :class="{ 'is-checked': model === label }">
            <span class="y-radio__inner"></span>
            <input
                ref="radio"
                class="y-radio__original"
                :value="label"
                type="radio"
                aria-hidden="false"
                v-model="model"
                @focus="focus = true"
                @blur="focus = false"
                @change="handleChange" />
        </span>
        <span class="y-radio__label">
            <slot></slot>
            <template v-if=! "" $slots.default">{{label}}</template>
        </span>
    </label>
</template>

<script>
import Emitter from '.. /.. /.. /src/mixins/emitter';
export default {

    name: 'YRadio'.// Add a dispath method to send events up to the parent component
    mixins: [Emitter],
    
    // Receives data from the parent component
    props: {
        value: {}, // Parent component V-model
        label: {}, // Parent component label
    },
    
    computed: {
        
        // If the parent component is radio-group, then the parent component is radio-group.
        isGroup() {
            let parent = this.$parent;
            while(parent) {
                // console.log(' Parent component under Radio ', parent, parent. new options.componentName);
                if(parent.$options.componentName ! = ='YRadioGroup') {
                    parent = parent.$parent;
                }else {
                    // Retain the radio-group component data
                    this._radioGroup = parent;
                    return true; }}return false;
        },
        
        /** * If radio-group is a radio, isGroup will be true. If radio-group is a radio, isGroup will be true. If radio-group is a radio, model will be true. * /
        model: {
            get() {
                // return this.value;
                return this.isGroup ? this._radioGroup.value : this.value;
            },
            set(val) {
                console.log('The model value has changed', val);
                // Notify the parent component to update the value of the V-model
                // this.$emit('input', val)
                if(this.isGroup) {
                    // this.dispatch('YRadioGroup', 'input', [val]);
                    // this. Dispatch is blended in to notify the parent radio-group of updates
                    this.dispatch('YRadioGroup'.'input', [val]);
                }else {
                    this.$emit('input', val);
                }
                // Synchronize to the selected state of the native checkbox
                this.$refs.radio && (this.$refs.radio.checked = this.model === this.label); }}},data() {
        return {
            focus: false,}},methods: {
        handleChange() {
            // After input is changed, the value corresponding to label can be obtained only after the view is updated
            this.$nextTick(() = >{
                console.log('handleChange'.this.model);
                // What is the meaning of this statement, notifies the parent component of the selected state change callback
                this.$emit('change'.this.model);
                // If the parent component is radio-group, the parent component's handleChange is called to update the model value
                this.isGroup && this.dispatch('YRadioGroup'.'handleChange'.this.model); })}},mounted() {
        // console.log('111', this.$slots, Boolean(this.$slots.default), this.value, this.label, this.model === this.label);
        // Test: the value of label is 1, if the colon is added, it indicates that the type passed is a number, 1+1=1; If the colon is not added, it indicates that the string type is passed in. 1+1=11
        // console.log('222', this.label, this.label + 1);
        console.log('333'.this.model)
    }
    
}
</script>
Copy the code

Mixed with Emitter

For example, if the radio component uses mixin and the mixin object has a method that the Radio component does not have, then the radio component will have this method * Usage scenario: If multiple components Shared the same way or anything, can be pulled out, mix in * official documentation: https://cn.vuejs.org/v2/guide/mixins.html * /

export default {

    methods: {

        /** * implement the child component to send events to the parent component, the child component to notify the parent component *@param {*} ComponentName componentName, used to find the component (the current parent component) that has the componentName *@param {*} EventName specifies the eventName. The value is a string of characters *@param {*} Params parameters * /
        dispatch(componentName, eventName, params) {

            // console.log(' Emitter ', componentName, eventName, Params, this);
            let parent = this.$parent;
            let name = parent.$options.componentName;

            // Find the parent component named componentName
            while(parent && (! name || name ! == componentName)) { parent = parent.$parent;if(parent) { name = parent.$options.componentName; }}/** * emit https://cn.vuejs.org/v2/api/#vm-emit * vm. $emit (eventName, args [...]), the parameters of the two forms, one kind is enclosing $emit (eventName, parameters), One is this. $emit ([event name, parameters]) * concat connecting two arrays [' input '] concat ([' 1 ']) = > [' input ', '1'], [' input '] concat (' 1 ') = > [' input ', '1'] * grammar: arrayObject concat (arrayX, arrayX,... , arrayX) necessary. This parameter can be a concrete value or an array object. It can be as many as you want. * Return value: Returns a new array. The array is generated by adding all the arrayX parameters to the arrayObject. If the argument to concat() is an array, then you add elements of the array, not the array. $emit([event name, parameter]); (this.$emit(parent, [eventName].concat(params))))) $emit(parent, ['input', '1']) will be translated to vm.$emit('input', '1') if the apply method accepts array arguments (call method accepts arguments) */
            console.log('Parent node', parent, name, [eventName].concat('1'));
            // apply changes the this reference in this.$emit
            this.$emit.apply(parent, [eventName].concat(params))
            
        }

    }

}
Copy the code

conclusion

  • Prop uses colons and no V-binde to pass values
  • Mixin, the component of the public data out of the official documentation