跳转至

Nuxt.js 高级用法

基于版本:"nuxt": "^2.15.8"

Nuxt 2 如何在全局插入 head script (使用modules)

首先你需要安装 cheerio,一款类似jQuery的用于操作html的库,我使用的版本是"cheerio": "^1.0.0-rc.12"

Bash
yarn add cheerio

创建自定义模块 modules/head-script.js,并写入以下内容:

JavaScript
import {load} from 'cheerio'

const fs = require('fs')
const Path = require('path')

// 此处的 analytics.html 文件可以写任意 html head 里支持的代码
const headHtmlCode = fs.readFileSync(Path.join(__dirname, './analytics.html'), {
  encoding: 'utf-8',
})

const isDev = process.env.NODE_ENV === 'development'

export default function HeadScriptModule(moduleOptions) {
  this.nuxt.hook('render:route', async (url, result, context) => {
    // console.log('render:route', url, result, context)
    const {
      req,
      nuxt: {config},
    } = context

    // 只在生产环境放置统计脚本
    // if (isDev) {
    //   console.log('Script disabled in non-production environment!')
    //   return
    // }

    // 添加自定义脚本
    result.html = addHead(
      result.html,
      headHtmlCode
    )

    // 也可以在特定页面添加统计脚本
    if (/test\/page1/gi.test(url)) {
      // TODO:在此添加逻辑
    }
  })
}

function addHead(html, content) {
  // Cheerio HTML
  const $ = load(html)
  $('head').append(content)
  return $.html()
}

最后,在项目中的 nuxt.config.js 增加以下内容,安装自定义 module:

JavaScript
1
2
3
4
5
{
  modules: [
    '~/modules/head-script',
  ]
}

Nuxt 2 如何在 Vue 组件 head() 中插入自定义 script

JavaScript
export default {
  head() {
    return {
      script: [
        // 插入jquery库
        {
          async: false,
          src: "https://code.jquery.com/jquery-3.7.0.min.js"
        },
        // 插入jsonLd
        {
          innerHTML: JSON.stringify({
            "@context": "https://schema.org/",
            "@type": "Product"
          }, null, 2),
          type: "application/ld+json"
        },
        // 插入统计数据
        {
          innerHTML: `
var dataLayer=[{
   'value': 0,
}];
`
        }
      ],
      // 允许危险的script内容
      __dangerouslyDisableSanitizers: ["script"]
    }
  }
}

Nuxt 2 如何在页面载入前判断是否手机端

在载入前判断用户是否手机端,ssr自动渲染对应的UI,可以避免页面出现闪烁,并且减少不必要的流量消耗

首先,创建**路由中间件** middleware/header-config.js,写入以下内容。这段代码用于告诉服务器,访问的浏览器的视口宽度,以便判断是否为手机。

JavaScript
export default function ({isHMR, req, res}) {
  if (isHMR) return

  try {
    if (req) {
      // https://masteringnuxt.com/blog/mobile-detection-with-nuxt-ssr
      res.setHeader('Accept-CH', 'Viewport-Width, Downlink')
    }
  } catch (e) {
    console.error(`[header-config]`, e)
  }
}

store/index.js 中添加 isMobile 相关内容,这样就可以以全局变量的方式访问。

JavaScript
export const state = () => ({
  // 检测是否手机
  isMobile: false,
})

export const mutations = {
  setIsMobile(state, flag) {
    state.isMobile = flag
  },
}

安装手机检测库:yarn add mobile-detect,然后创建自定义插件 plugins/my-plugin-ssr.js,这个插件用于判断是否为手机。

JavaScript
import MobileDetect from 'mobile-detect'

export default ({req, store}) => {
  // Detect isMobile before page load
  // https://masteringnuxt.com/blog/mobile-detection-with-nuxt-ssr
  const md = new MobileDetect(req.headers['user-agent'])
  const isMobile = md.phone() !== null || md.mobile() === 'UnknownMobile'

  store.commit('setIsMobile', isMobile)
}

最后,在 nuxt.config.js 中注册插件,即可使用。

JavaScript
1
2
3
4
5
6
7
8
9
{
  plugins: [
    {src: '~/plugins/my-plugin-ssr.js', mode: 'server'},
  },
  router: {
    // 路由中间件
    middleware: ['header-config'],
  }
}

要在 Vue 组件内访问 isMobile,直接使用以下方式。这个属性会在Vue组件挂载前自动设置值。

Text Only
1
2
3
4
5
export default {
  computed: {
    ...mapState(['isMobile']),
  },
}

后续需要根据用户屏幕大小动态更新 isMobile 属性,可以在全局默认 layout/default.vue 中增加以下代码。

安装依赖:yarn add throttle-debounce,此处使用的版本是 "throttle-debounce": "^2.3.0"

JavaScript
import {mapState} from 'vuex'
import {debounce} from 'throttle-debounce'

export default {
  computed: {
    ...mapState(['isMobile']),
  },
  mounted() {
    this.resizeDebounced()
    this.resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
    window.addEventListener(this.resizeEvt, this.handleResize)
  },
  beforeDestroy() {
    window.removeEventListener(this.resizeEvt, this.handleResize)
  },
  methods: {
    handleResize() {
      this.debounceCheckDevice(this)
    },
    debounceCheckDevice: debounce(200, false, (self) => {
      self.resizeDebounced()
    }),
    // 判断手机特性
    resizeDebounced() {
      const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
      // $mq_mobile_width
      this.$store.commit('setIsMobile', vw <= 567)
    },

  },
}

TODO: 待填坑:

Text Only
1
2
3
4
5
## Nuxt 2 如何设置 `.env` 环境变量 (区分开发、测试、生产环境)

## Nuxt 2 如何实现批量页面重定向 (使用modules)

## Nuxt 2 如何灵活的使用组件级别 i18n(多语言) 功能