Play with the render function “component-dynamic-select” (top)
Custom slots
Select Slots provides prefix/ Empty built-in Slots, so our component that is closed based on el-Select needs to support user-defined slot content
Configuration items
Implement basic component functions based on the current configuration items
parameter | instructions | type | The default value |
---|---|---|---|
slots | slot | Object |
{} |
scopedSlots | Scope slot | Object |
{} |
Render function
DynamicSelect/select.js
import SlotContent from './slotContent'
export default {
/ /... Ignore the configuration items defined in the previous article
// Register a functional component to render the content provided to the component's outer slot
components: { SlotContent },
render(h) {
// Config slot => used to render the component's built-in scope slot
const slots = Object.keys(self.slots).map(slotName= > {
return [h('slot-content', {
props: {
render: self.slots[slotName],
data: self
},
slot: slotName,
key: slotName
})]
})
}
}
Copy the code
Now we need to modify the third parameter of createElement in the el-select rendering
The third argument to createElement is the contents of the current node, just like div -> can hold multiple spans, so the third argument includes:
- The child node of the currently rendered element (component)
- The built-in scope slot provided by the current render element (component) (identified by $scopeSlots)
- The slot content slot of the currently rendered element (component)
return h('el-select', {
class: self.className,
staticClass: 'jl-full-line'. },Object.keys(this.$slots).map(s= > this.$slots[s]), ... optionsVnode, ... slots])Copy the code
With this we can render all three types of content into the el-Select component
DynamicSelect/select.js
export default {
name: 'SlotContent'.// Declare this a functional component
functional: true.props: {
render: {
type: Function.require: true
},
data: Object
},
render: (h, ctx) = > {
return ctx.props.render(h, ctx.props.data)
}
}
Copy the code
Flexible use of Render for highly customizable components
<template> <DynamicSelect ref="DynamicSelect" :value.sync="projectId" v-bind="projectSelectOption" :parse-data="parseData" :formatter="formatterValue" :multiple="true" collapse-tags // add customSlots configuration :slots="customSlots" > </DynamicSelect> </template> <script> export default { data() { return { customSlots: { prefix: this.prefixRender }, } }, methods: PrefixRender (h, vue) {// h => createElement // vue => DynamicSelect instance // We can use h to render any component into this custom slot. Return h('div', { staticClass: 'select-prefix', }, [h('svg-icon', { props: { 'icon-class': 'bug' }, })]) }, } } </script>Copy the code
The custom the options
Rendering π
Continue to refine the render function
+ const { value, label, labelRender } = self.optionsProps
The + // option formats display
+ let labelRenderNode = null
+ if (labelRender && typeof labelRender === 'function') {
+ labelRenderNode = function(labelValue, op) {
+ return labelRender(h, labelValue, op)
+}
+}// Render options const optionsVnode = self.optionsData.map((op, index) => {return [h('el-option', {attrs: {value: Op (value), label: op/label, disabled: op. Disabled}, key: op. Id | | op. The only key value / / binding+ } labelRenderNode ? labelRenderNode(op[label], op) : null)]
})
Copy the code
Formatter Customizes options content
<template> <DynamicSelect ... // add a customSlots configuration :slots="customSlots" :props="props" > </DynamicSelect> </template> <script> // define the const rendering options props = { label: 'proName', value: 'id', children: 'children', labelRender(h, label, item) {// h => createElement // label => options label // item => options Return [h('span', {staticClass: 'left', domProps: {innerText: label}}), h('span', {staticClass: 'Right ', domProps: {// On the right we show the first two bits of the project ID innerText: item?.id.substr(0, 2) || '' } })] } } export default { data() { return { customSlots: { prefix: This.prefixrender}, // Freeze the Object to avoid vue giving getters/setters to each member of the Object (also a performance optimization technique) : Object.freeze(props), } }, } </script>Copy the code
Add a full option to the component via $slots
<template> <DynamicSelect ... > <el-tag slot="selectAll" type="primary" class="select-tag-class" @click="handleSelectAll" > {{ selectAllLabel[selectAll] }} </el-tag> </DynamicSelect> </template> <script> export default { data() { return { SelectAllLabel: {false: 'selectAll ', true:' cancel ',}, // default: selectAll: false,}}, methods: HandleSelectAll () {this.selectAll =! This.selectall const list = [] if (this.selectAll) {// all} else {// cancel} // through $refs this.$refs.DynamicSelect.newValue = list } } } </script>Copy the code
$refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs = $refs Tip -> (a [] is passed to the back end when our project selects all)
Why not pass in all project ids??
[A, B, C, D] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F] [E, F
Copy the code
Back to the previous question, how can I respond to dynamically pulled options in a timely manner? π Publish and subscribe
Release subscription
There’s a lot of ways to do it, but I’ll write it as a class
./DynamicSelect/Publish.js
// Publish subscribe mode (solve the problem of asynchronous pull data options)
export default class Publish {
constructor() {
this.pond = []
}
on(callBack) {
this.pond.push(callBack)
}
emit(name) {
// Pass the name of the callback. If there is a match, the callback will be executed
const fn = this.pond.find(c= > c.name === name)
fn && fn()
}
}
Copy the code
Add a custom event to the previous method
// Dynamically pull option data
async getOptionsData() {
this.$emit('getOptionsSuccess'.this.optionsData)
}
Copy the code
Listen for this custom event
getOptionsSuccess(data) {
// The outer layer stores a reference to options
this.selectOptions = data
}
Copy the code
Perfect handleSelectAll
export default {
import Publish from './DynamicSelect/Publish.js'
const subscribe = new Publish()
methods: {
handleSelectAll() {
// You can push callbacks to the event pool from within the method, or you can call the method push(depending on the execution timing)
this.$nextTick(() = > {
this.selectAll = !this.selectAll
const list = []
if (this.selectAll) { / / all
list = this.selectOptions.map(i= > i.id)
} else { / / cancel
list = []
}
// Select all components ->
// $refs references the component's newValue directly
// Change value directly
this.porjectId = list
})
}
}
}
Copy the code
So far component encapsulation is complete, and the remote search piece is not written up, I found that writing this kind of article is not very easy to write, too much code and afraid of readers look confused, do not talk about the code is also difficult to explain. It is difficult to balance, which is why I have not updated my previous article “Developing mid-stage Projects with modularity in mind”. However, I have been learning this aspect, and there will be more in this series.
This component is wrapped in the Render function, not because it’s fancy. The Render function allows you to build components by writing JS, which is a lot more flexible than template syntax, but comes at a price
Many of the syntax sugar provided by Vue is unusable and needs to be implemented by itself, so you need to make a choice based on the functionality of the component
Component address πgithub.com/it-beige/bl…
Write in the last
If there is that piece of writing is not good or there is a problem, you are welcome to point out, I will also keep modifying in the following article. I hope I can grow with you as I progress. Like my article friends can also pay attention to it
I will be grateful for the first attention. At this time, young you and I, travel light; Then, rich you and I, full of goods.
The articles
[Suggestion] To build the middle and background project with the idea of modularization
Chapter one: Developing middle and back office project with modularization idea
EventLoop is an EventLoop that can be used in an interview.
[Front-end system] Build a tall building from the foundation
[Front-end system] The application scenario of regularity in development is more than just rule verification
“Functional programming practical scenario | nuggets technical essay – double festival special article”
All the arcane points of CSS are here