Shero.

生活百般滋味,你要笑着面对😊


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

vite+vue3

发表于 2022-03-17 | 分类于 前端框架

vite

  • vite
  • more

    首次执行命令(npm init vite@latest)一直报错

  • 解决

    • 修改源地址位淘宝镜像
      1
      npm config set registry http://registry.npm.taobao.org/
  • 修改源地址为官方源

    1
    npm config set registry https://registry.npmjs.org/
  • 再使用cnpm

  • 下载淘宝镜像

    1
    npm  install -g cnpm --registry==http://registry.npm.taobao.org
  • 指定淘宝镜像

    1
    npm config set  registry  http://registry.npm.taobao.org/

vite的优势

  • 冷服务 默认构建目标浏览器是能在script标签上支持原生ESM和原生ESM动态导入
    • 更多ESM
  • HMR模块热替换(hot module replacement)速度快 模块热更新(HMR)
  • Rollup打包,它使用rollup打包的代码,并且它是预配置的 支持大部分的rollup插件

目录

  • public – 静态文件(不被编译)
  • src/assets – 静态文件(被编译)

diff 算法

  • 有无key 是否覆盖,及跳过(顺、逆、乱)

相关Ref

  • ref
    • 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      <template>
      <div>
      <button @click="changeHandle">点击</button>
      <div>{{ mes }}</div>
      </div>
      </template>

      <script setup lang="ts">
      let mes: string = "初学习vite"
      const changeHandle = () => {
      mes = "change msg"
      }
      </script>

      <style>
      </style>
  • 以上操作,无法改变mes的值,因为mes并不是响应式的,无法被vue跟踪要改成ref

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <template>
    <div>
    <button @click="changeHandle">点击</button>
    <div>{{ mes }}</div>
    </div>
    </template>

    <script setup lang="ts">
    import {ref, Ref} from 'vue'
    let mes:Ref<string> = ref("我是message");

    const changeHandle = () => {
    mes.value = "change msg"
    }
    </script>

    <style>
    </style>
    // ------------------------------- ts两种方式 ---------------------------------
    <template>
    <div>
    <button @click="changeHandle">点击</button>
    <div>{{ mes }}</div>
    </div>
    </template>

    <script setup lang="ts">
    import { ref } from 'vue'
    let mes = ref<string | number>("我是message")

    const changeHandle = () => {
    message.value = "change msg"
    }
    </script>

    <style>
    </style>
  • isRef

    • 判断是不是一个ref对象
      1
      2
      3
      4
      5
      6
      7
      8
      9
      import { ref, Ref,isRef } from 'vue'
      let message: Ref<string | number> = ref("我是message")
      let notRef:number = 123
      const changeMsg = () => {
      message.value = "change msg"
      console.log(isRef(message)); //true
      console.log(isRef(notRef)); //false

      }
  • shallowRef

    • 创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的
    • 修改其属性是非响应式的这样是不会改变的
  • triggerRef

    • 强制更新页面DOM
  • customRef

    • customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set

reactive

  • 用来绑定复杂的数据类型 例如 对象 数组
  • 不可以绑定普通的数据类型这样是不允许 会给我们报错
  • 如果用ref去绑定对象 或者 数组 等复杂的数据类型,看源码里面其实也是 去调用reactive,使用reactive 去修改值无须.value
  • 数组异步赋值问题

    • 不会变化
      1
      2
      3
      4
      5
      let person = reactive<number[]>([])
      setTimeout(() => {
      person = [1, 2, 3]
      console.log(person);
      },1000)
  • 解决方案1

    1
    2
    3
    4
    5
    6
    7
    import { reactive } from 'vue'
    let person = reactive<number[]>([])
    setTimeout(() => {
    const arr = [1, 2, 3]
    person.push(...arr)
    console.log(person);
    },1000)
  • 解决方案2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    type Person = {
    list?:Array<number>
    }
    let person = reactive<Person>({
    list:[]
    })
    setTimeout(() => {
    const arr = [1, 2, 3]
    person.list = arr;
    console.log(person);
    },1000)
  • readonly

    • 拷贝一份proxy对象将其设置为只读
  • shallowReactive
    • 只能对浅层的数据 如果是深层的数据只会改变值,不会改变视图

to系列

  • toRef
    • 原始对象是非响应式的就不会更新视图 数据是会变的
    • 原始对象是响应式的是会更新视图并且改变数据的
  • toRefs
    • 批量创建ref对象主要是方便我们解构使用
  • toRaw
    • 响应式对象转化为普通对象

computed计算属性

  • computed用法
    • 计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值
    • 参数(函数或对象)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      const name = computed(() => {
      return `${fistName.value} ----- ${lastName.value}`
      })
      const name = computed({
      get() {
      return `${fistName.value} ----- ${lastName.value}`
      },
      set() {
      return `${fistName.value} ----- ${lastName.value}`
      }
      })

watch侦听器

  • watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用
  • watch参数

    • 第一个参数监听源(单个数据源、数组、函数)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      import { ref, watch, reactive } from 'vue';
      let message = reactive({
      name: '凤',
      name2: '凤凤',
      });
      // 只想监听特定的某个属性,可以传入函数
      watch(() => message.name, (newVal, oldVal) => {
      console.log('新的', newVal);
      console.log('旧的', oldVal);
      }, {
      // deep: true, // reactive类型 是否设置deep 都深度监听
      // immediate: true, // 第一次进入页面是否执行
      })
    • 第二个参数回调函数cb(newVal, oldVal)

    • 第三个参数一个options配置项是一个对象,可不传 undefined
      1
      2
      3
      4
      {
      immediate: true, // 是否立即调用一次
      deep: true // 是否开启深度监听, 如果是reactive类型,是否设置此属性默认深度监听
      }

watchEffect高级侦听器)

  • 立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数
  • 如果用到message 就只会监听message 就是用到几个监听几个 而且是非惰性 会默认调用一次
  • 清除副作用
    • 就是在触发监听之前会调用一个函数可以处理你的逻辑例如防抖
  • 停止跟踪 watchEffect 返回一个函数 调用之后将停止更新

  • 更多的配置项

    • 副作用刷新时机 flush 一般使用post(可以获取到DOM元素)
    • 更新时机,pre组件更新前执行, sync强制效果始终同步触发, post组件更新后执行
    • onTrigger 可以帮助我们调试 watchEffect
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      <div>
      <input id="inp" v-model="message" type="text" />
      <input v-model="message2" type="text" />
      <button @click="stopWatch">停止监听</button>
      </div>

      import { ref, watch, watchEffect, reactive } from 'vue';
      const message = ref<string>('凤');
      const message2 = ref<string>('凤凤');
      // 默认会执行一次
      const stop = watchEffect((oninvalidate) => {
      const inp:HTMLInputElement = document.querySelector('#inp') as HTMLInputElement;
      console.log('message--------', message.value);
      // console.log('message2--------', message2.value);
      console.log(inp, '进入页面');
      oninvalidate(() => {
      console.log('before');
      })
      }, {
      flush: 'post',
      onTrigger(e) {
      // dev可以帮助我们调试 watchEffect
      }
      })

      const stopWatch = () => stop();

识组件&Vue3生命周期

  • 每一个.vue 文件都可以充当组件来使用
  • 每一个组件都可以复用
  • 父组件使用

    • 引入子组件 xxx 然后直接就可以去当标签去使用 (切记组件名称不能与html元素标签名称一样)
    • vue3使用组件无需注册
  • 组件的生命周期

    • 是一个组件从创建到销毁的过程成为生命周期
    • 在我们使用Vue3 组合式API 是没有 beforeCreate 和 created 这两个生命周期的
  • onBeforeMount()
    • 在组件DOM实际渲染安装之前调用。在这一步中,根元素还不存在
  • onMounted()
    • 在组件的第一次渲染后调用,该元素现在可用,允许直接DOM访问
  • onBeforeUpdate()
    • 数据更新时调用,发生在虚拟 DOM 打补丁之前
  • updated()
    • DOM更新后,updated的方法即会调用
  • *nBeforeUnmounted()
    • 在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的
  • onUnmounted()
    • 卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载

实操组件和认识less 和 scoped

  • less

    • Less (Leaner Style Sheets 的缩写) 是一门向后兼容的 CSS 扩展语言。这里呈现的是 Less 的官方文档(中文版),包含了 Less 语言以及利用 JavaScript 开发的用于将 Less 样式转换成 CSS 样式的 Less.js 工具
    • Less 和 CSS 非常像,很容易学习。而且 Less 仅对 CSS 语言增加了少许方便的扩展,这就是 Less 如此易学的原因之一
      • 官方文档 Less 快速入门 | Less.js 中文文档 - Less 中文网
    • 在vite中使用less
      1
      npm install less less-loader -D // 安装即可
  • 在style标签注明即可

    1
    2
    3
    <style lang="less">

    </style>
  • scoped

    • 实现组件的私有化, 当前style属性只属于当前模块
      • 在DOM结构中可以发现,vue通过在DOM结构以及css样式上加了唯一标记,达到样式私有化,不污染全局的作用
      • 样式穿透问题学到第三方组件精讲 ::v-deep >>> /deep/

父子组件传参

  • 父组件通过v-bind绑定一个数据,然后子组件通过defineProps接受传过来的值
    • 传递了一个title 字符串类型是不需要v-bind
    • 传递非字符串类型需要加v-bind 简写 冒号
  • 子组件接受值
    • 通过defineProps 来接受 defineProps是无须引入的直接使用即可
    • 如果我们使用的TypeScript,可以使用传递字面量类型的纯类型语法做为参数
  • TS 特有的默认值方式
  • withDefaults是个函数也是无须引入开箱即用接受一个props函数第二个参数是一个对象设置默认值

  • 子组件给父组件传参

    • 是通过defineEmits派发一个事件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <template>
      <div class="menu">
      <button @click="clickTap">派发给父组件</button>
      </div>
      </template>

      <script setup lang="ts">
      import { reactive } from 'vue'
      const list = reactive<number[]>([4, 5, 6])

      const emit = defineEmits(['on-click'])
      const clickTap = () => {
      emit('on-click', list)
      }
      </script>
  • 在子组件绑定了一个click 事件 然后通过defineEmits 注册了一个自定义事件

    • 点击click 触发 emit 去调用我们注册的事件 然后传递参数
    • 父组件接受子组件的事件
  • 组件暴露给父组件内部属性
    • 通过defineExpose
    • 父组件获取子组件实例通过ref
    • 父组件想要读到子组件的属性可以通过 defineExpose暴露

动态组件

  • 让多个组件使用同一个挂载点,并动态切换,这就是动态组件。
  • 在挂载点使用component标签,然后使用v-bind:is=”组件”

    1
    <component :is="A"></component>
  • 使用场景

    • tab切换 居多
  • 注意事项
    1.在Vue2 的时候is 是通过组件名称切换的 在Vue3 setup 是通过组件实例切换的

2.如果你把组件实例放到Reactive Vue会给你一个警告runtime-core.esm-bundler.js:38 [Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with markRaw or using shallowRef instead of ref.
Component that was made reactive:

  • 这是因为reactive 会进行proxy 代理 而我们组件代理之后毫无用处 节省性能开销 推荐我们使用shallowRef 或者 markRaw 跳过proxy 代理

    1
    2
    3
    4
    5
    6
    7
    const tab = reactive<Com[]>([{
    name: "A组件",
    comName: markRaw(A)
    }, {
    name: "B组件",
    comName: markRaw(B)
    }])
  • ?.length的语法

    • 某个对象下的某个数组不存在,读取length会报错,处理方式(是否存在,不存在并赋值为空数组) item.children?.length ?? []
    • null ?? [] 得到[],但是 0 ?? [] 得到 0 false ?? [] 得到false
  • vue2 与 vue3使用方式区别

  • vue3中 is 如果是字符串,不会被渲染 setup 与 component之间没有建立媒介关系
  • 改写为vue 2方式没有问题
    <script lang="ts">
    export default {
    components: {
      A,
    }
    }
    </script>
    

for循环和forEach的语法

发表于 2022-03-05 | 分类于 js

for循环和forEach的语法

  • To Learn More

for循环和forEach的本质区别

  • forEach 是负责遍历(Array Set Map)可迭代对象的,而 for 循环是一种循环机制,只是能通过它遍历出数组
  • 只要是可迭代对象,调用内部的 Symbol.iterator 都会提供一个迭代器,并根据迭代器返回的next 方法来访问内部,这也是 for…of 的实现原理
1
2
3
let arr = [1, 2, 3, 4]  // 可迭代对象
let iterator = arr[Symbol.iterator]() // 调用 Symbol.iterator 后生成了迭代器对象
console.log(iterator.next()); // {value: 1, done: false} 访问迭代器对象的next方法

for循环和forEach的语法区别

  • forEach 的参数
  • arr.forEach((self,index,arr) =>{},this) // this: 回调函数中this指向

    1
    2
    3
    4
    5
    6
    7
    8
    let arr = [1, 2, 3, 4];
    let person = {
    name: 'xx'
    };
    arr.forEach(function (self, index, arr) {
    console.log(`当前元素为${self}索引为${index},属于数组${arr}`);
    console.log(this.name+='美美哒');
    }, person)
  • arr 实现数组去重

    1
    2
    3
    4
    5
    6
    let arr1 = [1, 2, 1, 3, 1];
    let arr2 = [];
    arr1.forEach(function (self, index, arr) {
    arr.indexOf(self) === index ? arr2.push(self) : null;
    });
    console.log(arr2); // [1,2,3]
  • forEach 的中断

  • js中有break return continue 对函数进行中断或跳出循环的操作(优化数组遍历查找),但forEach属于迭代器,只能按序依次遍历完成,不支持上述的中断行为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    let arr = [1, 2, 3, 4],
    i = 0,
    length = arr.length;
    for (; i < length; i++) {
    console.log(arr[i]); //1,2
    if (arr[i] === 2) {
    break;
    };
    };

    arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
    break; //报错
    };
    });

    arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
    continue; //报错
    };
    });
  • forEach 中跳出循环呢?其实是有办法的,借助try/catch

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    try {
    var arr = [1, 2, 3, 4];
    arr.forEach(function (item, index) {
    //跳出条件
    if (item === 3) {
    throw new Error("LoopTerminates");
    }
    //do something
    console.log(item);
    });
    } catch (e) {
    if (e.message !== "LoopTerminates") throw e;
    };
  • return 并不会报错,但是不会生效

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let arr = [1, 2, 3, 4];
    function find(array, num) {
    array.forEach((self, index) => {
    if (self === num) {
    return index;
    };
    });
    };
    let index = find(arr, 2);// undefined
  • forEach 删除自身元素,index不可被重置

    1
    2
    3
    4
    5
    let arr = [1,2,3,4]
    arr.forEach((item, index) => {
    console.log(item); // 1 2 3 4
    index++;
    });
  • for 循环可以控制循环起点

    1
    2
    3
    4
    5
    6
    7
    let arr = [1, 2, 3, 4],
    i = 1,
    length = arr.length;

    for (; i < length; i++) {
    console.log(arr[i]) // 2 3 4
    };
  • 数组遍历并删除

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let arr = [1, 2, 1],
    i = 0,
    length = arr.length;

    for (; i < length; i++) {
    // 删除数组中所有的1
    if (arr[i] === 1) {
    arr.splice(i, 1);
    //重置i,否则i会跳一位
    i--;
    };
    };
    console.log(arr); // [2]
    //等价于
    var arr1 = arr.filter(index => index !== 1);
    console.log(arr1) // [2]
  • for循环和forEach的性能区别

    • 性能比较:for > forEach > map 在chrome 62 和 Node.js v9.1.0环境下:for 循环比 forEach 快1倍,forEach 比 map快20%左右
    • for循环没有额外的函数调用栈和上下文,所以它的实现最为简单

正则常用表达式

发表于 2022-03-03 | 分类于 js

正则常用表达式

数字价格千分位分割

1
2
3
function numSplit(str) {
return str.replace(/(?!^)(?=(\d{3})+$)/g, ','); // 123,456,789
}

补充小数千分位支持

1
2
3
4
const formatNum = (numStr) => {
const reg = new RegExp(`(?!^)(?=(\\d{3})+${numStr.includes('.') ? '\\.' : '$'})`, 'g')
return numStr.replace(reg, ',')
}

手机号3-4-4分割

1
2
3
4
function formatMobile(mobile) {
let mobileReg = /(?=(\d{4})+$)/g;
return mobile.replace(mobileReg, '-');
}

将字符串首字母转化为大写,剩下为小写

1
2
3
4
const capitalize = (string) => {
const capitalizeRegex = /(?:^|\s+)\w/g
return string.toLowerCase().replace(capitalizeRegex, (match) => match.toUpperCase())
}

将字符串驼峰化

  1. foo Bar => fooBar
  2. foo-bar—- => fooBar
  3. foo_bar__ => fooBar
    1
    2
    3
    4
    5
    6
    const camelCase = (string) => {
    const camelCaseRegex = /[-_\s]+(.)?/g
    return string.replace(camelCaseRegex, (match, char) => {
    return char ? char.toUpperCase() : ''
    })
    }

实现一个trim函数

1
2
3
4
5
6
7
8
// 去除空格法
const trim = (str) => {
return str.replace(/^\s*|\s*$/g, '')
}
// 提取非空格法
const trim = (str) => {
return str.replace(/^\s*(.*?)\s*$/g, '$1')
}

表单验证常用正则

  • 用户名正则

    1
    2
    3
    4
    //用户名正则,4到16位(字母,数字,下划线,减号)
    var uPattern = /^[a-zA-Z0-9_-]{4,16}$/;
    //输出 true
    console.log(uPattern.test("caibaojian"));
  • 密码强度正则

    1
    2
    3
    4
    //密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
    var pPattern = /^.*(?=.{6,})(?=.*d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
    //输出 true
    console.log("=="+pPattern.test("caibaojian#"));
  • 整数正则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //正整数正则
    var posPattern = /^d+$/;
    //负整数正则
    var negPattern = /^-d+$/;
    //整数正则
    var intPattern = /^-?d+$/;
    //输出 true
    console.log(posPattern.test("42"));
    //输出 true
    console.log(negPattern.test("-42"));
    //输出 true
    console.log(intPattern.test("-42"));
  • 数字正则(可以是整数也可以是浮点数)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //正数正则
    var posPattern = /^d*.?d+$/;
    //负数正则
    var negPattern = /^-d*.?d+$/;
    //数字正则
    var numPattern = /^-?d*.?d+$/;
    console.log(posPattern.test("42.2"));
    console.log(negPattern.test("-42.2"));
    console.log(numPattern.test("-42.2"));
  • Email正则

    1
    2
    3
    var ePattern = /^([A-Za-z0-9_-.])+@([A-Za-z0-9_-.])+.([A-Za-z]{2,4})$/;
    //输出 true
    console.log(ePattern.test("99154507@qq.com"));
  • 手机号正则

    1
    2
    3
    var mPattern = /^1[34578]d{9}$/;
    //输出 true
    console.log(mPattern.test("15507621888"));
  • To Learn More

数据可视化项目开发

发表于 2022-03-03 | 分类于 css

数据可视化项目开发

  • To Learn More

    边框图片

    边框图片使用场景

  • 盒子的大小不一,边框样式相同
  • border-image

边框图片的切图原理(重要)

  • 把四个角切出去(九宫格的由来-四个角、四条边、中间部分),中间部分可以铺排、拉伸或者环绕
  • 按照上右下左顺序切割(保证四个角的完整性)

边框图片的使用语法

  • border-image-source 边框图片的路径
  • border-image-slice 指定图像的边界向内偏移(裁剪的尺寸,一定不要加单位,上右下左顺序)
  • border-image-width 图片边框的宽度(需要加单位)不回挤压文字(不是边框的宽度是边框图片的宽度)默认是boder宽度,
  • border-image-repeat 于图像边界是否应重复(repeat)、拉伸(stretch)或铺满(round)默认拉伸
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <div class="panel">
    <div class="inner">aaaa</div>
    </div>
    .panel {
    position: relative;
    width: 300rpx;
    height: 200rpx;
    border: 20rpx solid pink;
    border-width: 51rpx 38rpx 20rpx 132rpx;
    border-image-source: url('../../../static/icon/bd.png');
    border-image-slice: 51 38 20 132;
    .inner {
    position: absolute;
    }
    }

无缝滚动

无缝滚动原理

  • 先克隆marquee里面所有的行(row)

    1
    2
    3
    4
    $('.marquee-view .marquee').each(function () {
    let rows = $(this).children().clone();
    $(this).append(rows);
    })
  • 通过CSS3动画滚动marquee

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .marquee-view .marquee {
    animation: move 15s linear infinite;
    }
    @keyframes move {
    0% {

    }
    100% {
    transform: translateY(-50%);
    }
    }
  • 鼠标经过marquee就停止动画啊

    • animation-play-state: running | paused (指定动画是否正在运行或已暂停)
      1
      2
      3
      .marquee-view .marquee:hover {
      animation-play-state: paused;
      }

使用秋云 ucharts echarts踩坑

发表于 2022-03-02 | 分类于 前端框架、uniapp

uniapp使用秋云 ucharts echarts 高性能跨全端图表组件

  • To Learn More
  • 依赖uniapp的vue-cli项目:请将uni-modules目录复制到src目录,即src/uni_modules。(请升级uniapp依赖为最新版本)

自定义echarts参数

  • 使用eopts 但参数不能包含函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <qiun-data-charts
    :style="{ height: height, width: width }"
    type="area"
    ref="pieChart"
    :eopts="lineEopts"
    :opts="{yAxis:{data:[{min:0}]},extra:{area:{type:'curve',addLine:true,gradient:true}}}"
    :chartData="chartData"
    :echartsH5="true"
    :echartsApp="true"
    tooltipFormat="lineTooltip"
    />

自定义tooltipFormat格式

  • 在配置文件config-echarts.js里面定义对应的formatter 函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    <qiun-data-charts
    :style="{ height: height, width: width }"
    type="area"
    ref="pieChart"
    :eopts="lineEopts"
    :opts="{yAxis:{data:[{min:0}]},extra:{area:{type:'curve',addLine:true,gradient:true}}}"
    :chartData="chartData"
    :echartsH5="true"
    :echartsApp="true"
    tooltipFormat="lineTooltip"
    />

    // tooltip排序
    function compare(property) {
    return (arr, arr2) => {
    let a = arr[property];
    let b = arr2[property];
    return b - a;
    };
    }

    const cfe = {
    "formatter":{
    lineTooltip: (res) => {
    let result = '';
    let _res = res.sort(compare("value"));
    for (let i in _res) {
    if (i == 0) {
    result += res[i].axisValueLabel
    }
    let value = '--'
    if (_res[i].data !== null) {
    value = _res[i].data;
    }
    // #ifdef H5
    result += '\n' + _res[i].seriesName + ':' + value;
    // #endif

    // #ifdef APP-PLUS
    result += '<br/>' + _res[i].marker + _res[i].seriesName + ':' + value;
    // #endif
    }
    return result;
    },
    }

区域图设置渐变,自定义颜色color、graphicColor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
initColor() {
this.colorList = this.color.map((item, index) => {
return {
color: item,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: this.graphicColor[index] // 0% 处的颜色
}, {
offset: 0.4,
color: this.graphicColor[index] // 100% 处的颜色
}, {
offset: 1,
color: "#ffffff",
}],
global: false // 缺省为 false
}
}
}
})
},

tab切换数据合并问题,设置eopts参数

  • eopts不能传递function,如果option配置参数需要function,请将option写在config-echarts.js中即可实现。
    1
    2
    3
    lineEopts: {
    notMerge: true, // 是否不跟之前设置的 option 进行合并。默认为false。即表示合并
    }

使用mescroll-uni踩坑

发表于 2022-03-01 | 分类于 前端框架、uniapp

uniapp使用mescroll-uni

  • To Learn More

    tabs切换公用mescroll-uni

  • 初始化第一次定义不执行上拉刷新、下拉加载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    downOption: {
    auto: false, // 默认第一次不加载
    },
    upOption: {
    auto: false,
    page: {
    num: 0, //当前页 默认0,回调之前会加1; 即callback(page)会从1开始, 这里定义必须是0,不然切换tab重置this.mescroll.resetUpScroll() 之后,从第二页开始执行
    size: 10,
    },
    }
  • 切换tab初始化方法

    1
    2
    3
    4
    5
    6
    7
    8
    tabChage(item) {
    // 重置下拉刷新
    if (this.mescroll) {
    this.mescroll.scrollTo(0, 300);
    }
    // 重置列表为第一页 (自动执行 page.num=1, 再触发upCallback方法 )
    this.mescroll.resetUpScroll();
    }
  • 切换tab包裹了除列表之外的其余部分(不需要重新渲染)但可以滑动,配合v-if实现,及动态高度

  • top设置距离顶部高度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <view
    :style="{ height: 'calc(100vh' + -550 + 'rpx)' }"
    v-if="listData.length || pieChart"
    >
    <mescroll-uni
    ref="mescrollRef"
    top="185"
    @init="mescrollInit"
    @down="downCallback"
    :up="upOption"
    :down="downOption"
    @up="upCallback"
    >
    </mescroll-uni>
    </view>

echarts汇总

发表于 2022-01-26 | 分类于 前端框架

echarts汇总

  • To Learn More

    setOption

    1
    2
    3
    4
    5
    6
    7
    8
    // main.js
    import * as echarts from 'echarts'
    Vue.prototype.$echarts = echarts
    * echarts setOption第二个参数的含义
    chart.setOption(option, notMerge, lazyUpdate)
    * notMerge 可选,是否不跟之前设置的 option 进行合并,默认为 false,即合并

    myChart.setOption({...},true)

ECharts 默认loading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
initChart() {
this.chart = this.$echarts.init(this.$el);
this.chart.showLoading({
text: 'loading...',
color: '#1376fe',
textColor: '#1376fe',
// maskColor: 'rgba(0, 0, 0, 0.8)',
zlevel: 0,
});
setTimeout(() => {
this.chart.hideLoading();
this.setOptions(this.chartData);
}, 1000)
},

resize

1
2
* 每个子组件图表重新初始化一次,只需要在init中加入this.echart.resize
this.echart.resize()

echarts设置之stack参数

  • stack—数据堆叠,同个类目轴上系列配置相同的stack值后,后一个系列的值会在前一个系列的值上相加
  • 解决方法是,stack去掉,或者stack给不同的值
    1
    2
    3
    series: [{
    stack: 'total',
    }]

echarts案例大全

  • 强大社区Make A Pie展示各类的ECharts案例被关闭
  • 新的资源库
    • http://192.144.199.210/forum.php?mod=forumdisplay&fid=2
    • http://analysis.datains.cn/finance-admin/#/chartLib/all
    • http://ppchart.com/#/

js最近日期获取汇总

发表于 2022-01-26 | 分类于 JS

常用日期汇总

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
* 获取近半年日期
function halfYear() {
// 先获取当前时间
let curDate = (new Date()).getTime();
// 将半年的时间单位换算成毫秒
let halfYear = 365 / 2 * 24 * 3600 * 1000;
// 半年前的时间(毫秒单位)
let pastResult = curDate - halfYear;
// 日期函数,定义起点为半年前
let pastDate = new Date(pastResult);
let pastYear = pastDate.getFullYear();
let pastMonth = pastDate.getMonth() + 1;
pastMonth = pastMonth.toString().padStart(2, 0);
let pastDay = pastDate.getDate().toString().padStart(2, 0);
let endDate = pastYear + '-' + pastMonth + '-' + pastDay;
return endDate;
}
1
2
3
4
5
6
7
8
9
10
11
12
* 获取近一年日期
function reactYear() {
let nowDate = new Date();
let dates = new Date(nowDate);
dates.setDate(dates.getDate() - 365);
let year = dates.getFullYear();
let month = dates.getMonth() + 1;
month = month.toString().padStart(2, 0);
let strDate = dates.getDate().toString().padStart(2, 0);
let currentDate = year + '-' + month + '-' + strDate;
return currentDate;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
* 获取当前日期
function getCurDate(type) {
const date = new Date();
// date.setTime(date.getTime() + 24 * 60 * 60 * 1000);
date.setTime(date.getTime());
let year = date.getFullYear()
let month = date.getMonth() + 1
month = month.toString().padStart(2, 0);
let strDate = date.getDate().toString().padStart(2, 0);
let hour = date.getHours().toString().padStart(2, 0);
let minutes = date.getMinutes().toString().padStart(2, 0);
let seconds = date.getSeconds().toString().padStart(2, 0);
let curDate = year + '-' + month + '-' + strDate;
if(type) {
return `${year}-${month}-${strDate} ${hour}:${minutes}:${seconds}`;
}
return curDate;
}
1
2
3
4
5
6
7
8
9
10
11
* 最近三月
function beforeThree() {
const dates = new Date()
dates.setMonth(dates.getMonth() - 3);
let pastMonth = dates.getMonth() + 1;
let pastDay = dates.getDate();
pastMonth = pastMonth.toString().padStart(2, 0);
pastDay = pastDay.toString().padStart(2, 0);
const endDate = dates.getFullYear() + '-' + pastMonth + '-' + pastDay;
return endDate;
}
1
2
3
4
5
6
7
8
9
10
11
* 最近一月
function oneMonth() {
const dates = new Date();
dates.setMonth(dates.getMonth() - 1);
let pastMonth = dates.getMonth() + 1;
let pastDay = dates.getDate();
pastMonth = pastMonth.toString().padStart(2, 0);
pastDay = pastDay.toString().padStart(2, 0);
const endDate = dates.getFullYear() + '-' + pastMonth + '-' + pastDay;
return endDate
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
* 某年某月最后一天
function getLastDay(year, month) {
//获取本年本月的第一天日期
var date = new Date(year,month+1,'01');
//设置日期
date.setDate(1);
//设置月份
date.setMonth(date.getMonth());
//获取本月的最后一天
let cdate = new Date(date.getTime() - 1000*60*60*24);
//返回结果
// return cdate.getDate();
return `${cdate.getFullYear()}-${cdate.getMonth()+1}-${cdate.getDate()}`;
}
1
2
3
4
5
6
7
8
9
* 当月
function getMonthStartDate() {
const dates = new Date();
dates.setMonth(dates.getMonth());
let pastMonth = dates.getMonth() + 1;
pastMonth = pastMonth.toString().padStart(2, 0);
const endDate = dates.getFullYear() + '-' + pastMonth + '-' + '01';
return endDate
}
1
2
3
4
5
6
7
* 获取某月多少天
const _temp = '2021-06-12';
const month = _temp.substr(_temp.lastIndexOf("-") + 1, 2);
const year = _temp.substr(0, _temp.lastIndexOf("-"));
// console.log(1111, year, month, new Date(year, month, 0).getDate())
// 获取月份多少天
const day = new Date(year, month, 0).getDate();
1
2
3
4
5
6
7
* 获取当年当月第一天
getYearStartDate() {
const dates = new Date();
dates.setMonth(dates.getMonth());
const endDate = dates.getFullYear() + "-" + "01" + "-" + "01";
return endDate;
}
1
2
3
4
5
6
7
8
9
10
11
// utils.js
const globalFun = {
halfYear, reactYear, getCurDate, beforeThree, oneMonth,getLastDay, checkFull, getMonthStartDate,
};
export default globalFun;

// 全局方法挂载 main.js
import globalFun from "@/utils/utils.js";
Object.keys(globalFun).forEach((key) => {
Vue.prototype[key] = globalFun[key];
})

vue项目总结

发表于 2022-01-25 | 分类于 前端框架

vue项目总结

vue bus触发$emit 监听$on 关闭$off传值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.js
Vue.prototype.bus=new Vue()

// 子组件
this.bus.$emit("planLineDetail", false);

// 父组件
mounted() {
this.bus.$on("planLineDetail", (state, id) => {
// 逻辑
}
});

beforeDestroy() {
this.bus.$off("planLineDetail");
},

vue 混入 (mixin)

  • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      // .vue页面使用
    import common from "../mixins/common.js";
    export default {
    mixins: [screenSize, common, ....], // 混入js名称
    }
    // common.js
    export default {
    data(){
    return {
    }
    },
    methods: {

    },
    }

vue css 外部引入

1
2
3
4
5
6
// 直接页面分离
<style src="./emergency.scss" lang="scss" scoped></style>
// import
<style lang="scss" scoped>
@import "./detial.scss";
</style>

vue 动态组件(component)

1
2
3
4
5
6
7
8
<template>
<div>
<div class="form-con">
<component :is="currentView"></component>
</div>
</div>
</template>
* currentView 已注册组件的名字,或一个组件的选项对象

vue 全屏 Fullscreen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mounted() {
const that = this;
window.onresize = () => {
return (() => {
this.isFullscreen = this.checkFull(); // 判断是否可以全屏
})();
};
},
// 判断浏览器是否处于全屏状态 (需要考虑兼容问题)
function checkFull() {
//火狐浏览器
var isFull =
document.mozFullScreen ||
document.fullScreen ||
//谷歌浏览器及Webkit内核浏览器
document.webkitIsFullScreen ||
document.webkitRequestFullScreen ||
document.mozRequestFullScreen ||
document.msFullscreenEnabled;
if (isFull === undefined) {
isFull = false;
}
return isFull;
}

uniapp

发表于 2021-12-02 | 分类于 前端框架

uniapp项目总结

解决手机软键盘弹出挤压页面变形问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 统一处理模版页面按钮定位 -->
export const templateHeight = () => {
return uni.getSystemInfoSync().windowHeight - uni.upx2px(100);
}
<!-- 页面布局 -->
<view class="template-wrap" :style="{height: height + 'px'}">
<view class="template-wrap-con">
内容部分
</view>
<view class="bottom"">
底部固定按钮部分
</view>
</view>
<!-- css部分 -->
.template-wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
.template-wrap-con {
flex-grow: 1;
overflow: overlay;
}
}

css布局

  • ios个别版本对fixed的属性的支持性不好,需要用absolute替代
  • input 的 placeholder会出现文本位置偏上的时候
    • input 的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决是设置line-height:normal

使用uview组件

1
2
3
4
<!-- iOS 15 搜索框里多一个搜索图标怎么破 -->
[type="search"]::-webkit-search-decoration {
display: none;
}
1
2
3
4
5
6
7
8
9
10
11
<!-- iOS picker 日期 初始化日期无效 修改组件 与 uniapp 日期兼容有点差别 -->
<!-- 格式化时间,在IE浏览器(uni不存在此情况),无法识别日期间的"-"间隔符号 -->
<!-- 处理IOS不显示问题 -->
<!-- let fdate = this.defaultTime.replace(/\-/g, '/'); // 无需把-改为/ -->
let fdate = this.defaultTime;

<!-- uniapp iOS手机日期不识别- -->
<!-- 把yyy-mm-dd hh:mm:ss 格式ios不识别 把yyy-mm-dd hh:mm:ss 格式转换成 yyy/mm/dd hh:mm:ss -->
export const iosDataFilter = (time) => {
return time.replace(/-/g, '/');
}

复制粘贴(直接使用api 在手机app端 样式问题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
export const copyHandler = (e) => {
<!-- 直接传入可复制文本,无效 -->
const { name } = e.currentTarget.dataset;
let result;
let textarea = document.createElement('textarea');
textarea.value = name;
textarea.readOnly = 'readOnly';
document.body.appendChild(textarea);
textarea.select(); // 选中文本内容
textarea.setSelectionRange(0, name.length); // 设置选定区的开始和结束点
uni.showToast({
icon: 'none',
title: '复制成功'

})
result = document.execCommand('copy'); //将当前选中区复制到剪贴板
textarea.remove();
<!--
uni.setClipboardData({
data: name,
success: () => {
uni.showToast({
icon: 'none',
title: '复制成功'
})
}
});
-->
}

js方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 调用async方法 test() -->
test().then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
});

<!-- 数据没三位使用,分隔 -->
numSplit(value) {
if(value != '-') {
let val = value && Number(value);
return val && val.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
}
return 0;
}
123…7
yongfeng.peng

yongfeng.peng

(女英

67 日志
13 分类
11 标签
© 2022 yongfeng.peng