前言

在掘金上摸鱼看到了“一个基于vue3+vite+ts的完整项目”的文章,好了我也要开始搞一搞vue3.0,反正最近打算搞个新项目,干脆就用新的;
于是开始摸鱼看文章了,现在也很多关于3.0的文章看看,(学习中,不对的,欢迎纠正)
文档:.官方(应该是吧
Vue 组合式 API:https://composition-api.vuejs.org/zh/api.html

安装

  • 方式1(使用Vite安装)
    可以康康我的上一篇vite 搭建 Vue3.0项目

  • 方式2(使用Vue-cli安装),然而这个项目是用的Vue-cli安装的
    脚手架 vue-cli:

npm install -g @vue/cli # OR yarn global add @vue/cli
vue create hello-vue3
# select vue 3 preset

目前的了解(值得注意的新特性)

this指向的变化

  • Vue2.0 this直接指向组件实例
  • Vue3.0 this指向组件代理对象,代理对象在指向组件实例

2.x vs 3.0 钩子函数

在这里插入图片描述

setup

新的 setup 组件选项在创建组件之前执行,一旦 props 被解析,作为在组件内使用 Composition API 的入口点。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用。

!注意:由于在执行 setup 时尚未创建组件实例,
因此在 setup 选项中没有 this。这意味着,除了 props 之外,
你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。

响应式数据:Vue3.0则需要在setup 中通过ref或者reactive 来声明响应式数据。

setup 选项应该是props,context

  • props:props 是响应式的,当传入新的 prop 时,它将被更新,但是不能使用 ES6 解构,因为它会消除 prop 的响应性,如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作
  • context:context是一个普通的对象(不是响应式的)并且暴露出3个组件属性: 1. arrts 2.emit 3.slots

从 setup 返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。

export default {
  components: {},
  props: {
    user: { type: String }
  },
  setup(props,{attrs, slots, emit}) {
    console.log(props) // { user: '' }
    return {} // 这里返回的任何内容都可以用于组件的其余部分
  }
  // 其余部分
}

在这里插入图片描述

ref

ref 是一个函数,它接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。而ref只能监听简单类型的变化,不能监听复杂类型的变化(对象/数组)。 它的本质是reactive,当我们给ref函数传递一个值时,ref函数会自动将ref转换成reactive
从 setup 返回的 refs 在模板中访问时是被自动解开的,因此不应在模板中使用 .value

import { ref } from 'vue'

const counter = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

如果传入 ref 的是一个对象,将调用 reactive 方法进行深层响应转换。

isRef

isRef用于判断变量是否为ref对象。isRef(数据),返回true或者是false。

import {isRef} from 'vue'

reactive

接收一个普通对象然后返回该普通对象的响应式代理。

 /** 
 *@reactive:处理的是对象的双向绑定, 对象不能被解构或展开,一旦被解构或者展开,返回的值将失去响应式
 */
 export default {
  components: {},
  props: {
    user: { type: String }
  },
  setup(props) {
    console.log(props) // { user: '' }
    const formData = reactive({
	      user: "",
	      password: "",
	      companyName: ""
	});
    return {
    	formData,
    	formData.user  //解构或展开这里将失去响应式
    } 
  }
}

isReactive

检测一个数据是否是reactive类型的。可以用isReactive(数据),返回true或者false。

import {isReactive} from 'vue'

toRefs

toRefs用于将一个reactive对象转化为属性全部为ref对象的普通对象。

const state = reactive({
  foo: 1,
  bar: 2
})
const stateAsRefs = toRefs(state)
/*
Type of stateAsRefs:
{
  foo: Ref<number>,
  bar: Ref<number>
}
*/
// toRefs在setup或者Composition Function的返回值时可以保证在使用解构语法之后对象依旧为相应式

watch 响应式更改

使用从 Vue 导入的 watch 函数执行相同的操作。它接受 3 个参数:
一个响应式引用或我们想要侦听的 getter 函数
一个回调
可选的配置选项

import { ref, watch } from 'vue'

const counter = ref(0)
watch(counter, (newValue, oldValue) => {
  console.log('The new counter value is: ' + counter.value)
})

项目

登录页面

<template>
  <div class="login">
    <div class="login-mask">
      <div class="login-form-wrap">
        <div class="login-form">
          <div class="login-form-content">
            <header>
              <!-- <img src="@/assets/logo.png" /> -->
              <h1>welcome 登录界面</h1>
            </header>
            <a-form :model="formData" :rules="formRules" ref="formRef">
              <a-form-item name="companyName">
                <a-input
                  size="large"
                  v-model:value="formData.companyName"
                  placeholder="请输入公司名称"
                />
              </a-form-item>
              <a-form-item name="account">
                <a-input
                  size="large"
                  v-model:value="formData.account"
                  placeholder="请输入用户名"
                />
              </a-form-item>
              <a-form-item name="password">
                <a-input-password
                  autofocus="autofocus"
                  size="large"
                  visibilityToggle
                  v-model:value="formData.password"
                  placeholder="请输入密码"
                />
              </a-form-item>
              <a-form-item>
                <a-button
                  type="primary"
                  size="large"
                  block
                  @click="login"
                  :loading="formState.loading"
                  >登录</a-button
                >
              </a-form-item>
            </a-form>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
/**
 * @reactive : 处理的是对象的双向绑定, 对象不能被解构或展开,一旦被解构或者展开,返回的值将失去响应式
 *
 * @ref : 处理js基础类型的双向绑定,其实ref的实现原理也只是对基础类型进行对象化封装,
 *        把数据放在{ value: 基础值 }里,再添加一个ref标识属性用来区分
 */
import { defineComponent, reactive, ref, unref, toRaw } from "vue";
import { useRouter, RouteLocationRaw } from "vue-router";
import { notification } from "ant-design-vue";
import API from "../../api/api";
import { Md5 } from "ts-md5";

export default defineComponent({
  /** 所有的代码逻辑将在setup方法中实现,并且不再有this */
  setup() {
    /** 返回值 */
    const formData = reactive({
      account: "",
      password: "",
      companyName: ""
    });
    const formRef = ref<any>(null);
    const formState = reactive({
      loading: false
    });
    const formRules = reactive({
      companyName: [
        { required: true, message: "请输入公司名称", trigger: "blur" }
      ],
      account: [{ required: true, message: "请输入账号", trigger: "blur" }],
      password: [
        { required: true, message: "请输入密码", trigger: "blur" },
        {
          pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$/,
          max: 12,
          min: 6,
          message: "密码应该在6-12长度之间字母和数字的组合",
          trigger: "blur"
        }
      ]
    });
    /** 路由 */
    const router = useRouter();
    const toPage = (path: RouteLocationRaw) => router.push(path);
    /** 方法 */
    async function handleLogin() {
      const form = unref(formRef);
      if (!form) return;
      formState.loading = true;
      try {
        const data = await form.validate();
        // 调用登录接口API
        API.loginAPI
          .login(
            toRaw({
              companyName: data.companyName,
              password: Md5.hashStr(data.password),
              workerId: data.account
            })
          )
          .then(response => {
            console.log("loginInfo: ", response);
            localStorage.token = response.data.token;
            localStorage.login_userName = data.account;
            localStorage.login_companyName = data.companyName;
            toPage("/layout");
            setTimeout(() => {
              notification["success"]({
                message: "登录成功",
                description: "尊敬的" + data.account + "用户,欢迎回来!"
              });
            }, 500);
          })
          .catch(e => {
            console.log(e);
          });
      } catch (error) {
        notification["error"]({
          message: "登录失败",
          description: "请检查您的用户名或者密码是否正确!"
        });
      } finally {
        formState.loading = false;
      }
    }
    /** 返回值  */
    return {
      formRef,
      formData,
      formState,
      formRules,
      login: handleLogin
    };
  }
});
</script>
<style lang="stylus" scoped>
// 样式就省略吧
</style>

项目地址

GitHub:https://github.com/peiyu-ye/vue3.0-front(哈哈哈,觉得有用给个 Star)

Logo

前往低代码交流专区

更多推荐