如何在Nuxt.js中创建一个全局自定义插件

1,140 阅读3分钟

Nuxt.js,像Vue一样,支持插件,可以有三种类型:定制的插件,Vue插件,以及外部包和模块。虽然Nuxt文档详细讨论了后两者,但他们只简单地解释了如何在你的Nuxt应用程序中构建和使用自定义插件。

一个全局的自定义插件在一些情况下可以派上用场。例如,让我们想象一下,你无法为你试图实现的功能找到一个开源插件,或者你对你找到的插件不完全满意。或者,也许你觉得有点创意,而且你手上有一些时间。

在本教程中,我们将介绍使用Vue和JavaScript建立我们自己的自定义插件的两种不同选择。作为一个例子,我们的自定义插件将在你的Nuxt应用程序的控制台中显示我的生日,但你可以根据你的项目需求进行个性化定制。让我们开始吧!

构建组件

第一步是构建Vue组件。对于这篇文章,我们将使用一个基本的toast组件,它将显示简单的成功和错误信息。我已经为这篇文章构建了一个,我们稍后会详细讨论它:

<template>
  <div class="toast-element">
    <div :class="['toast-container', { success: state === 'success', error: state === 'error' }]">
      <div class="icon">
        <svg
          v-if="state === 'success'"
          width="8"
          height="7"
          viewBox="0 0 8 7"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path d="M6.96304 0.962891L2.88896 5.37647L1.03711 3.3703" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
        </svg>
        <svg
          v-else
          width="3"
          height="10"
          viewBox="0 0 3 10"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path d="M1 1.6665V4.99984" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
          <path d="M1 8.3335H1.00833" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
        </svg>
      </div>
      <p>
        {{ message }}
      </p>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      toastIsVisible: false,
      message: '',
      state: ''
    }
  },
  mounted () {
    this.$store.subscribe((mutation, state) => {
      if (mutation.type === 'toast/showToast') {
        this.message = state.toast.content
        this.state = state.toast.state
        this.toastIsVisible = true
        document.querySelector('.toast-element').classList.add('enter')
        setTimeout(() => {
          if (this.toastIsVisible) {
            this.removeToast()
          }
        }, 3000)
      }
    })
  },
  methods: {
    removeToast () {
      document.querySelector('.toast-element').classList.replace('enter', 'leave')
      setTimeout(() => {
        this.toastIsVisible = false
      }, 240)
    }
  }
}
</script>

<style scoped>
.toast-element {
  position: fixed;
  top: -90px;
  left: 0;
  width: 100%;
  height: max-content;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 7;
  opacity: 0;
  transition: all 240ms cubic-bezier(0, 0.0, 0.2, 1) 0s;
}
.enter {
  top: 20px;
  opacity: 1;
}
.leave {
  top: 20px;
  transform: scale(0.9);
}
.toast-container {
  width: fit-content;
  border: 1px solid transparent;
  border-radius: 5px;
  padding: 0.9375rem 1.875rem;
  display: grid;
  grid-template-columns: repeat(2, max-content);
  column-gap: 0.9375rem;
  align-items: center;
}
.success {
  border-color: #037F10;
  background-color: #F4FFF6;
}
.error {
  border-color: #FF2525;
  background-color: #FFF4F4;
}
.icon {
  border-radius: 50%;
  display: flex;
}
.success .icon {
  padding: 6px;
  background-color: #037F10;
}
.error .icon {
  padding: 5px 8px 5px 9px;
  background-color: #FF2525;
}
p {
  width: max-content;
  font-size: 1.0625rem;
  font-weight: 400;
}
.success p {
  color: #037F10;
}
.error p {
  color: #FF2525;
}
</style>

吐司组件创建了两个按钮,看起来像下面这样:

Toast Error

吐司组件错误信息:

Toast Success

吐司组件的成功信息

如果你回顾一下toast组件,你会注意到对商店的subscribe() 方法的调用。因为我们的组件是动态的,我们需要从某个地方获得内容,即商店。

商店

在我们的toast组件中,有两个变量,toast消息和它的状态,要么是success ,要么是error在Vuex的帮助下,我们将在Nuxt应用程序中存储状态。因此,我们需要一个商店,最好是与应用程序的一般商店不同的商店:

export const state = () => ({
  content: '',
  state: ''
})

export const mutations = {
  showToast (state, payload) {
    state.content = payload.content
    state.state = payload.state
  }
}

订阅组件到商店

现在我们的商店已经准备好了,我们需要在商店和toast组件之间建立一个通信通道。在这里,subscribe() 方法派上了用场,将组件订阅到商店的突变中。因此,它在商店的每次突变后被调用,接收突变和状态对象作为参数。要了解更多关于subscribe() 方法的信息,请查看Vuex API页面上的订阅部分

因为subscribe() 方法是在商店的每次突变后被调用的,我们需要确认toast商店被突变了。一旦我们确认了这一点,我们就可以继续更新组件的变量、消息和它的状态:

this.$store.subscribe((mutation, state) => {
  if (mutation.type === 'toast/showToast') {
    this.message = state.toast.content
    this.state = state.toast.state
    this.toastIsVisible = true
    document.querySelector('.toast-element').classList.add('enter')
    setTimeout(() => {
      if (this.toastIsVisible) {
        this.removeToast()
      }
    }, 3000)
  }
})

我们检查突变的类型是toast/showToast ,因为我们的toast存储在toast.js ,而突变的方法是showToast()

初始化该插件

现在我们已经完成了组件的构建和功能的实现,我们需要让它在Nuxt应用程序中可用,这样我们就可以在需要时调用show 方法来显示吐司组件;我们将在plugins 文件夹中这样做。

让插件在整个应用中可用也被称为注入插件,Vue为此提供了inject() 函数。这又给show 方法的对象加上了一个$ 的前缀:

export default ({ app, store }, inject) => {
  inject('toaster', {
    showToast ({ content = '', state = '' }) {
      store.commit('toast/showToast', { content, state })
    }
  })
}

因此,每当我们在Nuxt应用中调用这个$toaster.showToast() 方法时,我们也需要传入contentstate 参数。

然而,如果你的插件是用于一些JavaScript功能,比如在我们的例子中,显示我的生日,那么你只需要下面的代码:

export default ({ app }, inject) => {
  inject('displayBirthday', () => {
    console.log(`March 3rd!`)
  })
}

$displayBirthday() 将记录我的生日到你的控制台。对于这样的情况,你就不需要一个商店或一个组件。

如果你仔细注意了这两段代码,你会注意到inject() 函数的第二个参数的类型不同。第一个是一个对象,而第二个是一个函数。当你的插件可能需要多个动作时,对象类型很有用,而函数则最适合于单个动作。然而,对象中可以只有一个方法。

定义和注册插件

在我们渲染插件之前,我们的Nuxt应用程序需要确认toast插件的存在。我们可以使用nuxt.config.js 文件中的plugins 属性来添加这方面的代码:

export default {
  plugins: [
    { src: '~/plugins/toaster' }
  ]
}

插件的注入代码在plugins/toaster.js 文件中。

使用该插件

这样一来,我们的插件就可以使用了!要看到我们的插件在运行,首先,toast组件需要出现在页面上。然后,我们可以调用我们商店的$toaster.showToast() 方法,并传递contentstate 参数:

this.$toaster.showToast({
  content: 'Successfully logged in!',
  state: 'success'
})

总结

在这篇文章中,我们已经学会了如何使用Vue和JavaScript在Nuxt应用程序中建立一个全局的自定义插件。你可以使用这个组件在你的应用程序中实现不同类型的功能,当你找不到适合你项目需求的开源插件时,它就派上用场了。我们还讨论了如何去使用该插件的组件,以及当该插件不需要组件时该怎么办。

虽然我们这个教程的例子展示了相当简单的功能,在控制台中显示一个日期,但可以自由地在这个项目的基础上进行定制,以满足你的需求。关于Nuxt插件的更多信息,我建议查看Nuxt文档。祝你建设愉快!