Skip to content

Vue

发表于
更新于
字数
阅读量

日期

  • 本地时间:不带 Z 后缀的时间一般表示本地时间,时间取决于服务器的时区设置。
  • UTC 时间:带有 Z 的时间表示协调世界时间(UTC)。Z 是 “Zulu” 时间的缩写,表示没有时区偏移。
  • 如果日期带时间,应采用DateTimeOffset,方便时间统一。
  • 与docker环境变量有关 - TZ=Asia/Shanghai
  • js中将原date与中国时间协调显示
从后端读来格式为t:"2023-09-07T14:00:00+00:00",修改为t:"2023-09-07 14:00:00"或从后端读来格式为t: "2023-09-07T22:00:00+08:00",转为t: "2023-09-07 14:00:00.000Z",最后再转为t:"2023-09-07 14:00:00"

 if (ele.t.endsWith("+00:00") )
          ele.t = ele.t.replace("T", " ").split("+")[0];
 else
          ele.t = new Date(ele.t).toISOString().replace("T", " ").split(".")[0];
bash
import { format } from "date-fns";
format(validDate, "yyyy/MM/dd")

# 好用
import { useDateFormat } from "@vueuse/core";
useDateFormat(date, "YYYY/MM/DD"); //'YYYY-MM-DD HH:mm:ss'

vitepress

yarn add -D vitepress@2.0.0-alpha.9

yarn vitepress init

md文件嵌套

bash
可以使用 <!--@include: markdown文件路径-->,在一个 markdown 文件中嵌套另一个 markdown 文件的内容,markdown文件路径 可以是相对路径,也可以是 @/ 开头的以根目录为起点的路径
<!--@include: ./markdown-examples-demo.md-->

Echarts

yarn add echarts

1、安装后无法立刻找到模块“echarts”的声明文件,关闭 vc 后,重新打开。

设置 setOption 时,必须要在 dom 加载完之后加载。即在 onMounted 中加载。

不能将类型“null”分配给类型“HTMLElement”,使用!进行处理或者使用 as 进行断言(原来感叹号是非 null 和非 undefined 的类型断言),echarts.init(document.getElementById('main')!);

vuetify图标个别引用

js
yarn add -D @mdi/js @kingyue/rollup-plugin-modify

//vite.config.ts
import Modify from '@kingyue/rollup-plugin-modify'
import * as mdicons from '@mdi/js'

const mdi: Record<string, string> = {}
Object.keys(mdicons).forEach((key) => {
  const value = (mdicons as Record<string, string>)[key]
  mdi[
    key.replace(
      /[A-Z]+(?![a-z])|[A-Z0-9]/g,
      ($, ofs) => (ofs ? '-' : '') + $.toLowerCase(),
    )
  ] = value
})

plugins: [
    Modify({
      exclude: ['node_modules/**'],
      find: /\b(?<![/\w])(mdi-[\w-]+)\b(?!\.)/,
      replace: (match: string) => {
        if (mdi[match]) {
          return mdi[match]
        } else {
          console.warn('[plugin-modify] No matched svg icon for ' + match)
          return match
        }
      },
      sourcemap: false,
    }),
//vuetify.ts
    import type { FunctionalComponent } from 'vue'
import { createVuetify, type IconSet, type IconProps } from 'vuetify'
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'

function filename(path: string) {
  return path
    .split(/(\\|\/)/g)
    .pop()!
    .replace(/\.[^/.]+$/, '')
}

const svgIcons = Object.fromEntries(
  Object.entries(
    import.meta.glob<FunctionalComponent>('@/assets/icons/*.svg', {
      eager: true,
      import: 'default',
      as: 'component',
    }),
  ).map(([k, v]) => [filename(k), v]),
)
const custom: IconSet = {
  component: (props: IconProps) =>
    h(props.tag, [h(svgIcons[props.icon as string])]),
}

export default createVuetify({
 icons: {
    defaultSet: 'mdi',
    aliases,
    sets: { mdi, custom },
  },

icon直接显示svg用法

  <v-icon icon="custom:shuze" size="4.5em" color="primary" class="mb-4" />
  <v-icon icon="custom:shuze2" size="x-large" class="drawer-header-icon" color="primary" />

5、node 版本,nvm,改版本时,cmd 要管理员模式

解决 node 升级到 18 版本 node-sass 安装问题 //更改为如下版本 "node-sass": "^8.0.0", "sass-loader": "^10.4.1",

nvm use

vue-next-admin

1、http://shuze.net:8009/api/CommonService/menu/roleMenus

获取用户菜单权限

CurrentUser 无需注入即可使用。

2、http://shuze.net:8009/api/CommonService/menu/userMenuPermission

获取用户的权限

package.json

yarn 交互式更新

yarn upgrade-interactive --latest

删除没有用到依赖

bash
# 全局安装
npm install -g depcheck
# 然后在你项目的根目录下执行以下命令:
depcheck

vue3+vuetify+vite+pinia+axios

1、安装 vuetify3

bash
yarn create vuetify@latest
yarn add axios
yarn add -D unplugin-vue-components unplugin-auto-import vite-plugin-vue-meta-layouts unplugin-vue-router
yarn add echarts vue-echarts
yarn add lodash-es @types/lodash-es
yarn add @vueuse/core
yarn add -D @mdi/js @kingyue/rollup-plugin-modify vite-svg-loader
yarn add vite-svg-loader

2、注意事项

1、package.json中"build": "vue-tsc --noEmit && vite build",==》"build": "vite build",否则导入的插件 .d.ts出错
2、解决找不到'virtual:meta-layouts' module问题, add vite-plugin-vue-meta-layouts/client to compilerOptions.types of your tsconfig

3、配置 .env.production 等环境,要设置目录

ENV = 'development'
VITE_VUE_APP_BASE_API = 'http://shuze.net/api'
VITE_VUE_APP_AUTH_API = 'http://shuze.net/auth'

vite 插件

// vite.config.js
import ViteRestart from 'vite-plugin-restart'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import Pages from 'vite-plugin-pages'
import Layouts from 'vite-plugin-vue-layouts';


export default {
  plugins: [
    ViteRestart({
      restart: [
        'my.config.[jt]s',
      ]
    }),
    Components({ dts: './src/components.d.ts', types: [] }),
    AutoImport({
      imports: [
        'vue',
        'pinia',
        'vue-router','@vueuse/head', '@vueuse/core',
      ],
      dts: 'src/types/auto-imports.d.ts',
      dirs: ['src/stores'],
    }),
    Pages({
      dirs: 'src/views',
    }),
    Layouts(),
  ],
}
//env.d.ts
/// <reference types="vite-plugin-pages/client" />
/// <reference types="vite-plugin-vue-layouts/client" />

lodash-es

vueuse/core

1、 yarn add @vueuse/core

动画(Animation)—包含易于使用的过渡、超时和计时函数
浏览器(Browser)—可用于不同的屏幕控制、剪贴板、首选项等
组件(Component)— 为不同的组件方法提供简写
Formatters – 提供反应时间格式化功能
传感器(Sensors )—用于监听不同的 DOM 事件、输入事件和网络事件
状态(State )—管理用户状态(全局、本地存储、会话存储)
实用程序(Utility)—不同的实用程序函数,如 getter、条件、引用同步等
Watch —更高级的观察者类型,如可暂停观察者、去抖动观察者和条件观察者
杂项(Misc)— 事件、WebSockets 和 Web Worker 的不同类型的功能

useFullscreen

//isFullscreen 当前是否是全屏,true/false,可用于一些逻辑的判断
//toggle  是函数直接调用即可
const { isFullscreen, toggle } = useFullscreen();

<button @click="toggle">点击切换</button>

useStorage

import { useStorage } from "@vueuse/core"
const theDefault = {
  name: "Banana",
  color: "Yellow",
  size: "Medium",
  count: 0,
}
let state = useStorage("vue-use-local-storage", theDefault)
// state = JSON.parse(state.value)
console.log(state)

useClipboard 剪切板功能

<script setup>
import { useClipboard } from "@vueuse/core"
//text 复制的内容
//copy 是复制的函数
// isSupported 判断当前的浏览器是否支持这个api
const input = ref("")
const { text, copy, isSupported } = useClipboard()
console.log(text, copy, isSupported)
</script>

<template>
  <div>
    <input v-model="input" type="text" />
    <button @click="copy(input)">Copy</button>
  </div>
</template>

useTitle 动态修改标题名

<script setup>
// import { useToggle } from "@vueuse/shared"
import { useTitle } from "@vueuse/core"
const title = useTitle()
console.log(title.value) // print current title
const num = ref(0)
const btn = () => {
  num.value++
  title.value = "Hello" + num.value // change current title
}
</script>

<template>
  <button @click="btn">点击</button>
</template>

useDateFormat 时间格式

<script setup>
import { useNow, useDateFormat } from "@vueuse/core"

const formatted = useDateFormat(useNow(), "YYYY-MM-DD")// HH:mm:ss
</script>

<template>
  <div>{{ formatted }}</div>
</template>`

2、broswer(浏览器相关),点击复制文字:useClipboard 响应式 storage 数据,useStorage 来实现我们的localStorage功能,useStorage()将要用于引用的键名作为第一个参数传递,将要保存的值作为第二个参数传递。可代替 localStorage。当 useStorage 有两个参数的时候,是设置存储信息,并返回格式化好的数据 当 useStorage 只有一个参数的时候,是读取,但是返回的数据需要 json.parse 下,是字符串对象

import { useStorage } from '@vueuse/core'
const state = useStorage('my-store', { hello: 'hi', greeting: 'Hello' })

   const msg = ref('你好')
   //保存值
   useStorage('msg',msg.value)
   //获取值
   const msgData = useStorage('msg')
   console.log('msgData',msgData.value)
   //删除
   const clear = () => {
     msg.value = null
   }

useQRCode 二维码生成器,搭配 qrcode 使用

<script setup>
import { useQRCode } from "../utils/useQrcode"
let inp = ref("")
let qrcode = null
const inpBtn = () => {
  qrcode = useQRCode(inp.value)
}
</script>

<template>
  <input type="text" v-model="inp" @input="inpBtn" />
  <img :src="qrcode" alt="qrcode" />
</template>

useVModel,用于父子组件共享数据,

<script lang="ts" setup>
import { useVModel } from '@vueuse/core'

const props = defineProps<{
  modelValue: string
}>()
const emit = defineEmits(['update:modelValue'])

const data = useVModel(props, 'modelValue', emit)
</script>

前端文件上传

 <v-col cols="3">
        <v-file-input
          label="File input"
          v-model="state.selectedFile"
        ></v-file-input> </v-col
      ><v-col>
      <v-btn @click="uploadFile">上传</v-btn></v-col>
//modelName,file通通到data中,FormData格式
export function exportFromUpload(data: any) {
  return request({
    url: "/" + "CommonService" + "/" + "Common" + "/" + "ExportFromUpload",
    method: "post",
    data,
  });
}
function uploadFile() {
  const formData = new FormData(); // 创建FormData对象
  formData.append("modelName", "Model");
  formData.append("file", state.selectedFile);
  let modelName = "Model";
  exportFromUpload(formData).then((res) => {
    console.log(res.data);
  });
}
 public string ExportFromUpload( string modelName , IFormFile file )//
    {
        var result = ShuzeClassLibrary.ExportFromUpload("CommonService", modelName, file);
        return result;
    }

前端要采用 FormData 对象,增加的 key 要与后端参数名一致,不然获取不到值。多参数时不能用 params 方式。后端采用 IFormFile 格式,可返回序列化 string 到前端。

后端文件下载

export function genFormVue(moduleName: string, modelName: string) {
  return request({
    url: "/CommonService/ModelProp/GenFormVue",
    method: "get",
    responseType: "blob",
    params: {
      moduleName,
      modelName,
    },
  });
}
 <v-btn @click="genVue">生成vue文件</v-btn>
genVue() {
      genFormVue(this.moduleName, this.modelName).then((res) => {
        const link = document.createElement("a");
        link.href = window.URL.createObjectURL(res.data);
        link.download = "item.vue";
        link.click();
      });
    },
  public async Task<ActionResult> GenFormVueAsync(int modelType)
    {
        var stream = new MemoryStream();
        var sw = new StreamWriter(stream, Encoding.UTF8);
        string sl = "";

        sw.WriteLine(sl);
        sw.Flush();
        stream.Position = 0;
        var result = new FileStreamResult(stream, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/plain"));
        result.FileDownloadName = "index.vue";
        return result;
    }
<v-btn @click="exportItem"> <v-icon>mdi-export</v-icon>导出 </v-btn>
exportItem() {
      var input = {
        maxResultCount: this.options.itemsPerPage,
        skipCount: (this.options.page - 1) * this.options.itemsPerPage,
        filter: this.search,
      };

      getExportFile(this.moduleName, this.modelName).then((res) => {
        const link = document.createElement("a");
        link.href = window.URL.createObjectURL(
          new Blob([res.data], { type: "text/plain" })
        );
        link.download = "export.txt";
        link.click();
      });
    },
  public async Task<FileResult> GetExportFile(GetInputDto input, DateTime? startDate = null, DateTime? endDate = null)
    {
            MemoryStream memoryStream = new MemoryStream();
            StreamWriter streamWriter = new StreamWriter(memoryStream, Encoding.UTF8);
            string text = "";
            streamWriter.WriteLine(text);
            streamWriter.Flush();
            memoryStream.Position = 0L;
            return new FileStreamResult(memoryStream, "application/octet-stream")
            {
                FileDownloadName = "report.txt"
            };
    }

vue3 模板,菜单

store/app.ts 中 useAppStore 放置菜单,注意路径格式为“/”

text=>title

Vue 文件中引用路径的介绍

1,路径 ./
./当前文件同级目录, ./css/等同于css/
2. 路径 ../
../当前文件上一级目录
3.  @
@ 的作用是在你引入模块时,可以使用 @ 代替 /src 目录,避免易错的相对路径。 (注意@不要用在引入css文件路径,有的项目规范不支持)

vue3 组件传值之 props 与 attrs 的区别

最近在学习 vue3,整理了一些学习笔记,如果有人看到,并发现我有写的不对的地方,欢迎指正~

用过 vue 组件传值的小伙伴都知道 props 这个属性,而 $attrs 属性可以看做 props 的加强版,用来简化 vue 组件传值,那么这两个属性具体有什么区别呢?

先说结论,区别如下:

1、props 要先声明才能取值,attrs 不用先声明

2、props 声明过的属性,attrs 里不会再出现

3、props 不包含事件,attrs 包含

4、props 支持 string 以外的类型,attrs 只有 string 类型

混入

//全局混入时,组件内无法调用混入 data 内数据。但组件内混入时,则可以调用混入 data 内数据,20210218 3、相关的解释    3.1 当在组件中和混入中有相同的‘testMix’这个数据时,显示组件中’testMix’对应的数据,当只用混入中有’testMix‘函数时,显示混入中’testMix’对应的数据。    3.2 在组件中和混入中有相同的函数 mixinsFun()时,在组件中调用时,调用的是组件中的 mixinsFun()函数,当只用混入中有 mixinsFun()函数时,在组件中调用 mixinsFun()是调用混入中的。    3.3 在组件中和混入中有相同的 computed 函数 testMix2()时,在组件中调用时,调用的是组件中的 testMix2()函数,当只用混入中有 computed 函数 testMix2()时,在组件中调用 testMix2()是调用混入中的。    3.4 在组件中和混入中有相同的 created()函数时,先执行混入中的 created,再执行组件中的 created。猜想其他生命周期也应该是一样。    3.5 在组件中和混入中有相同的 watch()函数 testMix 时,先执行混入中 watch 的 testMix,再执行组件中 watch 的 testMix。

watch

Vue 之 watch 监听对象中某个属性的方法,vue2 通过 'userinfo.job' 的方式实现(推荐),备注:因为方法 2 是使用字符串作为键来对对象中的内容进行监听,编译器无法识别检测语法,在 vue3 中已经废弃,可以使用新的响应性 api watchwatchEffect来替代该方法

node 版本管理

nvm

nvm install latest 安装最新版本node.js
nvm use 版本号 使用某一具体版本,例如 :nvm use 14.3.0
nvm list 列出当前已安装的所有版本
nvm ls 列出当前已安装的所有版本
nvm uninstall 版本号 卸载某一具体版本,例如:nvm use 14.3.0
nvm ls-remote Mac版本中,列出全部可以安装的node版本
nvm ls available windows版本,列出全部可以安装的node版本
nvm current 显示当前的版本
nvm alias 给不同的版本号添加别名
nvm unalias 删除已定义的别名
nvm reinstall-packages 在当前版本node环境下,重新全局安装指定版本号的npm包

vuetify

1、安装

yarn create vuetify
输入项目名vueclient,选取安装插件vueroute pania
进入目录:cd vueclient
运行:yarn dev

2、yarn add axios

3、新建环境变量

vite 环境变量文件放在根目录,其中.env.development 文件(npm run dev 时自动启用该文件)和.env.production(npm run bulid 时自动启用该文件)文件为必须。注意:只有以 VITE_ 开头的变量才会被识别,并启用。

js 二进制转十进制

这个是把字符串(只能由字母和数字组成),这个只能是由低进制转高进制

Number.parseInt(string , radix)

这个函数只能将十进制数字转换为任意进制的字符串形式,同样,radix 表示进制,取值 2~36

Number.toString(radix)

defineModel

这个宏可以用来声明一个双向绑定 prop,通过父组件的 v-model 来使用。在对话框中使用方便,无需 emit("closeDialog")及 pinia。

bash
#子组件
const flagDialog = defineModel();
const props = defineProps(["id"]);

#父组件(要用v-model:flagDialog)
<ItemDialog
      ref="refDialog"
      v-model="state.tableInform.flagDialog"
      :id="state.fmdata.id"
      @refreshItem="refreshItem"
    ></ItemDialog>