【问题标题】:"document is not defined" in Nuxt.jsNuxt.js 中的“文档未定义”
【发布时间】:2018-02-13 23:03:02
【问题描述】:

我正在尝试在 Vue 组件中使用 Choices.js。组件编译成功,但随后触发错误:

[vue-router] 无法解析异步组件默认值: ReferenceError: 文档未定义

在我看到的浏览器中:

ReferenceError 文档未定义

我认为这与 Nuxt.js 中的 SSR 有关吗?我只需要 Choices.js 在客户端上运行,因为我猜这是客户端唯一的方面。

nuxt.config.js

build: {
  vendor: ['choices.js']
}

AppCountrySelect.vue

<script>
import Choices from 'choices.js'

export default {
  name: 'CountrySelect',
  created () {
    console.log(this.$refs, Choices)
    const choices = new Choices(this.$refs.select)
    console.log(choices)
  }
}
</script>

在经典的 Vue 中,这可以正常工作,所以我仍然非常了解如何让 Nuxt.js 以这种方式工作。

有什么想法我哪里出错了吗?

谢谢。

【问题讨论】:

    标签: javascript vue.js vuejs2 nuxt.js


    【解决方案1】:

    启动 Nuxt 项目时这是一个常见错误 ;-)

    Choices.js 库仅适用于客户端!所以 Nuxt 尝试从服务器端渲染,但是从 Node.js window.document 不存在,那么你有一个错误。
    注意:window.document 只能在浏览器渲染器中使用。

    由于Nuxt 1.0.0 RC7,您可以使用&lt;no-ssr&gt; 元素来允许您的组件仅用于客户端。

    <template>
      <div>
        <no-ssr placeholder="loading...">
          <your-component>
        </no-ssr>
      </div>
    </template>
    

    看看这里的官方例子:https://github.com/nuxt/nuxt.js/blob/dev/examples/no-ssr/pages/index.vue


    更新:

    由于Nuxt >= 2.9.0,您必须使用&lt;client-only&gt; 元素而不是&lt;no-ssr&gt;

    <template>
      <div>
        <client-only placeholder="loading...">
          <your-component>
        </client-only>
      </div>
    </template>
    

    要了解更多信息,请参阅 nuxt 文档:https://nuxtjs.org/docs/2.x/features/nuxt-components#the-client-only-component

    【讨论】:

    • 谢谢!知道如何使用 SSR 输出元素本身吗?例如,一些 JS 需要在客户端为选择列表执行操作,但我仍然希望在服务器上呈现实际的选择列表。
    • &lt;your-component /&gt; 文件应该是什么样子?我有YourComponent.vue:&lt;template&gt;&lt;div&gt;&lt;/div&gt;&lt;/template&gt; &lt;script&gt; import Plotly from 'plotly.js/dist/plotly' export default {} &lt;/script&gt;,它仍然以document is not defined结束
    • nuxtjs.org/guide/plugins#client-side-only plugins: [ { src: '~/plugins/vue-notifications', mode: 'client' } ] 我会建议那些仍在努力寻找解决方案的人。
    • @JeffBluemel 您的解决方案拯救了我的一天。我必须在我的 nuxt.config.js { src: '~/plugins/vue-izitoast', mode: 'client' } 中添加这个
    • @JeffBluemel,在为解决方案敲了半天之后,您的解决方案是唯一对我有用的解决方案。我确实尝试了我在互联网上可以找到的所有内容。
    【解决方案2】:

    接受的答案(虽然正确)太短了,我无法理解和正确使用它,所以我写了一个更详细的版本。我一直在寻找一种使用plotly.js + nuxt.js的方法,但是应该和OP的Choice.js + nuxt.js的问题一样。

    MyComponent.vue

    <template>
      <div>
        <client-only>
          <my-chart></my-chart>
        </client-only>
      </div>
    </template>
    <script>
    export default {
      components: {
        // this different (webpack) import did the trick together with <no-ssr>:
        'my-chart': () => import('@/components/MyChart.vue')
      }
    }
    </script>
    

    MyChart.vue

    <template>
      <div>
      </div>
    </template>
    <script>
    import Plotly from 'plotly.js/dist/plotly'
    export default {
      mounted () {
        // exists only on client:
        console.log(Plotly)
      },
      components: {
        Plotly
      }
    }
    </script>
    

    更新:在 Nuxt v>2.9.0 中有 &lt;client-only&gt; 标签而不是 <no-ssr>,请参阅 @Kaz 的评论。

    【讨论】:

    • 这在我使用 evodiaaut.github.io/vue-marquee-text-component 时有效。大多数情况下 no-ssr 标记就足够了,但是有了这个库,我必须按照上面提到的方式导入。 @michal。你能解释一下这种导入背后的原因吗
    • @BaldeepSinghKwatra 不幸的是,据我所知,我通过反复试验得出了这个解决方案
    • 如果您使用的是 Nuxt 版本的 > v2.9.0,请使用 &lt;client-only&gt; 而不是 &lt;no-ssr&gt;。由于 &lt;no-ssr&gt; 已从 Nuxt v2.9.0 弃用
    【解决方案3】:

    您需要将其添加为插件,然后为其禁用 SSR。

    因为文档和窗口没有在服务器端定义。

    你的 nuxt.config.js 应该如下所示

    plugins: [
    { src: '~/plugins/choices.js' } // both sides
    { src: '~/plugins/client-only.js', mode: 'client' }, // only on client side
    { src: '~/plugins/server-only.js', mode: 'server' } // only on server side
    ],
    

    【讨论】:

    • 现在语法看起来像这样 { src: '~/plugins/client-only.js', mode: 'client' }, // 仅在客户端 { src: '~/plugins/ server-only.js', mode: 'server' } // 只在服务器端
    • 感谢指针@ArifIkhsanudin 我刚刚更新了答案。
    【解决方案4】:

    我发现现在 no-ssr 被替换了,我正在使用 echart 并且有同样的问题,但现在它可以工作了!

        <client-only>
            <chart-component></chart-component>
        </client-only>
    

    【讨论】:

    • &lt;no-ssr&gt; 从 Nuxt 版本 v2.9.0 中弃用。
    【解决方案5】:

    lightgallery.js 添加模式时出现此错误:'client' 似乎有帮助

    nuxt.config.js

     plugins: [
        { src: '~/plugins/lightgallery.js',  mode: 'client' }
      ],
    

    插件/lightgallery.js

    import Vue from 'vue'
    import lightGallery from 'lightgallery.js/dist/js/lightgallery.min.js'
    import 'lightgallery.js/dist/css/lightgallery.min.css'
    
    Vue.use(lightGallery)
    

    ImageGallery.vue

    <template>
      <section class="image-gallery-container">
        <div class="image-gallery-row">
          <div
            ref="lightgallery"
            class="image-gallery"
          >
            <a
              v-for="image in group.images"
              :key="image.mediaItemUrl"
              :href="image.mediaItemUrl"
              class="image-gallery__link"
            >
              <img
                :src="image.sourceUrl"
                :alt="image.altText"
                class="image-gallery__image"
              >
            </a>
          </div>
        </div>
      </section>
    </template>
    
    <script>
    export default {
      name: 'ImageGallery',
      props: {
        group: {
          type: Object,
          required: true
        }
      },
      mounted() {
        let vm = this;
    
        if (this.group && vm.$refs.lightgallery !== 'undefined') {
          window.lightGallery(this.$refs.lightgallery, {
            cssEasing: 'cubic-bezier(0.680, -0.550, 0.265, 1.550)'
          });
        }
      }
    }
    </script>
    

    【讨论】:

      【解决方案6】:
      <script>
      import Choices from 'choices.js'
      
      export default {
        name: 'CountrySelect',
        created () {
          if(process.client) {
            console.log(this.$refs, Choices)
            const choices = new Choices(this.$refs.select)
            console.log(choices)
          }
        }
      }
      </script>
      

      我想这应该会有所帮助,nuxt 在服务器上渲染后会触及计算的内部,并且将定义窗口

      【讨论】:

        【解决方案7】:

        这个帖子有点老了,但我会在这里留下我的解决方案,所以也许有人会觉得它有用。

        我最近在使用 vue-star-rating 和其他几个插件时遇到了类似的问题。


        可以根据插件名称、导入/使用设置遵循和调整以下步骤:

        1. 转到您的插件文件夹并创建新的js 文件,在本例中为vue-star-rating.js,然后将其编辑为setup the plugin

        import Vue from 'vue'
        import VueStarRating from 'vue-star-rating'
        
        Vue.component('vue-star-rating', VueStarRating); //<--- the name you used to register the plugin will be the same to use when in the component (vue-star-rating)
        
        1. 转到您的nuxt.config.js 文件并添加plugin

          plugins: [{
              src: '~/plugins/vue-star-rating', // <--- file name
              mode: 'client'
            },
            //you can simply keep adding plugins like this:
            {
              src: '~/plugins/vue-slider-component',
              mode: 'client'
            }]
        
        1. 现在您可以在应用程序的任何位置使用该插件了。但是,要做到这一点,您需要将其包装在容器 &lt;client-only&gt; 中。示例:

        <client-only placeholder="loading...">
           <vue-star-rating />
        </client-only>
        

        注意事项:

        您不需要在本地向组件导入任何内容,只需像上面那样使用它就可以解决问题。

        请确保在第 1 步和第 3 步这两个地方都以相同的方式命名插件。在这种情况下,它将是 vue-star-rating

        【讨论】:

          【解决方案8】:

          如果你还想做,可以这样取document对象:

          const d = typeof document === 'undefined' ? null : document
          

          【讨论】:

          • 我不确定这是否能解决问题。
          猜你喜欢
          • 2021-07-22
          • 1970-01-01
          • 1970-01-01
          • 2021-11-29
          • 2019-07-25
          • 2021-01-15
          • 2019-02-20
          • 2021-01-13
          • 2021-06-20
          相关资源
          最近更新 更多