Vue探索

Vue

生命周期

Setup()

@date 2021/3/18

@note 今天再看一个开源的系统项目

https://gitee.com/asaasa/element_vue3.0?_from=gitee_search#/asaasa/element_vue3.0/blob/dev/src%5Cplugins%5Cpermission.js

在看到它的登录部分时候,发现该页面不存在onCreate()等生命周期的处理,只是在一个Setup()中有处理,搜罗了一下相关的资料,汇总一下

抛出问题
  • 既然有了明确的生命周期分块,干嘛还要整一个Setup()这个东西

为了实现组合式API

关于什么是组合式API看官方的说明:

https://v3.cn.vuejs.org/guide/composition-api-introduction.html#%E4%BB%80%E4%B9%88%E6%98%AF%E7%BB%84%E5%90%88%E5%BC%8F-api

为什么使用组合式API?

当系统变得复杂时,在一个页面中引入了多个组件,组件的初始化在不同的生命周期中,各个组件的逻辑实现代码就会变得这里一块那里一块;类似于如下这张图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mAcwxDgF-1616059490197)(C:\Users\10651\AppData\Roaming\Typora\typora-user-images\image-20210318165743083.png)]

上面是一个大型组件的实例,逻辑点按照颜色区分

这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。

如果我们能够将与同一个逻辑关注点相关的代码配置在一起,这样会更好。而这正是组合式 API 使我们能够做到的

如何实现组合式API?

setup位于created 和beforeCreated之前,

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

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

// src/components/UserRepositories.vue

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup(props) {
    console.log(props) // { user: '' }

    return {} // 这里返回的任何内容都可以用于组件的其余部分
  }
  // 组件的“其余部分”
}

​ //reactive()函数接收一个普通对象,返回一个响应式的数据对象。

​ const form = reactive({

​ userName: “Administrator”,

​ pwd: “123456”

​ });

​ //toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据

​ const { userName, pwd } = toRefs(form);

​ const ref_form = ref(null);

​ const success = ref(false);

封装mock和axios

@date 2021/3/19
@note 今天看了一下这个Demo的登录模块,下面做一下记录

一步步看,先放一下登录模块的代码

<template>
    <common
        ><div class="ve_container">
            <el-card :body-style="{ background: 'rgba(0,0,0,0.15)' }">
                <h1>VE-Admin</h1>
                <transition name="el-fade-in-linear">
                    <el-form
                        :model="form"
                        :rules="rules"
                        v-show="!success"
                        class="ve_form"
                        ref="ref_form"
                        :inline="false"
                        @keyup.enter="onSubmit"
                    >
                        <el-form-item prop="userName">
                            <el-input
                                v-model.trim="userName"
                                placeholder="用户名"
                            ></el-input>
                        </el-form-item>
                        <el-form-item prop="pwd">
                            <el-input
                                v-model.trim="pwd"
                                show-password
                                placeholder="密码"
                            ></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-button
                                class="ve_submit"
                                type="primary"
                                @click="onSubmit"
                                >登录</el-button
                            >
                        </el-form-item>
                    </el-form>
                </transition>
            </el-card>
        </div></common
    >
</template>

<script>
import Common from "@/components/Common";
import { ref, reactive, toRefs } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
const rules = {
    userName: [{ required: true, message: "请输入用户名", trigger: "blur" }],
    pwd: [{ required: true, message: "请输入密码", trigger: "blur" }]
};
export default {
    name: "Login",
    components: { Common },
    // 关于setup() 的介绍 https://blog.csdn.net/qq_25506089/article/details/114743592?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
    setup() {
        const store = useStore();
        const router = useRouter();
        //reactive()函数接收一个普通对象,返回一个响应式的数据对象。
        const form = reactive({
            userName: "ces",
            pwd: "test"
        });
        //toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据
        const { userName, pwd } = toRefs(form);
        const ref_form = ref(null);
        const success = ref(false);
         //清除缓存
        sessionStorage.clear();
        //vuex的异步操作
        store.dispatch("app/set_token", "");
        router.options.isAddDynamicMenuRoutes = false;

        const onSubmit = () => {
            //validate 表单验证   element ui 的 form控件的用法
            ref_form.value.validate(async valid => {
                console.log("valid");
                console.log(valid);
                if (valid) {
                    //若校验成功
                    console.log("测试");
                    //这里对 mock和axios 进行了封装,直接调用 VE_API.user.login()即可访问到 配置的 axios请求(或者mock请求)
                    const data = await VE_API.user.login(form);
                    console.log(data);
                    if (data.code === "00") {
                        const { token, uname } = data;
                        store.dispatch("app/set_token", token);
                        store.dispatch("app/set_uname", uname);
                        success.value = true;
                        router.push({ name: "AppMain" });
                    }
                } else {
                    return;
                }
            });
        };
        return {
            success,
            form,
            ref_form,
            userName,
            pwd,
            rules,
            onSubmit
        };
    }
};
</script>

<style lang="scss" scoped>
.ve_container {
    position: absolute;
    width: 400px;
    top: 50%;
    left: 100px;
    transform: translateY(-50%);
    min-height: 273px;
    text-align: center;
    h1 {
        font-size: 36px;
        -webkit-transition-duration: 1s;
        transition-duration: 1s;
        -webkit-transition-timing-function: ease-in-put;
        transition-timing-function: ease-in-put;
        font-weight: 400;
        margin-top: 12px;
    }
    .ve_form {
        .ve_submit {
            width: 100%;
        }
    }
}
</style>

这里有上述讲到的 setup() 以及为什么要从vue中引入 ref, reactive, toRefs
其中 ref, reactive, toRefs 的作用在备注中有所标注,摘要出来:
toRefs : toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据

reactive : reactive()函数接收一个普通对象,返回一个响应式的数据对象

让我们继续往下看
ref_form.value.validate(async valid => {})
这里是element ui 表单控件的使用方法

下面就是到了网络请求的部分了,乍一看乱糟糟的,axios的request()去哪里了,处理请求结果的函数跑到哪去了?

来到 封装的 axios.js 文件下

/* eslint-disable indent */
/*
 * @Author: your name
 * @Date: 2020-10-16 10:38:49
 * @LastEditTime: 2021-03-03 13:47:21
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \vue_3.0_test\src\plugins\axios.js
 */
"use strict";

import axios from "axios";
import Qs from "qs";
import NProgress from "nprogress";

// Full config:  https://github.com/axios/axios#request-config
// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
const install = (app, { router, store, opt }) => {
    let config = {
        Global: true,
        // baseURL: process.env.baseURL || process.env.apiUrl || ""
        // timeout: 60 * 1000, // Timeout
        // withCredentials: true, // Check cross-site Access-Control
        transformRequest: [
            function(data) {
                // 对 data 进行任意转换处理
                if (VE_ENV.MODE === "production") {
                    //简单来说,qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库
                    /*
                        qs.parse()是将URL解析成对象的形式
                        qs.stringify()是将对象 序列化成URL的形式,以&进行拼接
                    */
                    return Qs.parse(data);
                } else {
                    return Qs.stringify(data);
                }
            }
        ]
    };

    const _axios = axios.create(config);
    let ve_loading;
    let ve_message = null;
    let loadingCount = 0;
    // 请求拦截
    _axios.interceptors.request.use(
        config => {
            console.log(config);
            //NProgress 是一个进度条插件
            NProgress.done();
            if (config.Global) {
                NProgress.start();
                ve_loading = app.config.globalProperties.$loading({
                    lock: true,
                    text: "Loading",
                    spinner: "el-icon-loading",
                    background: "rgba(0,0,0,0.1)"
                });
            }
            loadingCount++;
            //*请求头添加token
            const token = store.getters.token;
            token && (config.headers.Authorization = token);

            // Do something before request is sent
            return config;
        },
        error => {
            // Do something with request error
            return Promise.reject(error);
        }
    );

    // Add a response interceptor
    // 响应拦截
    _axios.interceptors.response.use(
        response => {
            // TODO 根据响应头更新token
            store.dispatch("app/set_token", new Date().getTime());

            loadingCount--;
            if (loadingCount <= 0) {
                NProgress.done();
                ve_loading.close();
            }

            let type = "success";
            if (response.data.code != "00") {
                type = "error";
            }
            if (ve_message) {
                ve_message.close();
                ve_message = null;
            }
            ve_message = app.config.globalProperties.$message({
                type,
                message: response.data.message
            });
            // Do something with response data
            return response.data;
        },
        error => {
            loadingCount--;
            if (loadingCount <= 0) {
                NProgress.done();
                ve_loading.close();
            }
            if (error && error.response) {
                let message = "";
                switch (error.response.status) {
                    case 400:
                        message = "请求错误";
                        break;
                    case 401: {
                        message = "未授权,请登录";
                        router.replace({
                            name: "Login"
                        });
                        break;
                    }
                    case 403:
                        message = "没有权限,拒绝访问";
                        break;
                    case 404:
                        message = `请求地址出错`;
                        break;
                    case 408:
                        message = "请求超时";
                        break;
                    case 500:
                        message = "服务器内部错误";
                        break;
                    case 501:
                        message = "服务未实现";
                        break;
                    case 502:
                        message = "网关错误";
                        break;
                    case 503:
                        message = "服务不可用";
                        break;
                    case 504:
                        message = "网关超时";
                        break;
                    case 505:
                        message = "HTTP版本不受支持";
                        break;
                    default:
                        break;
                }
                if (ve_message) {
                    ve_message.close();
                    ve_message = null;
                }
                ve_message = app.config.globalProperties.$message({
                    message,
                    type: "error"
                });
            }
            // Do something with response error
            return Promise.reject(error);
        }
    );

    const method = {
        post: (url, p, config) => _axios.post(url, p, config),
        get: (url, p, config) =>
            _axios.get(url, Object.assign(config, { params: p }))
    };

    let api = {};
    //  require.context 是webpack中,用来创建自己的(模块)上下文;
    /*
        需要搜索的文件夹目录(必传)
        是否需要搜索它的子孙目录,默认为false
        匹配文件名的正则表达式
    */
    const files = require.context("../mock/modules", false, /\.js$/);
    console.log(files);
    files.keys().forEach(key => {
        const fileName = key.replace(/(\.\/|\.js)/g, "");
        api[fileName] = {};
        let obj = files(key);
        Object.keys(obj).forEach(item => {
            api[fileName][item] = (p, config = {}) =>
                method[obj[item].type](obj[item].url, p, config);
        });
        console.log(obj);
        console.log(api);
    });

    window[opt] = api;
    // Object.defineProperties(app.config.globalProperties, {
    //     [opt]: {
    //         get() {
    //             return api;
    //         }
    //     }
    // });
};

export default { install };

在这里面引入了qs,备注中有解释qs是干嘛用的
简单来说,qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库


注意:它封装的 axios 类传入了router和store对象
请求拦截器处理token,注意拦截后对其返回


我们继续往下看


然后他对axios配置文件进行处理
首先获取 配置文件夹目录下的所有js文件
const files = require.context("../mock/modules", false, /\.js$/);
然后获取当前文件下的所有API接口
封装(两层):[文件名][配置名] : {get,post}
通过window[opt] = api;赋给全局的上下文,通过 关键词.文件名.配置名即可进行接口的调用


继续看功能

@date 2021/03/25
@note 今天继续看一下这个的源码,分析拆解一下
在这里插入图片描述
可以看到他的这个界面还是挺简约,布局也挺不错的,看了一下源码;它是将整个背景封装成了一个背景组件,然后在登录组件中引入了这个背景组件,其中那个小人以及左边的月球,星星都是使用div标签画出来的,用到了css中动画、定位、div曲率等等属性;难道是不难就是个细活,我在想有没有专门这种使用div画图一键导出css的网站,没有的话可以考虑做一个。


接下来还是去看功能代码
在源码中,很多使用如下的变量定义方式:
const { result, ip } = data;
直接定义 data 中的属性,然后后续直接使用 result 而不再使用 data.result 的方式
我们看到 点击【登录】事件的处理

		const onSubmit = () => {
            //validate 表单验证   element ui 的 form控件的用法
            ref_form.value.validate(async valid => {
                console.log("valid");
                console.log(valid);
                if (valid) {
                    //若校验成功,执行login api
                    console.log("测试");
                    const data = await VE_API.user.login(form);
                    if (data.state === 0) {
                        const { result, ip } = data;
                        store.dispatch("app/set_token", result);
                        store.dispatch("app/set_uname", ip);
                        console.log("token",ip);
                        // success.value = true;
                        router.push({ name: "AppMain" });
                    }
                } else {
                    return;
                }
            });
        };

项目

现在在看尚硅谷的项目教程
传送 : https://www.bilibili.com/video/BV1V5411K7rT?p=48
附一下前端项目地址:https://github.com/PanJiaChen/vue-element-admin

接下来都是围绕此项目做一下记录

@Date 2021/04/16
@Note 刚开始看这个项目

在看它的API接口时,发现定义的Base_URL的方式是我没有见过的

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

这个

process.env.VUE_APP_BASE_API

参考博客:
https://blog.csdn.net/qq_42783654/article/details/108842949

是定义在如下几个文件中的
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值