The reason

Recently, the project is in a self-driven state, so I try my best to write it from a standard, long-term and learning perspective.

The project uses Element-Plus, VUe3

High-order components and functions

1. Characteristics of higher-order functions

Take one function as an argument to another

When the parameter is fixed, the result is fixed

In plain English, you pass in a function and return a function. The wrapped function can be decorated, but all arguments are passed to the function passed in. My understanding is the deep use of decorator syntax, and callback functions.

2. Higher-order components

High-order components and high-order functions are similar principles. React was first proposed, but is rarely used in the VUE community. But in terms of passing in a component and returning a component, we’ve probably written about that.

Second, vUE high order components we need to solve the biggest problem

I need to get all the parameters, which don’t need to be defined by props, all the parameters on the components, and then throw them all to the encapsulated components. Then we send the component back out and use it.

Vue2 syntax, we have a $attres to get all arguments, vue3 also has this argument, based on this aspect of the higher-order functions, there have been many articles implemented

Then vue3’s combinatorial API approach gets interesting.

Steup can return an object and a function, according to the official documentation

Returning an object puts the data into context, which is a JSX syntax for functions. The relevant address

Next JSX syntax is the way we need to use it.

Three, first throw out matters needing attention

Vue3 does not need to introduce new Babel and supports JSX syntax directly

2. JSX cannot be used with Scoped, you should know that

3. The isCustomElement parameter is useless. If you want to use templete without warning, you need to add it to vue

chainWebpack: The config = > {/ config/reference https://github.com/vuejs/vue-cli/issues/5610. Module. Rule (' vue). Use (' vue - loader) .loader(require.resolve('vue-loader-v16')) .tap(options => { options.compilerOptions = { ... (options.com pilerOptions | | {}), isCustomElement: tag = > / ^ JSX - custom /. The test (tag), / / define global analysis, is used to return the options JSX}})},Copy the code

4. If you use JSX instead of V-slot, you should use V-Solts instead

Reference documents: github.com/vuejs/jsx-n…

5. The reason v-Solts doesn’t work is because your component is not an undefined component, and the isCustomElement argument above resolves this problem.

You don’t want to put on top of a valid component like div, span, put on a valid component like div, span

<a  v-slot/>

Here the A component is not defined

6. Although higher-order components are basically realized, we found that the parent component could not operate the functions of the child component when we used it with REF, because the child component just rendered, regardless of the object processing. Then we need to bind the current higher-order component with functions that can be manipulated externally

const self = getCurrentInstance()

// Bind external operable functions to the current component object

 self.proxy.handColse = onColse

7, JSX below the named slot to use, but did not find the official document, tried for a long time is not good. Finally, h rendering function is adopted

{// Since it is a slot, it doesn't matter how to use the rendering function directly, and the V-slots method doesn't know how to name the slot [h('default', ctx.slots.default()), h('footer', ctx.slots.footer())]}Copy the code

Updated 17 December 2020. JSX can also be scoped CSS

Source: github.com/vuejs/jsx-n…

Use the demo:

<script lang="tsx"> import { defineComponent, withScopeId, getCurrentInstance } from 'vue' export default defineComponent({ setup(props, ctx) { const instance = getCurrentInstance() const scopeId = instance.type.__scopeId const withId = withScopeId(scopeId)  return withId(() => <div class="ceshi">fdsafas</div>) }, }) </script> <style scoped lang="scss"> .ceshi { width: 100px; height: 100px; background: red; } </style>Copy the code

4. Code presentation

This is high-level component encapsulation of an El-drawer component

< script lang = "JSX" > / * https://github.com/vuejs/jsx-next/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md * / JSX use manual import { ref, getCurrentInstance, h } from 'vue' export default { name: 'CopyDrawer', emits: [], setup(props, ctx) { const self = getCurrentInstance() let doneF = null const root = ref('root') function handleClose(done) { doneF = Done} function onColse() {root.value.handleclose () // Calls the internal shutdown method to pass the done event doneF()} to the handleClose parameter // binds the external operable function to the current component object self.proxy.handColse = onColse const slots = { default: () => <div>A</div>, foo: () => <span>B</span> }; return () => ( <el-drawer ref={root} {... Ctx.attrs} withHeader={false} before-close={handleClose}> <div className="copy-el-drawer"> {// Customize top title} <div className="title"> <span>{ctx.attrs.title}</span> <i className="icon el-icon-close" onClick={onColse} /> </div> { // // <jsx-custom v-slots="ctx.slots" />} { Slot [h('default', ctx.slots.default())), h('footer', ctx.slots.footer())]} </div> </el-drawer>)}, } </script> <style lang="scss"> .copy-el-drawer { width: 100%; height: 100%; position: relative; .title { width: 100%; font-size: $h4-16; height: 40px; display: flex; padding: 20px; align-items: center; color: $info; justify-content: space-between; } .icon { font-size: $h2-24; &:hover { color: $font-color; } } } </style>Copy the code

use

<copy-drawer: closeon-press-escape ="false" size="60%" title=" new address "V-model =" copy-drawer" direction=" RTL "@close="onClose" Destroy on-close ref="addFrom" > <div class="insert-drawer"> <el-button @click="ceshi"> Test </el-button> <el-form :model="formData" :rules="rules"></el-form> </div> <template #footer> <span>524551</span> </template> </copy-drawer>Copy the code

5. Elemental-plus bugs

Last time I posted a bug on Element. Not much this time. The official fix was quick. I used drawer components here, so I found two more.

1. The modal parameter cannot be set to false, otherwise it cannot be used, and issues have been submitted

2. The closeDrawer parameter in the official document cannot be obtained through ref or other methods, and has been submitted to issues

The personal solution is to operate handleClose, depending on the official update

code

Const root = ref('root') root.value.handleclose () // Calls the internal close method to pass the done event to the handleClose argumentCopy the code

Six, step pit basically complete

Today, I haven’t written any business code since I wanted to implement this function. But there were also gains. And once you’ve implemented higher-order components based on this, it’s easy to use templete.

Also, JSX is used in a different way than Ant-Desgin and Element-Plus. I’m a pure combinatorial API, but they used Render. Each to his own.

Finished!