分类 VUE 下的文章

问题描述

在style中使用scss时,安装sass和sass-loader。

解决过程(避坑)

之前搜的网上,安装node-sass,各版本对照等等,到最后也不能运行,后来发现,安装sass而不是node-sass,就可以完美运行。

解决方法

  1. 卸载之前安装的版本(node-sass,天坑)

    npm uninstall node-sass
    npm uninstall sass-loader
  2. 安装对应版本(此处NodeJS版本为V16.13.1)

    npm install sass@1.26.5 --save-dev
    npm install sass-loader@8.0.2 --save-dev
  3. Node其他版本和sass、sass-loader的关联并未尝试

参考:
https://blog.csdn.net/l963937050/article/details/122302208

简单版:

export function HandleUrlParam(url: string, param?: Record<string, any> | null): string {
  if (param) {
    const paramArray = [] as string[];
    const keys = Object.keys(param);
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      const value = param[key]?.toString() ?? "";
      paramArray.push(`${key}=${value}`);
    }
    if (paramArray.length > 0) {
      let paramText = paramArray.join("&");

      if (url.indexOf("?") >= 0) {
        url = `${url}${paramText}`;
      } else {
        url = `${url}?${paramText}`;
      }
    }
  }
  return url;
}

复杂版:
https://github.com/Leonardozn/json-qs-converter

Plus版:

export function HandleUrlParamPlus(url: string, param?: Record<string, any> | null): string {
  if (param) {
    let paramArray = GetUrlParamList('',param);

    if (paramArray.length > 0) {
      let paramText = paramArray.join("&");

      if (url.indexOf("?") >= 0) {
        url = `${url}${paramText}`;
      } else {
        url = `${url}?${paramText}`;
      }
    }
  }
  return url;
}

function GetUrlParamList(parentKey: string, param?: Record<string, any> | null) {
  let paramArray = [] as string[];
  if (param) {
    const keys = Object.keys(param);
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      const value = param[key] ?? "";
      if (!_.isObject(value)) {
        if (parentKey) {
          paramArray.push(`${parentKey}.${key}=${value}`);
        } else {
          paramArray.push(`${key}=${value}`);
        }
      } else {
        let childParamList = GetUrlParamList(key, value)
        if (parentKey) {
          for (let i = 0; i < childParamList.length; i++) {
            childParamList[i] = `${parentKey}.${childParamList[i]}`
          }
        }
        paramArray = _.concat(paramArray, childParamList)
      }
    }
  }
  return paramArray
}

main.ts

import '~/util/openInEditorConfig'

openInEditorConfig.ts

import { warpperEnv } from "~/util/build";

let envSettings = warpperEnv()
if (process.env.NODE_ENV === 'development') {
    let host = window.location.host
    window.VUE_DEVTOOLS_CONFIG = {
        openInEditorHost: `http://${host}/${envSettings.VITE_PUBLIC_PATH}/`
    }
}

src\util\build\index.ts

/**
 * 默认环境配置, 具体配置在 .env.xxx文件中修改
 */
const settings: EnvSettings = {
  VITE_PORT: 5003,
  VITE_PUBLIC_PATH: "/projexec",
  VITE_ONLY_OFFICE_HOST: 'http://192.168.101.88:1080',
  VITE_DOCUMENT_SERVER_HOST: 'http://localhost:9540',
  VITE_DOCUMENT_SERVER_VUE_HOST: 'http://localhost:8848',
  VITE_FILE_READY_ADDRESS: "http://xxxxxxxxxxxxx.aliyuncs.com/"
};

/**
 * 包装环境配置,用于将字符串格式化为boolean或number类型
 * @param envConf 环境配置
 * @returns 
 */
const warpperEnv = (envConf?: Record<string, any>): EnvSettings => {
  let ret = { ...settings, };

  if (!envConf) envConf = loadEnv()
  for (const envName of Object.keys(envConf)) {
    const envValue = envConf[envName]
    if (!envValue || typeof (envValue) !== 'string') {
      continue
    }

    let value: any = envValue.replace(/\\n/g, "\n");

    if (value === "true") {
      value = true
    } else if (value === "false") {
      value = false;
    }

    if (envName === "VITE_PORT") {
      value = Number(value);
    }

    ret[envName] = value;
  }
  return ret;
};


/**
 * 加载环境变量 import.meta.env
 * @returns 
 */
const loadEnv = () => {
  /**
   * development 开发环境从import.meta.env获取环境变量
   * 非development 开发环境则从config.js获取环境变量
   */

  // 在生产环境中,这些环境变量会在构建时被静态替换,因此,在引用它们时请使用完全静态的字符串。动态的 key 将无法生效。例如,动态 key 取值 import.meta.env[key] 是无效的。
  // https://cn.vitejs.dev/guide/env-and-mode.html#env-variables
  const env = import.meta.env;

  if (env.MODE === 'development') {
    return env;
  }

  Object.assign(env, window.appConfig)

  return env;
};

export { settings, warpperEnv };

public\config.js-test

window.appConfig = {
  // VITE_PORT:'80',
  VITE_PUBLIC_PATH:'projexec',
  VITE_ONLY_OFFICE_HOST:'http://192.168.101.88:1080',
  VITE_DOCUMENT_SERVER_HOST:'http://192.168.101.80:55000/document',
  VITE_DOCUMENT_SERVER_VUE_HOST:'http://192.168.101.80:55000/document',
  VITE_FILE_READY_ADDRESS: "http://xxxxxxxxxxxxxx.aliyuncs.com/"
}

后端代码:

using System.Diagnostics.CodeAnalysis;
using TB.ComponentModel;// 需要安装依赖 UniversalTypeConverter

[HttpPost]
public async Task<List<DFileInfoDto>> BatchUploadFileAsync(IFormCollection Form)
{
    var tokenDTO = await TokenHelper.GetCurrentTokenAsync(HttpContext);

    if (tokenDTO == null)
    {
        throw new CustomException(ErrCodes.DocTokenGetDataFail, "从Token中获取用户信息失败");
    }

    // Request.Form or Form
    var files = Form.Files;
    var list2 = IFormCollectionToGeneric<DFileInfoDto>(Form);

    var res = new List<DFileInfoDto>();
    for (int i = 0; i < files.Count; i++)
    {
        list2[i].FromFile = files[i];

        var fileInfoDto = await _document.UploadFileAsync(list2[i], tokenDTO);
        res.Add(fileInfoDto);
    }

    return res;
}


public static List<T> IFormCollectionToGeneric<T>(IFormCollection formCollection) where T : class, new()
{
    var properties = typeof(T).GetProperties();
    var propertiesNames = properties.Select(p => p.Name).ToList();
    var ignoreCaseComparer = new IgnoreCaseComparer();
    var keys = formCollection.Keys.Where(key => propertiesNames.Contains(key, ignoreCaseComparer)).ToList();
    var formCount = formCollection[keys.First()].Count;

    var list = new List<T>();
    for (int i = 0; i < formCount; i++)
    {
        var instance = Activator.CreateInstance<T>();
        foreach (var property in properties)
        {
            if (formCollection.TryGetValue(property.Name, out var stringValues))
            {
                var value = property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null;
                if (stringValues[i].IsConvertibleTo(property.PropertyType))
                {
                    value = stringValues[i].To(property.PropertyType);
                }
                property.SetValue(instance, value);
            }
        }
        list.Add(instance);
    }
    return list;
}

public class IgnoreCaseComparer : IEqualityComparer<string>
{
    public bool Equals(string? x, string? y)
    {
        return x.Equals(y, StringComparison.OrdinalIgnoreCase);
    }

    public int GetHashCode([DisallowNull] string obj)
    {
        return obj.ToUpper().GetHashCode();
    }
}

前端代码:
前端代码不完整,仅供参考,其原理为:将需要请求的对象数组,全部转换为FormData对象,因FormData对象没有对象数组的概念,所以FormData对象中的key是可重复的,在后端同个key可以接收到多个value

  const form = new FormData();
  dto.data!.forEach((t) => {
    const keys = Object.keys(t);
    keys.forEach((k) => {
      form.append(k, t[k]);
    });
  });
  dto.data = form;
  
  
  
  function PostApi<T = any>(url, data, headers?: any): Promise<ApiResultDTO<T>> {
  url = FormatUrl(url);
  let config: ConfigType = {
    headers: {},
    method: "POST",
    body: data != null ? JSON.stringify(data) : null,
  };
  if (data) {
    if (data instanceof FormData) {
      config.body = data;
    } else if (headers && headers["Content-Type"] === "multipart/form-data") {
      config.body = data;
    } else {
      config.body = JSON.stringify(data);
      config.headers["Content-Type"] = "application/json";
    }
  } else {
    config.body = null;
  }

  if (headers) {
    Object.assign(config.headers, headers);
  }
  return new Promise((resolve, reject) => {
    setLoading(true);
    fetch(url, config).then((res) => handleJsonResult(resolve, reject, res));
  });
}




下载地址:
https://github.com/coreybutler/nvm-windows/releases

命令:

nvm list #查看版本列表
nvm install 版本号(如 14.15.0)  #安装相应版本
nvm use 版本号(如 14.15.0) #切换使用版本

注意:
工具通过MKLinK软链接实现,所有nodejs版本会安装在nvm的根目录下,并通过path环境变量来指向软链接路径,当nvm切换版本时,nvm会重新设置软链接,指向nodejs新的版本路径

参考:
https://blog.csdn.net/recher_He1107/article/details/111029345

前言

  • 阅读本文您可以收获🔑:给全局组件添加类型声明的最佳实践(Vue3+TS+Volar)
  • 2022.2.7,农历大年初七,Vue3成为官方默认版本,这意味着,不管你学不学,Vue4已经在路上(狗头)。趁着过年闲着,悄悄地自家的UI组件库重写成Vue3,并且成功全局安装使用。

遇到问题

  • 不知道如何给UI组件库(自定义全局组件)声明类型,并且Vue3最新的官方文档,也找不到关于全局组件类型声明的一丝痕迹,因此,UI组件使用的时候也就没有任何的提示

- 阅读剩余部分 -