Web笔记 · · By/蜜汁炒酸奶

Nuxt动态引入Script模块

Nuxt在body中增加模块很容易,这里不再多言,仅讨论在<head>标签中动态增加Script模块的方式。
本文所有结果基于Nuxt版本:"^2.13.0"

head中增加模块

正常情况有两种引入:script外部脚本和页内脚本,静态写法如下:

head () { return { title: xxx, meta: [ // ... ], script: [ // 所有script模块均在此处添加才可进入<head>标签 ] } }

外部脚本

nuxt实现如下:

head () { return { // ... script: [ { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.js', async: true, defer: true } ] } }

效果:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" async defer></script>

页内脚本

nuxt实现如下:

head () { return { // ... script: [{ hid: 'ldjson-schema', innerHTML: '{ "@context": "http://schema.org" }', type: 'application/ld+json' }], __dangerouslyDisableSanitizersByTagID: { 'ldjson-schema': ['innerHTML'] }, } }

效果:

<script type="application/ld+json"> { "@context": "http://schema.org" } </script>

需注意:

  1. 官网api文档尚有vmid的例子,但当前版本中设置无效,需要改为设置hid
  2. hidldjson-schema的script模块的innerHTML属性值不经过 __dangerouslyDisableSanitizersByTagID禁用转义,字符串中的特殊字符均会被转义。
  3. head的更多配置请参考 官方文档

head中动态增加模块

本文中的动态增加则是通过正则表达式将字符串拆分拼接成上述数组实现的。步骤如下:

  1. 将js字符串根据<script>....</script>标签拆分成js数组,即正则:/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g
  2. 循环js数组,逐个解析js字符串内容。
  3. 基于/<script.*?>/ 获取js前半部分标签即<script>的内容。
  4. 步骤3中的字符串和indexOf("<\/script>")结合获取<script>....</script> 中间的内容(如果有)。
  5. 步骤3中的字符串基于正则"[\\s]+ 替换所有空格为但空格,即replace("[\\s]+"," ")
  6. 拆分步骤3中字符串,获取到<script>标签属性配置,逐个变成键值对,作为js对象的属性。
  7. 最后将js对象放到数组中,并将数组赋值给上述head块的script属性。

完整代码如下:

head () { let scriptArry = []; // JavaScript对象数组,用于赋值给script let scripTag = {}; // 待禁止转义的JavaScript内容块ID,用于赋值给 __dangerouslyDisableSanitizersByTagID // this.windcoder.com.site_head_script_code 待拆分js字符串 if(this.windcoder.com.site_head_script_code) { // 1. 将字符串拆分为 <script>....</script> 格式字符串的数组 let reg = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g; let scriptStrArry = this.siteInfo.site_head_script_code.match(reg); let reg2 =/<script.*?>/; // 用于获取字符串前半部分 let scnum = 0; // 用于设置script块的ID标签 // 2.循环拆分出的数组,逐个获取数据 for(let str of scriptStrArry) { // 3. 获取js前半部分标签,即<script>的内容 let preStr = str.match(reg2)[0]; // 4. 获取js标签中间部分的内容(如果有,说明是script块,需要禁用转义) let mindStr = str.substring(preStr.length,str.indexOf("<\/script>")); // 5. 格式化js标签前部分内容,方便后续拆分 let preStr2 = preStr.substring(7,preStr.length-1).replace("[\\s]+"," "); let scriptObj = {}; // 用于存储转化后的js对象 scnum++; if(preStr2.length>0) { // 获取scipt标签的属性数组 let preArry = preStr2.split(" "); for(let apre of preArry) { // 6. 基于“=”拆分属性,如 src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" 被拆分为 ["src",'"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"'] let preArr2 = apre.split("="); if(preArr2.length==2) { // 说明是键值对形式,这里仅对字符串形式做了处理,数值型,请依据类似做法转化为js对象的属性。 scriptObj[preArr2[0]] = preArr2[1].substring(1,preArr2[1].length-1); } else { // 说明属性是默认值,如上面的 async if(preArr2[0]!='') { scriptObj[preArr2[0]] = true; } } } } // 如果存在中间内容,追加hid,并添加到scripTag用于后续禁用转义 if(mindStr.length>0) { scriptObj.innerHTML = mindStr; scriptObj['hid'] = 'script-'+scnum; scripTag['script-'+scnum] = ['innerHTML']; } scriptArry.push(scriptObj); } } return { title: this.siteInfo.name, meta: [ { hid: "keywords", name: "keywords", content: this.siteInfo. site_key}, { hid: "description", name: "description", content: this.siteInfo. site_description}, ], script: scriptArry, // 7. JavaScript标签组动态赋值 style:[], __dangerouslyDisableSanitizersByTagID: scripTag, link: [ // ... ], } },

小结

本文主要讲的是如何将JavaScript基于正则表达式动态生成的问题,css相关内容也可以像上面一样动态添加,这里就不再过多说了。这种方式存在一点小问题,就是不支持谷歌广告的js标签。容易出现l类似如下的问题:

adsbygoogle.push() error: Only one AdSense head tag supported per page. The second tag is ignored.

Uncaught TagError: adsbygoogle.push() error: All ins elements in the DOM with class=adsbygoogle already have ads in them.

这些JavaScript最好编译前动手引入。最简单的设置在 nuxt.config.js文件的head中,这种方案未作测试,请以实际效果为准。
还有一种文案是通过在项目根目录下创建app.html,从而修改应用模板,默认如下:

<!DOCTYPE html> <html {{ HTML_ATTRS }}> <head {{ HEAD_ATTRS }}> {{ HEAD }} </head> <body {{ BODY_ATTRS }}> {{ APP }} </body> </html>

修改之后如下:

<!DOCTYPE html> <!--[if IE 9]><html class="lt-ie9 ie9" {{ HTML_ATTRS }}><![endif]--> <!--[if (gt IE 9)|!(IE)]><!--><html {{ HTML_ATTRS }}><!--<![endif]--> <head {{ HEAD_ATTRS }}> {{ HEAD }} <script data-ad-client="ca-pub-xxxxxx" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> </head> <body {{ BODY_ATTRS }}> {{ APP }} </body> </html>

参考资料:

How to add Google Adsense to Nuxt

评论已关闭

example
C
蜜汁炒酸奶

当前处于试运行期间,可能存在不稳定情况,敬请见谅。

欢迎点击此处反馈访问过程中出现的问题