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