2019-04-11 | 服务端渲染 | UNLOCK

全局组件和构造组件

自己需要知道自定义组件的一些细节

data 必须是一个函数

data () {
  return {
    ......
  }
}

一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,相互之间不会因为组件的复用而影响到其他的实例

全局注册和局部注册

// 注册组件,传入一个扩展过的构造器
Vue.component(
  'myComponent',
  Vue.extend({
    /* ... */
  })
)

// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', {
  /* ... */
})

Vue.extend(options)

使用基础 Vue 构造器,创建一个“子类”

Vue.nextTick(cb)

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

Vue.nextTick(() => {...})

// promise

Vue.nextTick().then(() => {...})

判断是否是服务端还是客户端

Node 和浏览器之间存在许多微小的环境差异,全局化组件需要注册在 window 上,如果在 Node 中,由于 window 不存在,程序会报错,可以使用下面两种方法避免在服务端使用 window

void 0undefinednull

undefined 表示未定义, 一般我们可以用全局变量 undefined (就是名为 undefined 的这个变量) 来表示这个值
但是 JS 中 undefined 只是一个变量,并不是一个关键字,可以被篡改
解决方法: void 可以把任何一个表达式变成 undefined ,一般使用 void 0 来获取 undefined

  • typeof window === void 0

    null 是 JS 中的关键字,可以使用 null 变量来获取 null 的值

使用 typeofwindow 进行判断,即使 window 不存在, 也不会报错,只会返回 undefined
使用 typeof 判断 window 是否存在,如果 返回的值是 undefined, 则不会继续后续对 window 的操作和注册全局的组件

  • process.browser

    在浏览器中它返回 true,而在 Node 中它返回 false, 也可以用来判断是服务端还是客户端

全局化挂载组件

  • 首先完成一个简单的组件
<!-- SuccessBox.vue -->
<template>
  <div class="success-wrapper center-flex" @click="close" v-if="visible">
    <div class="success-container" @click.stop>
      <div class="bg-container">
        <img src="../assets/success_icon.png" alt="" class="bg-img" />
      </div>
      <div class="success-header">
        {{data.header}}
      </div>
      <div class="success-detail" v-for="(item, key) in data.detail" :key="key">
        {{item}}
      </div>
      <div class="success-tip" v-if="data.tip">
        {{data.tip}}
      </div>
      <div class="success-button" @click.stop="close">
        确认
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'SuccessBox',
    props: {},
    data() {
      return {
        visible: true,
        data: {
          header: '购买成功',
          detail: ['购买成功!', '请在门店支付订单后进行兑换!'],
          tip: ''
        }
      }
    },
    methods: {
      close() {
        this.visible = false
      }
    }
  }
</script>
  • 挂在到全局对象 window
// utils/SuccessBox.js

import Vue from 'vue'
const SuccessBox = Vue.extend(require('@/common/successBox.vue').default)

let instance

export default {
  show: (data = {}, callback) => {
    if (typeof document === 'undefined') return // 服务端渲染
    // 挂载到全局对象上
    if (!instance) {
      instance = new SuccessBox({
        el: document.createElement('div')
      })
      document.body.appendChild(instance.$el)
    }
    if (callback) instance.callback = callback
    instance.data = { ...instance.data, ...data }
    Vue.nextTick(() => {
      instance.visible = true
    })
  }
}
  • 挂载到全局
//  nuxt.config.js
  plugins: [
    { src: '~plugins/vue-awesome-swiper.js', ssr: false }, // swiper
    '~plugins/$SuccessBox.js'
  ],