• 工作中遇到的问题与解决办法(三)


    Vite+vue3+ts

    创建Vue3项目

    检查工程文件夹

    cmd进入文件夹

    npm init vite(初始化工程)

    安装依赖

    npm install

    启动项目

    npm run dev

    setup语法糖

    <script setup lang='ts' name='hello'>
    </script>
    

    ref()响应式数据

    js要用.value,模板里面不用

    ref用于定义基本类型数据,js里面需要.value

    reactive用于定义对象类型数据,js里面不需要.value

    toRefs()转换

    vue3生命周期

    创建(steup)

    挂载

    onMount()

    更新

    onUpdated()

    卸载(销毁)

    onUnMounted()

    路由

    src取别名

    安装path模块

    npm install --save-dev @types/node
    

    修改 vite.config.ts 文件

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import path from 'path'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [vue()],
      resolve: {
        alias: {
          '@': path.resolve(__dirname, 'src')
        }
      }
    })
    

    修改tsconfig.js

    compilerOptions对象添加

    "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
        "paths": { //路径映射,相对于baseUrl
          "@/*": ["src/*"]
        }
    

    安装最新版路由

    npm install vue-router@next --save 
    或者npm install vue-router@4(vue3 版本)
    npm install vue-router@3(vue2 版本)
    

    新建router.index.ts

    import { createRouter, createWebHistory} from "vue-router"
    
    //创建路由
    const router = createRouter({
        history: createWebHistory(),
        routes:[
            //首页
            {
                path: '/home',
                name: 'home',
                component: () => import('@/views/Home.vue'),
            },
            //测试页面
            {
                path: '/test',
                name: 'test',
                component: () => import('@/views/test/index.vue'),
            },
        ]
    })
    //导出路由
    export default router;
    
    

    main.ts中使用路由

    import { createApp } from 'vue'
    import './style.css'
    import App from './App.vue'
    //路由
    import router from "./router/index.ts"
    const app = createApp(App);
    //使用路由
    app.use(router)
    app.mount('#app')
    

    App.vue中修改内容,使用占位

    
    
    
    
    
    
    

    这样浏览器url展示对应的vue页面

    history与hash模式

    编程式路由导航

    router.push()

    存储区

    这里使用pinia

    安装

    npm i pinia
    

    安装依赖

    main.ts全局使用

    import {createPinia} from 'pinia'
    const pinia = createPinia()
    use(pinia);
    

    store文件夹下面创建userStore.js

    import { defineStore } from "pinia";
    
    export const userStore = defineStore("userStore", {
      state: () => {
        return {
          token:'',
          userId: null,
          userName: null
        };
      },
      getters: {},
      actions: {},
    });
    

    使用

    <script setup>
    import { userStore } from '@/store/userStore'
    const user = userStore()
    const userId = user.userId
    </script>
    

    环境配置

    生产、开发、测试环境

    .env.development

    # 页面标题
    VITE_APP_TITLE = 首页
    # 开发环境配置
    VITE_APP_ENV = 'development'
    # 微信公众号/开发环境
    VITE_APP_BASE_API = '/dev-api'
    

    .env.production

    # 页面标题
    VITE_APP_TITLE = 首页
    
    # 生产环境配置
    VITE_APP_ENV = 'production'
    
    # 微信公众号/生产环境
    VITE_APP_BASE_API = '/prod-api'
    
    # 是否在打包时开启压缩,支持 gzip 和 brotli
    VITE_BUILD_COMPRESS = gzip
    

    .env.test

    # 页面标题
    VITE_APP_TITLE = 首页
    # 测试环境配置
    VITE_APP_ENV = 'test'
    # 微信公众号/开发环境
    VITE_APP_BASE_API = '/test-api'
    

    项目启动端口与后端请求地址

    vite.config.ts 新增

    // vite 相关配置
      server: {
        port: 8080,
        host: true,
        open: true,
        proxy: {
          // https://cn.vitejs.dev/config/#server-proxy
          '/dev-api': {
            target: 'http://localhost:8081',
            changeOrigin: true,
            rewrite: (p) => p.replace(/^\/dev-api/, '')
          }
        }
      },
    

    路径变化,页面title发生变化

    router文件

    import { createRouter, createWebHistory} from "vue-router"
    
    //创建路由
    const router = createRouter({
        history: createWebHistory(),
        routes:[
            //首页
            {
                path: '/index',
                name: 'index',
                component: () => import('@/views/index.vue'),
                meta:{
                    hidden:true,
                    title:"首页"
                }
            },
            //测试页面
            {
                path: '/test',
                name: 'test',
                component: () => import('@/views/test/index.vue'),
                meta:{
                    hidden:true,
                    title:"测试页面"
                }
            },
        ]
    })
    // 全局前置守卫
    router.beforeEach((to, from, next) => {
        // 在这里设置页面的标题
        document.title = to.meta.title || '首页';
        next();
    });
    
    //导出路由
    export default router;
    

    svg图标库配置

    安装

    npm i vite-plugin-svg-icons -D
    or
    pnpm install vite-plugin-svg-icons -D
    

    安装

    pnpm install fast-glob -D
    

    vite.config.ts配置插件

    import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
    plugins: [
          vue(),
          createSvgIconsPlugin({
            // 指定需要缓存的图标文件夹
            iconDirs: [path.resolve(process.cwd(), "src/assets/icons/svg")],
            // 指定symbolId格式
            symbolId: "icon-[dir]-[name]",
          }),
    
    

    main.ts导入

    //svg
    import 'virtual:svg-icons-register'   
    

    阿里云矢量图标库复制svg代码到存放文件夹

    页面使用

      
          //use 使用yygh.svg图标
      
    

    封装请求方法

    安装axios

    cnpm install axios
    

    安装vant

    cnpm instanll vant
    

    main.ts全局使用

    // 全局引入 Vant 所有组件
    import Vant from 'vant';
    import 'vant/lib/index.css';
    app.use(Vant)
    

    新建utils/request.ts

    import axios, { AxiosInstance, AxiosResponse }from "axios";
    import { showNotify } from 'vant';
    //引入store
    import {userStore} from '@/store/userStore.ts'
    const user = userStore();
    // 创建axios实例
    export const service:AxiosInstance = axios.create({
      //请求地址
      baseURL: import.meta.env.VITE_APP_BASE_API,
      // 超时
      timeout: 10000 * 20,
      //请求头
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
      },
    });
    // request拦截器,请求体加上token
    service.interceptors.request.use(
        (config: any) => {
            // prettier-ignore
            config.headers["Authorization"] = "Bearer " + user.token; // 让每个请求携带自定义token 请根据实际情况自行修改
          return config;
        },
        (error) => {
          Promise.reject(error);
        }
    );
    
    
    //响应拦截
    service.interceptors.response.use((res:AxiosResponse) => {
      // 未设置状态码则默认成功状态
      const code = res.data.code;
      // 获取错误信息
      // prettier-ignore
      const msg = res.data.msg;
      // 二进制数据则直接返回
      // prettier-ignore
      if (res.request.responseType === "blob" || res.request.responseType === "arraybuffer") {
        return res.data;
      };
      //返回状态码判断
      if (code === 401) {
        // 说明不通过微信公众号调用
        showNotify({ type: 'danger', message: '请关注微信公众号使用!' });
        // prettier-ignore
        return Promise.reject("请关注微信公众号!");
      } else if (code === 500) {
        showNotify({ type: 'danger', message: msg });
        return Promise.reject(new Error(msg));
      } else if (code !== 200) {
        showNotify({ type: 'danger', message: msg });
        return Promise.reject("error");
      } else {
        return res.data;
      }
    },  (error) => {
      let { message } = error;
      if (message == "Network Error") {
        message = "后端接口连接异常";
        showNotify({ type: 'danger', message: message });
      } else if (message.includes("timeout")) {
        message = "系统接口请求超时";
        showNotify({ type: 'danger', message: message });
      } else if (message.includes("Request failed with status code")) {
        message = "系统接口" + message.substr(message.length - 3) + "异常";
        showNotify({ type: 'danger', message: message });
      }
      return Promise.reject(error);
    
    });
    
    
    //对外暴露
    export default service;
    
    

    定义请求方法

    import request from "@/utils/request";
    
    
    /**
     * 测试查询
     */
    export const getTset = async () => {
        return await request({
            url: "/api/test",
            method: "get",
        });
    };
    
    
    

    测试调用

    
    

    springboot 获得token

    @Controller
    public class TestController {
        @GetMapping("/api/test")
        @ResponseBody
        public AjaxResult test(@RequestHeader("Authorization") String authHeader){
            // 假设token是Authorization头中的值,并且以"Bearer "开头
            String token = authHeader.replaceFirst("Bearer ", "");
            System.out.println(token+"??");
            return AjaxResult.success("xhengg");
        }
    }
    
    

    element ui plus 显示中文

    import zhCn from 'element-plus/es/locale/lang/zh-cn'
    app.use(ElementPlus,{locale:zhCn})
    

    element ui plus 单选框修改选中与不选择样式

    /* 覆盖被选中的el-radio样式 */
    :deep.el-radio.is-checked .el-radio__inner {
      border-color: #05BF9A !important; /* 选中时的边框颜色 */
      background-color: #05BF9A !important; /* 选中时的背景颜色 */
    }
    
    /* 当el-radio被选中时,改变对勾的样式 */
    :deep.el-radio.is-checked .el-radio__label {
      color: #05BF9A !important;
    }
    
    /* 覆盖被选中的el-radio样式 */
    :deep.el-radio.is-disabled .el-radio__inner {
      border-color:  #b1b3b8 !important; /* 选中时的边框颜色 */
      background-color:  #b1b3b8 !important; /* 选中时的背景颜色 */
    }
    
    

    c-loading修改样式

    css

    :deep .el-loading-spinner .path{
      stroke: #32b16c;
    }
    

    倒计时

    初始化

    const showDialog =()=>{
      dialogVisible.value = true;
      countDown.value = 30;
      const x = setInterval(updateCountdown, 1000);
    }
    

    开始倒计时

    const updateCountdown=() =>{
      if (countDown.value > 0) {
        countDown.value--;
      } else {
        
      }
    }
    

    CLODOP打印

    打印PDF base64文件

    1,官网下载CLODOP

    2,将安装包下LodopFuncs.js 加入到工程项目

    2,打印方法

    const pdfbase64 = "要打印的pdf base64编码"
    let LODOP=getLodop();
      if(LODOP == null){
        ElMessageBox.confirm('CLODDP插件加载失败!', '提示', {
          confirmButtonText: '确定',
          type: 'warning',
          confirmButtonClass: 'bt'
    
        })
        visiable.value = false;
        return;
      }
      //判断打印机
      const counter = LODOP.GET_PRINTER_COUNT() // 获取打印机个数
      if(counter == 6){
        ElMessageBox.confirm('此电脑没有连接打印机!', '提示', {
          confirmButtonText: '确定',
          type: 'warning',
          confirmButtonClass: 'bt'
        })
        visiable.value = false;
        return;
      }
      //选初始化
      LODOP.PRINT_INIT("门诊报告打印");
      //设置打印机
      const name = LODOP.GET_PRINTER_NAME(0);
      console.log(name)
      if(!LODOP.SET_PRINTER_INDEX(0)){
        ElMessageBox.confirm('打印机不存在', '提示', {
          confirmButtonText: '确定',
          type: 'warning',
          confirmButtonClass: 'bt'
        })
        return;
      }
      //开始打印
      LODOP.ADD_PRINT_PDF(0,0,"100%","100%",pdfbase64.value);
      //LODOP.PREVIEW();
      LODOP.PRINT();
      //打印结果判断
      LODOP.On_Return=function(TaskID,Value){
        if(Value == true){
          showDialog();
        }else{
          ElMessageBox.confirm('打印失败,请联系管理员!', '提示', {
            confirmButtonText: '确定',
            type: 'warning',
            confirmButtonClass: 'bt'
          })
        }
      };
    

    自定义简单

      LODOP.ADD_PRINT_TEXT(70,0,"100%","100%","测试文本");//top,left,width,heigh,string
      LODOP.SET_PRINT_STYLEA(0,"Fontsize",30);//字体大小
      LODOP.SET_PRINT_STYLEA(0,"Alignment",2);//文本框里 内容对于文本框居中,
      LODOP.SET_PRINT_STYLEA(0,"Horient",2);//打印项在纸张中水平居中
      LODOP.ADD_PRINT_HTM(840,0,1200,"100%","
    "
    )//html代码横线

    el-date-picker定义时间范围为最近一个月

    const end = new Date()
    const start = new Date()
    start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
    //查询条件
    const mzfyQuery=ref({
      PatientId:wxUserStore().patientId,
      StartDate:null,
      EndDate:null,
      Date:[start,end],
    })
    

    倒计时

    //倒计时
    const seconds = ref(120);
    const startCountdown = () => {
      const intervalId = setInterval(() => {
        if (seconds.value > 0) {
          seconds.value -= 1;
        } else {
          // 点击确认执行的逻辑
          router.push("/index");;
        }
      }, 1000);
    };
    //开始倒计时
    startCountdown();
    

    页面自适应

    vw vh

    .centerCard{
      width: 80vw;
      height: 60vh;
    }
    

    el-button 图标大小

    <el-icon class="el-icon--right" style="font-size: 3vw" ><CloseBold/></el-icon>
    

    修改字体

    深度选择器

    el-select

    ::v-deep .el-select .el-select__placeholder {
      font-size: 1.25vw;
    

    el-radio

    ::v-deep .el-radio-group .el-radio__label {
      font-size: 1.25vw; /* 设置你想要的字体大小 */
    
    }
    

    el-form-item label字体

    "sex">
      
    
    

    el-date-picker一年以内日期

    vue3+ts

    
    
    // 初始化日期范围
    const dateRangeValue = ref(["2020-03-01","2024-07-03"]);
    const initQuery = ()=>{
    // 创建一个新的Date对象,这将自动设置为当前日期和时间
      let currentDate = new Date();
    // 获取年份、月份(注意月份是从0开始的,所以需要+1)和日期
      let year = currentDate.getFullYear();
      let yearLast = currentDate.getFullYear()-1;
      let month = String(currentDate.getMonth() + 1).padStart(2, '0'); // padStart用于确保月份为两位数
      let day = String(currentDate.getDate()).padStart(2, '0'); // padStart用于确保日期为两位数
    // 将它们组合成"YYYY-MM-DD"的格式
      let endDate = `${year}-${month}-${day}`;
      let startDate = `${yearLast}-${month}-${day}`;
      let temp = [startDate,endDate];
      dateRangeValue.value = temp;
    
    }
    initQuery()
    

    eldialog

    文字居中

    请将身份证放到如图所示区域
    

    img居中

    .img-center {  
    
      display: flex;  
    
      justify-content: center; /* 水平居中 */  
    
      align-items: center; /* 垂直居中 */  
    
      height: 100%; /* 确保 div 的高度与其父元素相同 */  
    
    }
    

    div 位于页面中央

    
    
    
    
    
    

    子组件往父组件发消息

    子组件

    //定义
    import { defineEmits } from 'vue';
    const emit = defineEmits(['childMsg']);
    //通过事件提交
    emit('childMsg', "1");
    

    父组件获取

    //定义获取子组件数据
    const childMsg = (value: string) => {
      console.log("子组件返回数据"+value)
    };
    //父组件使用子组件
    <childVue @child-msg="childMsg"/>
    
  • 相关阅读:
    Java之多线程的综合练习二
    Mysql - 读写分离与读负载均衡之Maxscale
    隧道代理vs普通代理:哪种更适合您的爬虫应用?
    恒星的正方形问题
    快速实战SQL - 排序检索数据
    RHCE --- ansible配置yum源
    关于pool.apply_async的学习【参数问题】
    AWS SES发送邮件如何正确配置?操作指南?
    批量提取文件名到excel?
    甲硝唑修饰二硫化钨MoS2/二硒化钨WSe2/碲化钨WTe2/二氧化锰MnO2/四氧化三铁Fe3O4/二氧化硅SiO2/二氧化钛TIO2纳米粒
  • 原文地址:https://blog.csdn.net/lovewangyihui/article/details/140293527