分页: 2/273 第一页 上页 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 下页 最后页 [ 显示模式: 摘要 | 列表 ]
12月16

import type { App, Plugin } from 'vue';
export const withInstall = <T>(component: T, alias?: string) => {
  const comp = component as any;
  comp.install = (app: App) => {
    app.component(comp.name || comp.displayName, component);
    if (alias) {
      app.config.globalProperties[alias] = component;
    }
  };
  return component as T & Plugin;
};




import { withInstall } from '/@/utils';
import appLogo from './src/AppLogo.vue';
export const AppLogo = withInstall(appLogo);
12月16

props: {
      /**
       * Specified role is visible
       * When the permission mode is the role mode, the value value can pass the role value.
       * When the permission mode is background, the value value can pass the code permission value
       * @default ''
       */
      value: {
        type: [Number, Array, String] as PropType<RoleEnum | RoleEnum[] | string | string[]>,
        default: '',
      },
    },



export const buttonProps = {
  color: { type: String, validator: (v) => ['error', 'warning', 'success', ''].includes(v) },
  loading: { type: Boolean },
  disabled: { type: Boolean },
  /**
   * Text before icon.
   */
  preIcon: { type: String },
  /**
   * Text after icon.
   */
  postIcon: { type: String },
  /**
   * preIcon and postIcon icon size.
   * @default: 14
   */
  iconSize: { type: Number, default: 14 },
  onClick: { type: Function as PropType<(...args) => any>, default: null },
};

12月16

AppSearch.vue

15:17软件分析与设计  From: 本站原创

<script lang="tsx">
  import { defineComponent, ref, unref } from 'vue';
  import { Tooltip } from 'ant-design-vue';
  import { SearchOutlined } from '@ant-design/icons-vue';
  import AppSearchModal from './AppSearchModal.vue';
  import { useI18n } from '/@/hooks/web/useI18n';

  export default defineComponent({
    name: 'AppSearch',
    setup() {
      const showModal = ref(false);
      const { t } = useI18n();

      function changeModal(show: boolean) {
        showModal.value = show;
      }

      return () => {
        return (
          <div class="p-1" onClick={changeModal.bind(null, true)}>
            <Tooltip>
              {{
                title: () => t('common.searchText'),
                default: () => <SearchOutlined />,
              }}
            </Tooltip>
            <AppSearchModal onClose={changeModal.bind(null, false)} visible={unref(showModal)} />
          </div>
        );
      };
    },
  });
</script>
12月16
[codes=c#]
VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","http://localhost:3300/upload"]]


export function createProxy(list: ProxyList = []) {
  const ret: ProxyTargetList = {};
  for (const [prefix, target] of list) {
    const isHttps = httpsRE.test(target);

    // https://github.com/http-party/node-http-proxy#options
    ret[prefix] = {
      target: target,
      changeOrigin: true,
      ws: true,
      rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
      // https is require secure=false
      ...(isHttps ? { secure: false } : {}),
    };
  }
  return ret;
}

[/codes]
Tags: , , , , ,
12月14
就是xhr.abort(),不需要服务器确认。
axios/blob/master/lib/cancel/CancelToken.js#L22
axios/blob/master/lib/adapters/xhr.js#L153
the-abort()-method

在开发中,经常会遇到接口重复请求导致的各种问题。

对于重复的get请求,会导致页面更新多次,发生页面抖动的现象,影响用户体验。

对于重复的post请求,会导致在服务端生成两次记录(例如生成两条订单记录)。

如果当前页面请求还未响应完成,就切换到了下一个路由,那么这些请求直到响应返回才会中止。

无论从用户体验或者从业务严谨方面来说,取消无用的请求确实是需要避免的。

当然我们可以通过页面loading来避免用户进行下一次的操作,但本文只讨论单纯的如何取消这些无用的请求。

axios 的 cancelToken
axios是一个主流的http请求库,它提供了两种取消请求的方式。

通过axios.CancelToken.source生成取消令牌token和取消方法cancel
[codes=c#]
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
通过axios.CancelToken构造函数生成取消函数

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();
[/codes]
需要注意的是在catch中捕获异常时,应该使用axios.isCancel()判断当前请求是否是主动取消的,以此来区分普通的异常逻辑。
封装取消请求逻辑
上面有两种取消请求,用哪种都是可以的,这里使用第二种。

取消请求主要有两个场景:

当请求方式method,请求路径url,请求参数(get为params,post为data)都相同时,可以视为同一个请求发送了多次,需要取消之前的请求
当路由切换时,需要取消上个路由中未完成的请求
我们封装几个方法:
[codes=c#]
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
const pending = new Map()
/**
* 添加请求
* @param {Object} config
*/
const addPending = (config) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
    if (!pending.has(url)) { // 如果 pending 中不存在当前请求,则添加进去
      pending.set(url, cancel)
    }
  })
}
/**
* 移除请求
* @param {Object} config
*/
const removePending = (config) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  if (pending.has(url)) { // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}
/**
* 清空 pending 中的请求(在路由跳转时调用)
*/
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}
[/codes]
Map是ES6中一种新型的数据结构,本身提供了诸多方法,方便操作,适合当前场景。如果不熟悉的可以查看ECMAScript 6 入门。

在给config.cancelToken赋值的时候,需要判断当前请求是否已经在业务代码中使用了cancelToken

qs是一个专门用来转换对象和字符串参数的库,最初是由 TJ 创建并维护的,也是axios推荐使用的参数序列化库。这里我们的目的只是单纯的将参数对象转换为字符串方便拼接。

Map结构默认部署了Symbol.iterator属性,可以使用for...of循环直接获取键名和键值,当然你也可以使用for...in循环。

在 axios 拦截器中使用
主要的方法已经写好了,只需要添加到axios拦截器中就可以了。
[codes=c#]
axios.interceptors.request.use(config => {
  removePending(options) // 在请求开始前,对之前的请求做检查取消操作
  addPending(options) // 将当前请求添加到 pending 中
  // other code before request
  return config
}, error => {
  return Promise.reject(error)
})

axios.interceptors.response.use(response => {
  removePending(response) // 在请求结束后,移除本次请求
  return response
}, error => {
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
  }
  return Promise.reject(error)
})
将clearPending()方法添加到vue路由钩子函数中

router.beforeEach((to, from, next) => {
  clearPending()
  // ...
  next()
})
[/codes]
12月13

 Vue2中的语法糖.sync:

在父组件中的
<div :title.sync="visible" ></div>
等同于: / .sync将针对于title的监听事件缩写 /
<div :title="visible" @update:title="visible = $event" ></div>
在子组件的methods中使用如下将新的value传给父级:

` handleClose() {        this.$emit('update:title', newValue)    }`

Vue3中用v-model替代了.sync修饰符和组件的model选项 / 不兼容 /:

针对于有参数的:<div v-model:title="visible" ></div>
等同于:<div :title="visible" @update:title="visible = $event" ></div>

Vue3中还针对于没有参数的v-model:

<div v-model="visible" ></div>
没有参数但却实际上在父组件内传入modelValue,类似于:
v-model:modelValue="visible" @updata:modelValue="visible =$event"
在父组件里是运用visible,在子组件里传入的props里的是modelValue.
更改参数,传入父级也是用modelValue
this.$emit('update:modelValue', newValue)

详情可以看Vue3的官方

.sync在Vue3的转变

12月12
先来看看Vue3的几种组件通信方式:
[codes=c#]
props
$emit
expose / ref
$attrs
v-model
provide / inject
Vuex
[/codes]
下面分别介绍这几种方式的写法:

1、props
[codes=c#]
父组件



子组件

[/codes]
2、$emit

父组件
[codes=c#]



子组件


[/codes]
3、expose / ref

父组件
[codes=c#]



子组件

[/codes]
4、attrs

父组件
[codes=c#]



子组件

[/codes]
5、v-model

父组件(v-model可省略)
[codes=c#]



子组件


[/codes]
6. provide / inject

父组件
[codes=c#]


子组件

[/codes]
接下来是Vue2.x 组件通信使用方法:
1、 props

父组件
[codes=c#]


子组件
export default {
  props:{
      msg:{
          type:String,
          default:'这是默认数据'
      }
  },
  mounted(){
      console.log(this.msg)
  }
[/codes]
2、.sync
[codes=c#]
父组件


[/codes]
3、v-model
[codes=c#]
父组件


[/codes]
4、ref
[codes=c#]
子组件
export default {
    data(){
        return {
            name:""
        }
    },
    methods:{
        someMethod(msg){
            console.log(msg)
        }
    }
}

父组件


[/codes]
5、$emit / v-on
[codes=c#]
子组件
export default {
  data(){
      return { msg: "这是发给父组件的信息" }
  },
  methods: {
      handleClick(){
          this.$emit("sendMsg",this.msg)
      }
  },
}
父组件


export default {
    methods:{
        getChildMsg(msg){
            console.log(msg) // 这是父组件接收到的消息
        }
    }
}
6、children/parent
[codes=c#]
父组件
export default{
    mounted(){
        this.$children[0].someMethod() // 调用第一个子组件的方法
        this.$children[0].name // 获取第一个子组件中的属性
    }
}

子组件
export default{
    mounted(){
        this.$parent.someMethod() // 调用父组件的方法
        this.$parent.name // 获取父组件中的属性
    }
}
[/codes]
7、EventBus
[codes=c#]
// 方法一
// 抽离成一个单独的 js 文件 EventBus.js ,然后在需要的地方引入
// EventBus.js
import Vue from "vue"
export default new Vue()

// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
[/codes]
8、Vuex(这个就不举例子了........懂的都懂!)
12月9

vueuse

22:35软件分析与设计  From: 本站原创
VueUse is a collection of utility functions based on Composition API. We assume you are already familiar with the basic ideas of Composition API before you continue.
https://vueuse.org/guide/

exp:
[codes=c#]
//npm i @vueuse/core
import { useMouse, usePreferredDark, useLocalStorage } from '@vueuse/core'

export default {
  setup() {
    // tracks mouse position
    const { x, y } = useMouse()

    // is user prefers dark theme
    const isDark = usePreferredDark()

    // persist state in localStorage
    const store = useLocalStorage(
      'my-storage',
      {
        name: 'Apple',
        color: 'red',
      },
    )

    return { x, y, isDark, store }
  }
}
[/codes]
Tags:
12月9

ECMAScript概览

22:28软件分析与设计  From: 本站原创
前言 (介绍 ECMAScript)
最初 JavaScript 语言有 2 份标准:

ECMA-262:主标准,由 ECMA 国际组织(Ecma International)负责管理(为了让最初的JavaScript 与最初的 JScript 能遵循同一套标准发展而诞生的 ECMAScript ,正好排到了作为 Ecma 的 262 号标准,所以得到 ECMA-262 编号。)

ISO/IEC 16262:第二标准,由国际标准化组织 ISO(International Standard Organization)和国际电子技术委员会 IEC(International Electrotechnical Commission)负责管理

出于商标版权的原因,规范标准中将这门语言称为 ECMAScript ,所以原则上 JavaScript 与 ECMAScript 指的是同一个东西,但有时也会加以区分:

JavaScript:指语言及其实现
ECMAScript:指语言标准及语言版本,比如 ES6 表示语言(标准)的第 6 版
ECMAScript 发展历史
ECMAScript 1(1997 年 6 月):规范第一版
ECMAScript 2(1998 年 6 月):为了同步 ISO 标准,引入了一些小更新
ECMAScript 3(1999 年 12 月):增加了正则表达式、字符串处理、控制语句(do-while、switch)、异常处理(try-catch)等众多核心特性
ECMAScript 4(2008 年 7 月废除):本来是一次大规模升级(静态类型、模块、命名空间等),但跨度过大,出现了分歧,最终没能推广使用
ECMAScript 5(2009 年 12 月):变化不大,加了一些标准库特性和严格模式
ECMAScript-5.1(2011 年 6 月):又一次小更新,为了同步 ISO 标准
ECMAScript 6(2015 年 6 月):一大波更新,实现了当年 ES4 的许多设想,并正式改为按年份命名规范版本
ECMAScript 2016(2016 年 6 月):第一个年度版本,与 ES6 相比,发布周期较短,新特性也相对少些
ECMAScript 2017(2017 年 6 月):第二个年度版本...
以后的 ECMAScript 版本(ES2018、ES2019、ES2020 等)都在 6 月正式获准生效
12月8
[codes=c#]
interface ListItem {
  name: string;
  address: string;
};

let listData = [
  {name: 'xiaoming', address: '高尔夫花园'},
  {name: 'xiaoming', address: '国宾一号'},
  {name: 'hanmeimei', address: '一顿小镇'},
];

console.log(listData);

let newListData  = [];
newListData = listData.filter((item, index) => {
  undefined;
  return (
    listData.findIndex(
      (item1) => item1.name == item.name
    ) == index
  );
});

console.log(newListData);

[/codes]
分页: 2/273 第一页 上页 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 下页 最后页 [ 显示模式: 摘要 | 列表 ]