Nuxt mounts tripartite JS script plug-ins
The cause of
Because of the company’s official website function migration, from the original SPA application to the SSR application of Nuxt, involved in the loading of third-party customer service scripts, the front-end is not familiar with the artist to help, so I wrote a Vue plug-in to save colleagues in the fire.
TODO List
- Mount tripartite JS scripts
- Uninstall the tripartite JS script
- Provide global methods
- Initializes the incoming configuration item
- Use to register plug-ins with vue.use
Mount the script
const PluginName = 'LoadScriptPlugin'
const prefix = `[${PluginName}] - `
/** @typedef {{name: string, src: string, selector? : string, defer? : boolean, async? : boolean}} ScriptOption */
/ * *
* Create and mount scripts
* @param {ScriptOption} option Mount script options
* @returns {void}
* /
function createScript(option = {}) {
if(typeof option ! = ='object' || option === null) {
option = {}
}
const scriptId = `${prefix}${name}`
const script = document.createElement('script')
const parentEl = document.querySelector(selector) || document.body
script.id = scriptId
script.src = option.src
script.defer = option.defer
script.async = option.async
parentEl.append(script)
}
Copy the code
The above code creates the script tag with createElement and mounts the script by receiving an external parameter that sets the script’s properties.
To facilitate later unmounting of the script, we also need to record the elements of the script and its elements each time it is mounted. Add the following code:
/ * *
* All script information
* @description
* parent: parent element
* self: self element (script element)
*
* @type {{parent: HTMLElement, self: HTMLElement}}
* /
const scriptMap = {}
function createScript(option = {}) {
// append the tail
+ scriptMap[scriptId] = {
+ parent: parentEl,
+ self: script
+}
}
Copy the code
Destruction of the script
We recorded the parent element and its element each time the script was mounted via scriptMap above. Now we destroy the script by creating a function that receives the name identifier.
/ * *
* Destroy scripts
* @param {string} name Specifies the script name
* @returns {string}
* /
function destroyScript(name) {
const scriptId = `${prefix}${name}`
const scriptInfo = scriptMap[scriptId]
scriptInfo.parent.removeChild(scriptInfo.self)
delete scriptMap[scriptId]
}
Copy the code
Define the plugin
Above we have implemented the basic functions of the plug-in, but we have not yet seen where the plug-in we defined is. Next we need to visualize the plug-in and expose the installation interface for vue.use.
/ * *
* Vue automatically mounts tripartite script plug-ins
* @example
* Vue.use(Plugin, {})
* // or
* Vue.use(Plugin, [{}])
* /
const Plugin = {
/ * *
* the plugin name
* /
name: PluginName,
/ * *
* Installation record
* /
installed: false.
/ * *
* Installation behavior
* @param {Vue} Vue
* @param {ScriptOption|ScriptOption[]|null} options
* @returns {void}
* /
install(Vue, options) {
if (Plugin.installed || Vue.$isServer) return
if (options) {
options = Array.isArray(options) ? options : [options]
options.forEach((opt) => createScript(opt))
}
Plugin.installed = true
Vue.prototype.$createScript = createScript
Vue.prototype.$destroyScript = destroyScript
}
}
Copy the code
The above code defines the basic information and installation interface of our plug-in, which can be exported by default and registered with vue. use(LoadScriptPlugin), and can receive options to mount the plug-in at initialization.
Mount our script functions for the Vue prototype to facilitate the dynamic use of mount and destroy script functions in subsequent businesses.
Treatment of boundary
Up to now, our plug-in has basically been implemented, but there are still hidden dangers in use, because we developed it to provide convenience for other personnel to operate, and there may be error in operation when using it without complete understanding, so we need to make strict verification on the receiving parameters.
function log(... messages) {
console.log(prefix, ... messages)
}
functionwarn(... messages) {
console.warn(prefix, ... messages)
}
/ * *
* Create and mount scripts
* @param {ScriptOption} option Mount script options
* @returns {void}
* /
function createScript(option = {}) {
if(typeof option ! = ='object' || option === null) {
option = {}
}
if ([' ', null, void 0].includes(option.src)) {
return warn('The src property of the option cannot be falsly value! ')
}
if ([' ', null, void 0].includes(option.name)) {
return warn(
'The name property of the option cannot be falsly value! The name property will be used to identify the current script! '
)
}
const scriptId = getScriptId(option.name)
if (scriptId in scriptMap) {
return warn('Duplicate name attribute, please re-enter! ')
}
.
log(`The ${name}script been created! `)
}
/ * *
* Destroy scripts
* @param {string} name Specifies the script name
* @returns {string}
* /
function destroyScript(name) {
.
if(! (scriptIdin scriptMap) || scriptInfo === undefined) {
return warn(`The script with name as ${name}does not exist! `)
}
.
log(`The ${name}script been destroyed! `)
}
Copy the code
The complete code
import Vue from 'vue'
const PluginName = 'LoadScriptPlugin'
const prefix = `[${PluginName}] - `
/ * *
* All script information
* @description
* parent: parent element
* self: self element (script element)
*
* @type {{parent: HTMLElement, self: HTMLElement}}
* /
const scriptMap = {}
function log(... messages) {
console.log(prefix, ... messages)
}
functionwarn(... messages) {
console.warn(prefix, ... messages)
}
/ * *
* Gets the parent element to mount
* @param {string} selector
* @returns {HTMLElement}
* /
function getParentEl(selector) {
let el = null
if (selector) el = document.querySelector(selector)
return el || document.body
}
/ * *
* Gets a unique script identifier
* @param {string} name Specifies the script name
* @returns {string}
* /
function getScriptId(name) {
return `${prefix}${name}`
}
/** @typedef {{name: string, src: string, selector? : string, defer? : boolean, async? : boolean}} ScriptOption */
/ * *
* Create and mount scripts
* @param {ScriptOption} option Mount script options
* @returns {void}
* /
function createScript(option = {}) {
if(typeof option ! = ='object' || option === null) {
option = {}
}
if ([' ', null, void 0].includes(option.src)) {
return warn('The src property of the option cannot be falsly value! ')
}
if ([' ', null, void 0].includes(option.name)) {
return warn(
'The name property of the option cannot be falsly value! The name property will be used to identify the current script! '
)
}
const scriptId = getScriptId(option.name)
if (scriptId in scriptMap) {
return warn('Duplicate name attribute, please re-enter! ')
}
const script = document.createElement('script')
const parentEl = getParentEl(option.selector)
script.id = scriptId
script.src = option.src
script.defer = option.defer
script.async = option.async
parentEl.append(script)
scriptMap[scriptId] = {
parent: parentEl,
self: script
}
log(`The ${name}script been created! `)
}
/ * *
* Destroy scripts
* @param {string} name Specifies the script name
* @returns {string}
* /
function destroyScript(name) {
const scriptId = getScriptId(name)
const scriptInfo = scriptMap[scriptId]
if(! (scriptIdin scriptMap) || scriptInfo === undefined) {
return warn(`The script with name as ${name}does not exist! `)
}
scriptInfo.parent.removeChild(scriptInfo.self)
delete scriptMap[scriptId]
log(`The ${name}script been destroyed! `)
}
/ * *
* Vue automatically mounts tripartite script plug-ins
* @example
* Vue.use(Plugin, {})
* // or
* Vue.use(Plugin, [{}])
* /
const Plugin = {
/ * *
* the plugin name
* /
name: PluginName,
/ * *
* Installation record
* /
installed: false.
/ * *
* Install plugins
* @param {Vue} Vue
* @param {ScriptOption|ScriptOption[]|null} options
* @returns {void}
* /
install(Vue, options) {
if (Plugin.installed || Vue.$isServer) return
if (options) {
options = Array.isArray(options) ? options : [options]
options.forEach((opt) => createScript(opt))
}
Plugin.installed = true
Vue.prototype.$createScript = createScript
Vue.prototype.$destroyScript = destroyScript
}
}
// exportDefault Plugin // Export plug-in entry
// Nuxt plugin
Vue.use(Plugin, [
/** Load the customer service script */
{
name: 'customService'.
src: 'xxx
}
])
Copy the code
The last
The solution of each problem is a step forward for me to achieve wealth and freedom!
Write an article for the first time, do not like spray, have a question welcome comment area message exchange!