This is the first day of my participation in the August Text Challenge.More challenges in August
When using UI frameworks such as elementUI and antdUI, the Message global prompt method is used, while commonly used Vue components are written as tags.
<el-button type="primary">The main button</el-button>
<el-button type="success">Successful button</el-button>
Copy the code
However, Message and other components are used in a different way, which can be directly called by JS without introducing the Vue component of Message:
<template>
<el-button type="text" @click="open">Click to open the Message Box</el-button>
</template>
<script>
export default {
methods: {
open() {
this.$confirm('This operation will permanently delete the file. Do you want to continue? '.'tip', {
confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
}).then(() = > {
this.$message({ type: 'success'.message: 'Deleted successfully! ' });
}).catch(() = > {
this.$message({ type: 'info'.message: 'Cancelled delete'}); }); }}}</script>
Copy the code
How to use JS to call Vue components in Vue3?
Normal writing
Write a normal component first:
<template>
<div class="test-comp">
<div>title: {{title}}</div>
<div>{{msg}}</div>
<button @click="onClose">Shut down</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
title: String.onClose: Function
},
setup() {
const msg = 'This is a test component's own MSG'
return {
msg
}
},
})
</script>
Copy the code
Then call it within the parent component:
<template>
<div>Js calls the Vue component</div>
<button @click="isshow = true">Calling the test component</button>
<TestComp
v-if="isshow"
title="This is the title that came in."
:onClose="onClose"
/>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import TestComp from '.. /components/testComp.vue'
export default defineComponent({
components: {
TestComp
},
setup() {
const isshow = ref(false)
const onClose = () = > isshow.value = false
return {
isshow,
onClose
}
},
})
</script>
Copy the code
Then look at the effect:
Overwriting JS calls
Next, rewrite the above component as a js call:
Before rewriting, there are a few more global apis you need to know about vue3:
- DefineComponent: Returns a function or object converted to an object
- H: Converts component objects into VNodes
- Render: Mount vNode to node or remove node
Create another TS/js file and convert the TestComp component:
First implement a vNode mount node function and a node remove function:
import { defineComponent, h, render } from 'vue'
// Generate a unique key
const COMPONENT_CONTAINER_SYMBOL = Symbol('component_container')
/** * Create the component instance object * returns the same instance as getCurrentComponent() *@param {*} Component* /
function createComponent(Component: any, props: any, children: any) {
/ / create a vnode
constvnode = h(Component, { ... props }, children)// Create a component container
const container = document.createElement('div')
// @ts-ignore Mounts the component container to vNode for subsequent removal
vnode[COMPONENT_CONTAINER_SYMBOL] = container
// Render vNode into a component container. In version VUe2, parent elements can be passed null, but vue3 does not
render(vnode, container)
// Returns the component instance
return vnode.component
}
/** * Destroys the component instance object *@param {*} ComponnetInstance A component instance object obtained by createComponent */
export function unmountComponent(ComponnetInstance: any) {
// Remove component node, render function first pass null, indicating remove action, will execute unmount method
render(null, ComponnetInstance.vnode[COMPONENT_CONTAINER_SYMBOL])
}
Copy the code
Importing components to mount nodes
import TestComp from './testComp.vue'
/ /...
/ /...
// In the current scenario, you can omit this conversion step, but in terms of type, the value returned by defineComponent has a synthesized type constructor
const componentConstructor = defineComponent(TestComp)
// Create a variable to receive the created component instance
let instance: any;
// Create a node
const showTestComponent = (options: any) = > {
// Create a component instance object
instance = createComponent(componentConstructor, options, null)
// Add to body
document.body.appendChild(instance.vnode.el)
}
// options are props for the component
export const testComp = function (options: any) {
const close = options.onClose
// Rewrap close, add remove element operation
options.onClose = () = > {
close && close.call()
unmountComponent(instance)
}
showTestComponent(options)
}
Copy the code
Finally called in the parent component
<template>
<div>Js calls the Vue component</div>
<button @click="show">Calling the test component</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { testComp } from '.. /components/testComp'
export default defineComponent({
setup() {
const show = () = > {
testComp({
title: 'This is the title that came in.'.onClose() {
console.log('close')}}}return {
show
}
},
})
</script>
Copy the code
Ps: Effect picture:
At this point, the rewriting of the Vue component using JS calls is complete. This kind of component is very convenient in some scenarios. It can be wrapped according to the specific scenario and then called with one click.