vue3快速拥抱element-ui

266 阅读3分钟

前序

Vuejs 3.0 在北京时间2020年9月 19 日凌晨,终于发布了 3.0 版本,代号:One Piece

对于我们日常维护的vue2.5.x版本,尤大并不建议我们来升级它,那么我们又如何快速体验hook带来的体验呢?

用完hook的我,只能说一句真香!!!

再也不担心mixins的乱套,也不用逼逼赖赖的找mixins带来的变量覆盖,找不到变量在哪一次的使用

vue官网也提供了相对应的api,让我们在v2.5.x版本中,可以体验vue3带来的api改变

那就不得不用到vue官网提供的@vue/composition-api

vue3生命周期

  • setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
  • onBeforeMount() : 组件挂载到节点上之前执行的函数。
  • onMounted() : 组件挂载完成后执行的函数。
  • onBeforeUpdate(): 组件更新之前执行的函数。
  • onUpdated(): 组件更新完成之后执行的函数。
  • BeforeUnmount(): 组件卸载之前执行的函数。
  • Unmounted(): 组件卸载完成后执行的函数
  • Activated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行。
  • onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。
  • onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数(以后用到再讲,不好展现)

实践

安装依赖 @vue/composition-api

npm install @vue/composition-api --save

针对现有页面进行改造,举个栗子:login.vue

代码量可能会相对比较多,请耐心查看一下~~~

export default {
  data() {
    return {
      codeUrl: '',
      cookiePassword: '',
      loginForm: {
      username: '',
      password: '',
      rememberMe: false,
      code: '',
      uuid: '',
    },
    loginRules: {
      username: [
        { required: true, trigger: 'blur', message: '用户名不能为空' },
      ],
      password: [
        { required: true, trigger: 'blur', message: '密码不能为空' },
      ],
      code: [
        { required: true, trigger: 'change', message: '验证码不能为空' },
      ],
    },
    loading: false,
    redirect: undefined
    }
  },
  watch: {
    $route: {
      handler: function (route) {
      	console.log('111')
      },
      immediate: true,
    },
  },
  created() {
    this.getCode()
    this.getCookie()
    if (process.env.NODE_ENV !== 'production') {
      this.loginForm.username = 'admin'
      this.loginForm.password = 'admin123'
    }
  },
  methods: {
    getCode() {
      getCodeImg().then((res) => {
        this.codeUrl = 'data:image/gif;base64,' + res.img
        this.loginForm.uuid = res.uuid
      })
    },
    getCookie() {
      const username = Cookies.get('username')
      const password = Cookies.get('password')
      const rememberMe = Cookies.get('rememberMe')
      this.loginForm = {
        username: username === undefined ? this.loginForm.username : username,
        password:
          password === undefined ? this.loginForm.password : decrypt(password),
        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
      }
    },
    handleLogin() {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          this.loading = true
          if (this.loginForm.rememberMe) {
            Cookies.set('username', this.loginForm.username, { expires: 30 })
            Cookies.set('password', encrypt(this.loginForm.password), {
              expires: 30,
            })
            Cookies.set('rememberMe', this.loginForm.rememberMe, {
              expires: 30,
            })
          } else {
            Cookies.remove('username')
            Cookies.remove('password')
            Cookies.remove('rememberMe')
          }
          this.$store
            .dispatch('Login', this.loginForm)
            .then(() => {
              this.$router.push({ path: this.redirect || '/' })
            })
            .catch(() => {
              this.loading = false
              this.getCode()
            })
        }
      })
    },
  }
}

调整 data 方法

为了简单方便演示效果,所以以下处理直接使用reactive,可以根据自己实际项目需要使用

  • reactive 递归监听
  • ref
  • shallowRef, shallowReactive非递归监听
  • toRaw 不想被监听

等方法,请自行根据api选择

import { reactive, toRefs } from '@vue/composition-api';
export default {
  setup() {
  	let state = reactive({
      codeUrl: '',
      cookiePassword: '',
      loginForm: {
        username: '',
        password: '',
        rememberMe: false,
        code: '',
        uuid: '',
      },
      loginRules: {
        username: [
          { required: true, trigger: 'blur', message: '用户名不能为空' },
        ],
        password: [
          { required: true, trigger: 'blur', message: '密码不能为空' },
        ],
        code: [
          { required: true, trigger: 'change', message: '验证码不能为空' },
        ],
      },
      loading: false,
      redirect: undefined,
    })
  }
  
  return {
  	 ...toRefs(state)
  }
}

调整 methods 方法

export default {
    setup() {
      getCode() {
        getCodeImg().then(res => {})
      }
      getCookie() {},
      handleLogin() {}

      return {
        getCode,
        getCookie,
        handleLogin
      }
    }
}

调整this.$refs获取

<template>
  <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
  </el-form>
</template>
import { onMounted } from '@vue/composition-api'
export default {
  setup() {
    const loginForm = ref(null)

    onMounted(() => {
      // 这里就等于我们的 this.$refs
      console.log(loginForm.value)
    });

    return {
      loginForm
    }
  }
}

调整created方法

由于vue3的 beforeCreatecreated 被调整为 setup,具体生命中取

export default {
  setup() {
    this.getCode()
    this.getCookie()
    if (process.env.NODE_ENV !== 'production') {
      this.loginForm.username = 'admin'
      this.loginForm.password = 'admin123'
    }
  }
}

调整this

用于vue3的生命周期,setup方法里并没有this概念,因此我们得把页面涉及到this都要做更改

为方便演示,代码中只重写getCode的逻辑写法

<el-form-item prop="code">
  <el-input
    v-model="loginForm.code"
    auto-complete="off"
    placeholder="验证码"
    style="width: 63%"
    @keyup.enter.native="handleLogin"
  >
    <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
  </el-input>
  <div class="login-code">
    <img :src="codeUrl" @click="getCode" />
  </div>
</el-form-item>
import { ref, reactive, toRefs } from '@vue/composition-api'
export default {
  setup() {
    let codeUrl = ref('')
    
    // 以下也可以用ref处理,这样在赋值的时候得用 store.value 
    let store = reactive({
       loginForm: {
         username: ''
      }
    })
    
    const getCode = () => {
      getCodeImg().then((res) => {
        codeUrl.value = 'data:image/gif;base64,' + res.img
       	store.loginForm.uuid = res.uuid
      })
    }
    
    return {
      codeUrl,
      ...toRefs(store),
      getCode,
    }
  }
}

$route$router怎么获取?

由于我们是基于vue2.x版本进行改造的,而vuex,vue-router并没有相对应的升级,所以并不能使用useStore或者Router相关的api方法,因此,$route$store我们可以从如下获取

setup存在2个参数

export default {
  setup(prop, context) {
    console.log(prop) // 组件可以拿到父组件传过来的消息
    console.log(context) // 当前上下文
    
    let {
      $store, // 这个对应 this.$store
      $router, // 这个对应 this.$router
      $route, // 这个对应 this.$route
      $confirm, // 这个是element-ui this.$confirm 的方法
    } = context.root;
    
    // 以上变量就可以拿到传递过来的参数了
  }
}

友情链接

@vue/composition-api