关于typescript:使用TS封装axios

<article class=“article fmt article-content”><h2>一、根本封装</h2><pre><code>import axios from ‘axios’import type { AxiosInstance, AxiosRequestConfig } from ‘axios’class Request { // axios 实例 instance: AxiosInstance constructor(config: AxiosRequestConfig) { this.instance = axios.create(config) } request(config: AxiosRequestConfig) { return this.instance.request(config) }}export default Request</code></pre><h2>二、拦截器封装</h2><p>1.类拦截器:在类中对axios.create()创立的实例调用interceptors下的两个拦截器。</p><pre><code>// index.tsconstructor(config: AxiosRequestConfig) { this.instance = axios.create(config) this.instance.interceptors.request.use( (res: AxiosRequestConfig) => { console.log(‘全局申请拦截器’) return res }, (err: any) => err, ) this.instance.interceptors.response.use( // 因为咱们接口的数据都在res.data下,所以咱们间接返回res.data (res: AxiosResponse) => { console.log(‘全局响应拦截器’) return res.data }, (err: any) => err, )}</code></pre><p>2.实例拦截器:保障了封装的灵活性,每一个实例中的拦截器后的解决可能不一样。<br/>拦截器的执行程序为实例申请→类申请→实例响应→类响应;这样能够在申请的时候做一些不同的拦挡。</p><pre><code>根底拦挡// types.tsimport type { AxiosRequestConfig, AxiosResponse } from ‘axios’export interface RequestInterceptors { // 申请拦挡 requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig requestInterceptorsCatch?: (err: any) => any // 响应拦挡 responseInterceptors?: (config: AxiosResponse) => AxiosResponse responseInterceptorsCatch?: (err: any) => any}// 自定义传入的参数export interface RequestConfig extends AxiosRequestConfig { interceptors?: RequestInterceptors}</code></pre><p>定义完根底的拦截器之后,须要革新咱们传入的参数的类型,因为是axios提供的AxiosRequestConfig是不容许咱们传入拦截器的,所以咱们须要自定义拦截器RequestConfig,让其继承AxiosRequestConfig。</p><pre><code>// index.tsimport axios, { AxiosResponse } from ‘axios’import type { AxiosInstance, AxiosRequestConfig } from ‘axios’import type { RequestConfig, RequestInterceptors } from ‘./types’class Request { // axios 实例 instance: AxiosInstance // 拦截器对象 interceptorsObj?: RequestInterceptors constructor(config: RequestConfig) { this.instance = axios.create(config) this.interceptorsObj = config.interceptors this.instance.interceptors.request.use( (res: AxiosRequestConfig) => { console.log(‘全局申请拦截器’) return res }, (err: any) => err, ) // 应用实例拦截器 this.instance.interceptors.request.use( this.interceptorsObj?.requestInterceptors, this.interceptorsObj?.requestInterceptorsCatch, ) this.instance.interceptors.response.use( this.interceptorsObj?.responseInterceptors, this.interceptorsObj?.responseInterceptorsCatch, ) // 全局响应拦截器保障最初执行 this.instance.interceptors.response.use( // 因为咱们接口的数据都在res.data下,所以咱们间接返回res.data (res: AxiosResponse) => { console.log(‘全局响应拦截器’) return res.data }, (err: any) => err, ) }}</code></pre><p>3.接口拦挡:对繁多接口进行拦挡操作<br/>首先将AxiosRequestConfig类型批改为RequestConfig容许传递拦截器;在类拦截器中将接口申请的数据进行了返回,也就是说在request()办法中失去的类型就不是AxiosRequest类型。</p><p>查看axios的index.d.ts中对<strong>request()</strong>办法的类型如下:</p><pre><code> // type.ts request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;也就是说容许咱们传递的类型,从而扭转request()办法的返回值类型:// index.tsrequest<T>(config: RequestConfig): Promise<T> { return new Promise((resolve, reject) => { // 如果咱们为单个申请设置拦截器,这里应用单个申请的拦截器 if (config.interceptors?.requestInterceptors) { config = config.interceptors.requestInterceptors(config) } this.instance .request<any, T>(config) .then(res => { // 如果咱们为单个响应设置拦截器,这里应用单个响应的拦截器 if (config.interceptors?.responseInterceptors) { res = config.interceptors.responseInterceptors<T>(res) } resolve(res) }) .catch((err: any) => { reject(err) }) })}</code></pre><p>申请接口拦挡是最前执行,而响应拦挡是最初执行。</p></article> ...

March 5, 2024 · 2 min · jiezi

关于typescript:ts封装axios

<article class=“article fmt article-content”><p>axios拦截器能够让咱们在我的项目中对后端http申请和响应主动拦挡解决,缩小申请和响应的代码量,晋升开发效率同时也不便我的项目前期保护。在申请响应的interceptors(因特塞泼特斯).这个外面的话.他分为申请拦截器和响应拦截器,申请拦截器外面个别在申请头外面携带token值.响应拦截器外面对状态码的判断.比方说返回401的时候就是token没权限.跳转到登录界面.</p><p>封装axiso首先下载</p><pre><code>npm install axios</code></pre><p>创立文件夹request,在文件夹中创立<code>index.ts</code>文件名,开始对axios进行手动封装封装 或 官网复制粘贴拦截器(https://www.axios-http.cn/docs/interceptors)</p><ol><li>首先引入下载好的aixos</li><li>创立实例</li><li><p>申请拦挡,别离蕴含申请胜利 和 申请谬误两个函数</p><ol><li>执行机会为:发动申请时,申请还没有发送进来时执行 申请拦挡</li><li>申请胜利:申请头携带token</li><li>申请谬误:产生谬误申请时,能够解决 4 结尾的谬误</li></ol></li><li><p>响应拦挡,别离包响应胜利 和 响应失败两个函数</p><ol><li>执行机会为:申请完结后,服务器有响应的时候执行</li><li>响应胜利:返回状态码为2xx(200…)携带的数据</li><li>响应失败:响应失败/谬误时,能够对 5 结尾的状态码进行解决、申请超时、谬误状态码的解决。</li></ol></li><li>导出封装好的axios</li></ol><p>手动封装axios代码详情</p><pre><code>// 引入axiosimport axios from axios// 进度条和款式import nProgress from “nprogress” // npm install nprogressimport “nprogress/nprogress.css”// 实例化axiosconst install = axios.create({ // 申请地址的前缀 公共全局的URL baseURL:"", // 申请时长 — 超出定义的时长,申请超时 timeout:5000})// 申请拦挡install.interceptors.request.use( (config)=>{ // 开始进度条 nProgress.start() // 获取token const token = localStorge.getItem(’token’) // 申请头携带token config.headers[’’] = “Bearer " + token return config }, (error)=>{ return Promise.reject(error) })// 响应拦挡install.interceptors.response.use( (response)=>{ // 响应胜利敞开进度条 nProgress.done() // 返回响应的数据 return response }, (error)=>{ // 申请超时解决 if(error.message.includes(’timeout’)){ alert(‘申请超时’) return; } // 不同谬误状态码解决 const code = error.response.status; switch(code){ case 400: console.log(‘申请谬误’); break; case 401: console.log(‘未受权’); break; case 403: console.log(‘禁止拜访’); break; case 404: console.log(‘页面隐没’); break; case 500: console.log(‘服务器外部谬误’); break; case 502: console.log(‘网关谬误’); break; } return Promise.reject(error) })// 导出封装好的aixos</code></pre><p>以上是axios两次封装,咱们还能够将他们的申请形式也封装一下,比方在同文件夹内新建一个<code>methods.ts</code>文件,而后如下代码:</p><pre><code>// 引入封装好的axiosimport install from “./index”// 定义任意类型接口interface anyType{ [key:string]:any | (string|number)}// 定义类型接口interface dataType{ url:string, // 门路 method?:string, // 申请办法 get / post… headers?:anyType, // 申请头 params?:anyType, // get申请携带参数用的 data?:anyType, // post申请携带参数用的}// 创立 get 申请办法export const get = (data:dataType)=>{ // 定义申请办法 data.method = “GET” // 返回 return install(data)}// 创立post申请办法export const = (data:dataType)=>{ // 定义post申请办法 data.method = “POST” // 返回 return install(data)}</code></pre><p>URL=http://172.16.10.111:5886/#/</p><p>模仿申请</p><pre><code>// 引入封装好的 get post 申请办法import {get,post} from “./methods”// 模仿一个申请接口export const getLogin = (data) =>{ return get({ url:“申请的门路”, data:data // 传递参数 })}</code></pre><p>最初只须要在组件内调用 getLogin 这个办法即可。</p><p>更具体的封装</p><pre><code>/** * * axios * * 封装 axios 逻辑 * 1.下载依赖 * 2.创立文件 * 3.导入/引入 axios * 4.增加默认配置 * 5.定义返回的数据类型 * 6.增加拦截器 * 7.封装申请办法 * 8.导出/抛出 实例 * * * 1.AxiosInstance * 示意: * axios 实例的配置项 url 办法 headers 参数 * 2.AxiosRequestConfig * 示意: * axios 实例的类型 * 3.AxiosResponse * 示意: * axios 响应的数据结构 状态码 响应头 响应数据 * 4.AxiosError * 示意: * axios 申请产生谬误的谬误对象 错误信息 申请配置 * 5.InternalAxiosRequestConfig * 示意: * 扩大了 AxiosRequestConfig 接口 * /// 导入import axios, { AxiosInstance, AxiosResponse, AxiosRequestConfig, AxiosError, InternalAxiosRequestConfig } from ‘axios’;// 默认配置 实例化const instance: AxiosInstance = axios.create({ baseURL: import.meta.url || “”, //设置api 的根本门路 相当于 默认的根目录 timeout: 5000, //申请时长})// 申请拦截器instance.interceptors.request.use( (config: InternalAxiosRequestConfig) => { // return config; }, // 申请地址谬误 (error: AxiosError) => { return Promise.reject(error); })// 响应拦截器instance.interceptors.response.use( (response: AxiosResponse) => { // 判断 if (response.status === 200) { return response.data } else { // 如果响应状态码不是 200 返回一个回绝的 Promise // Promise 三个状态 别离 胜利,失败,进行中 return Promise.reject() } }, (error: AxiosError) => { // return Promise.reject(error); throw new Error(“Http Error: " + error) })// 导出export default instance// 定义后果 接口的 result // unknown 未知类型export interface Result<T = unknown> { message: string; code: number; data: T; [key: string]: any; // 其余任意类型}// 申请后果的类型 Result/ 定义一个名为Result的接口 默认类型为 泛型T unknown 未知类型 接口是一种用户形容对象构造的类型 接口的属性都有 message:字符串类型,代表后果的音讯信息 code:数字类型,代表后果的状态 data:泛型类型T, 代表后果的数据 默认为 unknown 类型 [key:string]:any:索引签名,代表接口能够具备任意数量的其余属性,属性名为字符串类型,属性值为任意类型 PS: 通过定义这个接口,咱们能够在代码中应用Result类型来示意一个具备特定构造的后果对象。 例如,能够应用Result<number>来示意一个具备数字类型数据的后果对象。/// 定义后果接口的resultexport interface Result<T = unknown> { message: string; code: number; data: T; [key: string]: any; // 其余的任意类型}// axios.get(“xxxx”, { params: {} });export const http = { get<T = any>(url: string, params?: object): Promise<Result<T>> { console.log(params); return service.get<T, Result<T>>(url, { params }); }, post<T = any>(url: string, data?: object): Promise<Result<T>> { return service.post<T, Result<T>>(url, data); }, put<T = any>(url: string, data?: object): Promise<Result<T>> { return service.put<T, Result<T>>(url, data); }, delete<T = any>(url: string, data?: object): Promise<Result<T>> { return service.delete<T, Result<T>>(url, data); },};export const http = { // axios.get(‘xxx门路’,{params:{}}) 原型 get<T = any>(url: string, params?: object): Promise<Result<T>> { return instance.get<T, Result>(url, {params}) }, post<T = any>(url:string,data?:object): Promise<Result<T>> { return instance.post<T, Result<T>>(url, {data}); }, put<T = any>(url:string,data?:object): Promise<Result<T>> { return instance.put<T,Result<T>>(url, {data}); }, delete<T =any>(url:string,data?:object): Promise<Result<T>> { return instance.delete<T,Result<T>>(url, {data}); },} 解析 这段代码是应用 TypeScript 定义的一个 HTTP 申请库的封装。这段代码次要蕴含两个局部,一个是 Result 接口,另一个是 http 对象。Result 接口 Result 接口定义了返回后果的通用构造。它蕴含以下属性: message: 字符串类型,通常用于形容操作的后果音讯。 code: 数字类型,通常用于示意操作的返回状态码。 data: 能够是任何类型,用于存储申请返回的数据。 [key: string]: any;: 这是一个残余属性,意味着能够增加任何其余类型的属性。 这个接口能够用来定义 HTTP 申请的响应格局,使得调用者能够不便地解决返回后果。http 对象 http 对象提供了常见的 HTTP 申请办法,并对每个办法进行了泛型参数化,使得返回后果能够灵便地适应不同的数据类型。 get 办法:用于发送 GET 申请。它承受一个 URL 和可选的参数对象,返回一个 Promise 对象,该 Promise 在申请实现后解析为 Result 类型。调用示例:http.get<User>(’/users/123’). post 办法:用于发送 POST 申请。它承受一个 URL、一个可选的申请数据对象,返回一个 Promise 对象,该 Promise 在申请实现后解析为 Result<T> 类型,其中 T 是申请数据对象的类型。调用示例:http.post<User>(’/users’, userData). put 办法:用于发送 PUT 申请。它承受一个 URL、一个可选的申请数据对象,返回一个 Promise 对象,该 Promise 在申请实现后解析为 Result<T> 类型,其中 T 是申请数据对象的类型。调用示例:http.put<User>(’/users/123’, userData). delete 办法:用于发送 DELETE 申请。它承受一个 URL 和一个可选的申请数据对象,返回一个 Promise 对象,该 Promise 在申请实现后解析为 Result<T> 类型,其中 T 是申请数据对象的类型。调用示例:http.delete<User>(’/users/123’).** 如何调用和创立接口 这段代码没有明确提供如何创立和实例化接口或类的具体步骤,因而无奈提供对于这部分的具体阐明。但通常来说,你能够应用 TypeScript 的类和接口来创立和实例化对象,而后应用这些对象的办法。例如: typescript 复制代码 import { http, Result } from ‘./http’; // 导入 http 和 Result 接口 // 应用 http.get 发送 GET 申请 http.get<User>(’/users/123’).then(response => { console.log(response.data); // 打印返回的用户数据 }); 详解 /* get申请办法 办法名为get 应用了 泛型<T = any> 默认是类型为 any(任意类型) get<T = any>(url:string,params?:object):Promise<Result = unknow>{ return aixos.get<T,Result<T>>(url,params) } 他承受两个参数 第一个是url(门路)字符串类型 第二个是params(承受参数的)可选参数 对象类型 get办法 返回一个promise对象 这个对象是一个未知类型的 Result(申请后果)对象 函数外部 调用了axios中get申请办法,同时传入了 url(字符串类型) 和 params(可选对象类型) 外部的get申请办法也应用了泛型 他承受两个类型参数 第一个类型参数是 T (any) 第二个类型参数是 Result<T> 返回一个Promise对象 返回的Promise对象的后果可能是一个T类型的值 或者是一个Result<T>类型的值 总结: 这个办法的作用是发送一个Get申请,返回一个Promise对象, 这个Promise对象的后果是一个Result对象 Result对象可能蕴含一个T类型的值,也可能是蕴含一个Result<T>类型的值 */ 发送一个申请,默认类型泛型(any)任意类型 返回一个promise对象,承受两个参数 url(字符串类型) 和 params(可选参数类型对象) 输出 一个aixos申请形式默认类型 泛型 或 Result 泛型 ,传递两个参数url 和 params(ps:已定义好类型))</code></pre><p>援用/调用</p><pre><code>引入import { http } from ‘@/utils/Request’ http.get(‘www.baidu.com’).then(res=>{ console.log(res,‘111’); })</code></pre></article> ...

March 5, 2024 · 4 min · jiezi

关于typescript:TypeScript-工具泛型

highlight: github theme: juejin前言Typescript 中默认内置了很多工具泛型,通过应用这些工具,能够使得咱们定义类型更加灵便,高效。本文将会介绍罕用泛型工具的应用技巧,以及对其实现原理进行相应的解析,如果有谬误的中央,还望指出。 Partial\<T>作用:将传入对象类型 T 的属性变为可选属性。 示例: interface Person { name: string; age: number;}const tom: Partial<Person> = { name: "Tom",};Partial<Person> 等价于 interface Person { name?: string; age?: number;}实现原理: 通过关键字 keyof 将传入对象类型的键值转换为联结类型。通过关键字 in 遍历联结类型,即遍历对象的键值。通过类型映射,将对象的属性转换为可选属性type MyPartial<T> = { [P in keyof T]?: T[P];};Readonly\<T>作用:把传入对象类型 T 属性变为只读属性。 示例: interface Person { name: string; age: number;}const tom: Readonly<Person> = { name: "Tom", age: 18;};tom.age = 22 // errorReadonly<Person> 等价于 interface Person { readonly name: string; readonly age: number;}实现原理: ...

September 25, 2023 · 3 min · jiezi

关于typescript:vitevue3-配置ESLint与prettier

本次我的项目创立所应用工具版本node:v18.16.0 (vite须要你的node的版本在12以上)vite:v4.4.9 vite内置了eslint和prettier的模板,所以不必像以前那样从头配置Eslint和Prettier 我的项目创立步骤如下:一、vite 创立我的项目npm init vite@latest 我的项目名字框架选vue选customize with create-vue,而后依据项目选择(抉择customize with create-vue理论就是去调了npm init vue@latest) 二、我的项目创立实现后的目录构造曾经主动帮咱们生成.eslintrc.cjs和.prettierrc.json两个文件 我的项目构造 .prettierrc.json 文件 { //一行最多多少个字符 printWidth: 100, // 指定每个缩进级别的空格数 tabWidth: 2, // 应用制表符而不是空格缩进行 useTabs: true, // 在语句开端是否须要分号 semi: true, // 是否应用单引号 singleQuote: true, // 多行时尽可能打印尾随逗号。(例如,单行数组永远不会呈现逗号结尾。) 可选值"<none|es5|all>",默认none trailingComma: 'es5'}.eslintrc.cjs文件 三、装置vscode插件 四、ESLint 和 Prettier 配合应用prettier官网提供了一款工具 eslint-config-prettier这个工具其实禁用掉了一些不必要的以及和Prettier相冲突的ESLint规定。 装置依赖 pnpm install --save-dev eslint-config-prettierpnpm install --save-dev eslint-plugin-prettierpnpm install --save-dev prettier批改eslintrc文件{ "extends": ["plugin:prettier/recommended"]} 配置后果通过以上配置,在咱们ctrl+s进行保留的时候,会主动按着咱们配置的prettier对代码进行格式化。保留前:因为咱们在.prettierrc.json设置了规定,所以 双引号报错提醒句末加分号报错提醒单行超100字符报错提醒ctrl+s保留后:报错提醒隐没且代码格式化以上,就实现了应用eslint+prettier,进行代码格式化的校验和配置,如果还须要其余配置,依据官网文档批改对应文件即可。

September 24, 2023 · 1 min · jiezi

关于typescript:在项目中使用Service-Worker-与-PWA

小册这是我整顿的学习材料,十分零碎和欠缺,欢送一起学习古代JavaScript高级小册深入浅出Dart古代TypeScript高级小册linwu的算法笔记引言最近next我的项目有应用pwa技术,应用起来也不简单,目前浏览器的兼容性也比拟良好 Service Worker是浏览器中独立于网页运行的脚本,而PWA(渐进式Web应用程序)是一种Web应用程序,其外观和感觉相似于原生应用程序。在探讨Service Worker与PWA之前,让咱们先简要理解一下Web Worker。Web Worker1. 什么是 Web Worker?Web Worker 是浏览器内置的线程,用于执行非阻塞事件循环的 JavaScript 代码。因为 JavaScript 是单线程语言,一次只能解决一个工作。简单工作的呈现可能导致主线程被阻塞,重大影响用户体验。Web Worker 的作用是容许主线程创立 worker 线程,使它们能够同时运行。Worker 线程次要负责解决简单的计算工作,而后将后果返回给主线程。简而言之,worker 线程执行简单计算,同时放弃页面(主线程)的流畅性,不会造成阻塞。 2. 类型Web Worker 有三种次要类型: Dedicated Workers【专用 Worker】由主线程实例化,只能与主线程通信。Shared Workers【共享 Worker】能够被同源的所有线程拜访。Service Workers【服务 Worker】可能管制其关联的网页,拦挡和批改导航、资源申请,并缓存资源,使您可能在某些状况下灵便控制应用程序的行为。3. 限度1. 同源限度调配给 Worker 线程运行的脚本文件必须与主线程的脚本文件同源,通常都应该放在同一我的项目下。 2. DOM 限度Web Workers 无法访问某些要害的 JavaScript 个性,包含: 1 DOM(因为这可能导致线程不平安) 2 window 对象 3 document 对象 4 parent 对象 3. 文件限度出于平安思考,worker 线程无奈读取本地文件。它们加载的脚本必须来自网络,并且必须与主线程的脚本同源。 什是Service Worker?Service Worker(服务工作线程)是一种在浏览器背地运行的脚本,用于提供弱小的离线和缓存性能,以改善 Web 应用程序的性能和可靠性。它是渐进式网络应用程序(Progressive Web App,PWA)的要害组成部分,能够让 Web 应用程序更像本地应用程序,即便在离线状态下也能失常工作。Service Worker 是 Web 开发中的一个弱小工具,它使开发人员可能更好地管制和治理 Web 页面的资源缓存、网络申请和响应,从而提供更疾速、更稳固的用户体验。 ...

September 24, 2023 · 3 min · jiezi

关于typescript:最近最火的话题Turbo8-放弃-Typescript

Ruby on Rails 作者 @DHH 的一篇文章引起了前端届的轩然大波,也变成了前端最近最火的话题:Turbo 在最新版本中移除了 Typescript,改为应用 Javascript。 1.具体起因@DHH 解释了做出这个决定的起因: TypeScript just gets in the way of that for me. Not just because it requires an explicit compile step, but because it pollutes the code with type gymnastics that add ever so little joy to my development experience, and quite frequently considerable grief. Things that should be easy become hard, and things that are hard become any. No thanks! ...

September 9, 2023 · 1 min · jiezi

关于typescript:关于-TypeScript-展开运算符在-Angular-应用开发中的应用一例

笔者最近始终在 SAP 中国研究院从事 Angular 开发,我所在的团队负责应用 Angular 开发 SAP Commerce Cloud 这款产品的界面,我的项目代号为 Spartacus. 这是一个开源我的项目,咱们我的项目的 Github 地址如下。 最近我解决了一个 bug,我的代码改变放在这个 Pull Request里。 上面是这个 Pull Request 里蕴含的代码改变,能够看到我应用了 TypeScript 的开展运算符(三个句点): 代码里应用的 stringifyWithContext 办法,接管一个字符串类型的变量和一个 Context 对象作为输出参数,返回一个序列化之后的 JSON 字符串。这个输入的 JSON 字符串能够写入 kibana 等 Trace 工具内。 protected stringifyWithContext( message: string, context: ExpressServerLoggerContext ): string { const logObject = { message, context: this.mapContext(context) }; return isDevMode() ? JSON.stringify(logObject, null, 2) : JSON.stringify(logObject); }而 transform 办法的输入是一个数组。为了把数组里的元素顺次开展成 String 和 Context 对象,故咱们对该数组应用开展运算符。 ...

September 8, 2023 · 2 min · jiezi

关于typescript:TypeScript-设计模式之发布订阅者模式-IKUN-监控小黑子

引言公布订阅者模式是一种很重要的设计模式,在很多软件架构中都作为核心部件组织代码,通常用于:分布式系统、音讯队列、事件处理零碎等、GUI框架等场景下。在前端畛域很多框架也都在实现公布订阅者模式的思维,比方:Redux、Vue、RxJS、EventEmiiter3 等。公布订阅者模式外围构件有三个局部组成、发布者、订阅者、事件和数据。接下来咱们一起揭开这层面纱,彻底了解公布订阅者模式的思路。 小故事话说最近 IKUN 很懊恼,太多小黑子须要发律师函。 小黑子每天都在群里唱跳Rap, 基尼太美~~ 。IKUN 思来想去提交了知识产权申请,当前只能 IKUN 受权的小黑子能力唱:‘基尼太美~’ 其余未受权的监控到违规应用,立刻发送律师函。 因为家里厕纸不太够了,咱们须要帮IKUN实现这个想法,尽早收到律师函补贴家用。 这个场景完满符合公布订阅者模式: 发布者音讯变动发送音讯,订阅者检测变动做出响应。 咱们秉承面向接口编程,先形象一下发布者和订阅者接口。 订阅者 Observer 须要定义一个接收数据的函数 revive,这里的数据蕴含三个局部,type、name、 msg 。 发布者 Publisher 定义保护观察者的列表 subscribers 【依照最小裸露准则,这个局部不应该裸露进去,然而为了大家了解分明,这里咱们抉择裸露进去】、进行注册和登记观察者的两个办法 subscribe/unsubscribe 、最初定义一个播送音讯的函数 publish 。interface Observer { revive(data: { type: string; name: string; msg: string }): void}interface Publisher { subscribers: Observer[] subscribe(op: Observer): void unsubscribe(op: Observer): void publish(data: any): void}咱们先来实现一下订阅者,也就是咱们的 IKUN IKUN 为了防止误伤,建设了一个白名单 whiteList 名单外面的都是受权的人群,比方刘德华要是唱跳rap了也不能起诉,得给华哥打钱感激宣传。定义了一个发送律师函的办法 postPaper。 class IKUN implements Observer { // IKUN 受权的白名单 private whiteList: string[] = [] constructor() { this.whiteList = ["LiuDeHua"] } revive(action: { type: string; name: string; msg: string }): void { const { type, msg, name } = action // 坤坤 次要针对的都是男性的小黑子,女生个别都 比拟温顺就不吓唬了 if (!this.whiteList.includes(name) && type === "male") { // 不在白名单的,产生侵权都给我发律师函 if (msg.includes("基尼太美")) this.postPaper({ name, msg }) } } private postPaper(op: { name: string; msg: string }) { const { name, msg } = op console.log(`${name}你好,我是IKUN, 请进行你的侵权行为:${msg}`) }}该定义咱们的发布者了,也就是在座的各位。这外面咱们比拟盲目,微信外面聊了啥都慷慨的告诉内部的订阅者~ 现实生活中咱们可没这么傻,然而有好心人帮咱们做了这件事~ 咱们身边有个特务,你说的话,打的字,都会被收集起来而后分发给上游,上游会在你的广告上、购物APP上给你精准举荐最近你搜寻或者说过的物品。这个不是偶尔~~~ ...

August 31, 2023 · 2 min · jiezi

关于typescript:笔记写Flink-SQL-Helper时学到的一些姿势

版本日期备注 1.02023.8.23文章首发前阵子向大家分享了我写的插件https://marketplace.visualstudio.com/items?itemName=CamileSin...,最近梳理了我之前的学习相干常识时的笔记,心愿可能帮到对这一块实现感兴趣的同学。 1. TypeScirpt开发VS Code,能够抉择应用了TypeScript or JavaScript。尽管我没学过TypeScript,然而我马上抉择开始学习TypeScript。我想起大学工作室的时候,身边有小伙伴就特地喜爱JavaScript这种写起来很快的语言,然而我却更喜爱Java这种语言。因为有些时候我基本不晓得JavaScript里的一些变量的值到底是什么。 TS在官网是用一句话形容了它TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale。一段时间用下来,发现TS真香,我自身接触的语言也不算少,所以上手很快。而且它的类型零碎十分弱小,让我十分有好感。 这个语言让我比拟印象粗浅的是,它不仅设置了相似Java中Object的Unknown,还有所有类型子类的Never类型,用来代表其永远不会产生,比方: function foo(x: string | number): boolean { if (typeof x === 'string') { return true; } else if (typeof x === 'number') { return false; } // 如果不是一个 never 类型,这会报错: // - 不是所有条件都有返回值 (严格模式下) // - 或者查看到无法访问的代码 // 然而因为 TypeScript 了解 `fail` 函数返回为 `never` 类型 // 它能够让你调用它,因为你可能会在运行时用它来做平安或者具体的查看。 return fail('Unexhaustive');}function fail(message: string): never { throw new Error(message);}另外就是对于范型的反对也很有意思,下面这个函数签名能够写出foo(x: string | number)这样的写法。对于范型反对的更好意味着能够让程序员更好的去做形象。 ...

August 23, 2023 · 2 min · jiezi

关于typescript:7月8日OpenTiny重磅发布

华为开发者大会2023(HDC.Cloud 2023)于7月7日-9日在东莞拉开帷幕,本届大会以“每一个开发者都了不起”为主题,面向寰球开发者,为寰球开发者打造了一个思维碰撞、技术交换、实操竞技的技术殿堂,让开发者全面理解并把握最新的技术动静,为将来技术创新开辟更广大空间。OpenTiny作为企业级前端组件库解决方案,也在本次大会中正式公布啦! 内容介绍:华为云云岭团队前端专家莫春辉作为本次开源我的项目正式公布的演讲嘉宾,给大家解说了OpenTiny作为一个企业级组件库解决方案如何给用户解决痛点和窘境。以下为我的项目解说资料: 通过介绍OpenTiny全景图,深入分析开发者面临的市场痛点,给到用户相应的解决方案。针对企业 toB 业务场景,提供跨端、跨框架、跨版本的组件库和开箱即用的管理系统模板,以及笼罩前端开发全流程的 CLI 工具。通过介绍TinyVue组件库的9年倒退历程的三个阶段,通过1500多个我的项目的验证,3000+用户的应用,充沛验证了TinyVue开源组件库性能平安、稳固且牢靠。TinyVue组件库翻新的架构设计解决了以后业界组件库的痛点,对立API接口反对不同终端展现和交互标准,联合面向业务逻辑的开发范式和无渲染组件的设计模式,反对不同技术栈和Vue不同版本。该架构设计已申请专利。通过Demo介绍了TinyVue反对多主题,展现了流程组件在不同主题下的自适应成果。在PC端浅色主题下失常展现,在大屏端深色主题下主动适配,挪动端展现也有独特的模样。这一翻新架构加重了组件开发者的累赘,升高了组件使用者的老本。通过视频Demo展现了,应用TinyVue的一套代码即可反对PC和挪动端交互界面,包含浏览和创立待办事项。日期框和下拉框在不同设施上有不同的模式。提供两套连贯云服务的TinyPro 模板:基于Vue的中后盾业务模板和基于Angular的云服务控制台模板。反对布局配置、响应式框架、主题定制等,提供20个典型页面,包含工作台、列表页、表单页、服务总览页、服务购买页等。TinyCLI 命令行工具,是一站式的前端工程化工具,提供一系列开发套件和工程插件,可能帮忙用户疾速构建业务。只需一条命令就能实现我的项目的初始化。其中命令行插件次要专一于某些特定的繁多的性能,比方代码公布上线等等。TinyTheme是在线主题配置零碎,满足不同畛域的视觉定制化需要。用户在官网上实时预览操作界面,调配出个性化的组件款式。提供不同的主题,每套主题的按钮色彩、边框不同,有直角和圆角等。 以上就是咱们 OpenTiny 的内容,具体的内容请拜访咱们的官网,咱们的网址是 https://opentiny.design。最初,欢送大家退出咱们 OpenTiny 的开源社区,跟咱们一起共建企业级的前端开发套件,谢谢大家! 7月8日—7月9日 CodeLabs训练营:训练营:本次OpenTiny退出了CodeLabs训练营,旨在疾速帮忙开发者应用TinyVue组件库实现Vue2到Vue3的平滑迁徙,助力实战晋升。两天工夫,共有10位开发者参加并顺利完成我的项目,取得荣誉证书。在这个过程中小陆同学有提到:“通过应用TinyVue我的项目搭建好之后迁徙起来的确不便,只有改几行代码批改下版本号装置,迁徙起来的确挺平滑的”也有开发者提到“通过本次训练营不仅学会了如何将Vue2我的项目降级到Vue3,而且理解了如何应用OpenTiny制作表格和表单页面。” 7月8日 极客挑战赛:挑战赛:7月8日OpenTiny也设置了极客挑战赛环节,开发者在这里一决高下,展示技能和智慧。 本次OpenTiny设置的挑战赛赛题为:开发者通过挑战应用@vue/repl和OpenTiny组件(Button / Select / Checkbox)创立一个 Playground 代码演练场。对于这个赛题,开发者也是兴趣十足。通过讲师的精湛辅导和急躁解说、开发者们高超的理解能力和不凡的实操技巧,最终决出了咱们的最佳技术大侠! 7月8日-7月9日 展台交换:展台状况:当然展台交换的内容也是相当丰盛,咱们前端专家也在一线与开发者们发展深度的沟通与探讨。收集开发者们遇到的痛点及问题,近距离为开发者分享及解答以后前端开发者的困惑。首先OpenTiny作为一套企业级组件库解决方案,次要是为了解决以下问题: 多终端须要屡次开发多技术栈导致能力无奈复用框架大版本升级工作量大低代码零碎不足配置式组件社区管理系统模板匮乏其次在交换过程中,也有很多开发者反馈了本人的疑难,对于这些问题,咱们的展台专家们也是给大家一一作出了解答。例如: 1、 为什么OpenTiny可能实现一套代码同时反对Vue2和Vue3? OpenTiny采纳无渲染Renderlesss设计架构,在这个架构下,TinyVue 组件有对立的 API 接口,开发人员只需写一份代码,组件就能反对不同终端的展示,比方 PC 端和 Mobile 端,而且还反对不同的 UX 交互标准。借助 React 框架的 Hooks API 或者 Vue 框架的 Composition API 能够实现组件的外围逻辑代码与前端框架解耦,甚至实现一套组件库代码,同时反对 Vue 的不同版本。 2、 如何让本人的我的项目从原来的组件库迁徙到OpenTiny的组件库上来? 当一个我的项目想要迁徙到OpenTiny组件库时,能够采纳渐进式迁徙的形式,任何我的项目的切换都须要肯定的老本。但OpenTiny组件库我的项目从Vue2迁徙到Vue3的时候就能做到一个简略平滑的迁徙,并且随着前端技术的倒退OpenTiny也可能一直的适应将来,面向未来。例如除了以后利用比拟宽泛的三大支流框架,还有Svelte等新兴框架也受到大家的注目,后续为了满足某些业务需要须要进行我的项目革新,也能够进行一个平滑的迁徙。如果想从原有的Vue2的我的项目切换应用OpenTiny组件库我的项目,能够通过先放弃本人原有搭建的页面个性及成果不变的状况下,进行单个组件的切换。当我的项目工程实现整体切换之后,再通过批改版本号就能够做到简略平滑迁徙。 3、 一个我的项目用了OpenTiny组件库之后,从原来的老版本更新到新版本是否会影响老个性的应用? 当开发者之前用本人的组件库切换到OpenTiny组件库之后进行版本升级是否会影响之前旧版本的个性。这个问题须要具体问题具体分析,依据开发者的开发场景及业务场景,但个别状况下,为了保障业务的连续性,是不会对性能个性产生较大的影响。如果是进行大版本升级,可能会呈现大量影响。 4、 开发者如何可能疾速的上手应用OpenTiny开源组件库我的项目? 对于组件库上手,OpenTiny也是在一直帮忙开发者升高学习老本,首先能够通过进到OpenTiny的官网查看帮忙文档进行学习,其次咱们会定期进行直播分享,帮忙开发者疾速上手应用,同时,咱们也会通过文章和视频的模式帮忙开发者了解我的项目内容应用我的项目,接着咱们还会定期参加或发展开发者流动及交换大会,与开发者近距离沟通,理解开发者痛点和窘境,帮忙开发者解决问题,最初,咱们还有社群答疑服务,感兴趣的开发者能够退出咱们的技术交换群,群里有各个技术工程师会给大家进行答疑。 5、 OpenTiny组件库与竞品组件库的劣势在于哪里? 对于前端开发者而言,如果须要搭建一个新我的项目,势必会依据本人的业务场景和业务需要去进行技术选型。就目前市面上的组件库来说,大家也各有劣势。但目前存在一个问题在于业界的前端 UI 组件库,个别按其前端框架 Angular、React 和 Vue 的不同来分类,比方 React 组件库,Angular 组件库、Vue 组件库,也能够按面向的终端,比方 PC、Mobile 等不同来分类,比方 PC 组件库、Mobile 组件库、小程序组件库等。两种分类穿插后,又可分为 React PC 组件库、React Mobile 组件库、Angular PC 组件库、Angular Mobile 组件库、Vue PC 组件库、Vue Mobile 组件库等。另外,因为前端框架Angular、React 和 Vue 的大版本不能向下兼容,导致不同版本对应不同的组件库。以Vue 为例,Vue 2.0 和 Vue 3.0 版本不能兼容,因而 Vue 2.0 的 UI 组件库跟 Vue 3.0 的UI 组件库代码是不同的,即同一个技术栈也有不同版本的 UI 组件库。咱们将下面不同分类的 UI 组件库汇总在一张图里,而后站在组件库使用者的角度上看,如果要开发一个利用,那么先要从以下组件库中筛选一个,而后再学习和把握该组件库,可见以后多端多技术栈的组件库给使用者带来惨重的学习累赘。那OpenTiny能够如何解决这个问题呢?OpenTiny采纳Renderless无渲染的设计架构,通过组件逻辑、组件款式、组件模板拆散的设计理念使得代码更易于了解和保护: ...

July 13, 2023 · 1 min · jiezi

关于typescript:TypeScript-中装饰器-decorator-的知识

TypeScript 中装璜器 decorator 的常识本文次要介绍对于 TS 中装璜器 Decorator 的相干内容以及应用场景;介绍如何实现一个简略DI依赖注入例子; 为什么须要装璜器?新技术的呈现都是在解决问题,TypeScript 中的装璜器理论是实现了 ECMAScript 对于装璜器的提案。目标是解决以下问题: 元数据注入(reflect-metadata): 能够为类、办法或属性上增加元数据,这些元数据在运行时被动静拜访和应用【想想 DI,依赖注入的场景,大部分都是靠装璜器来进行依赖关系的传递】。性能扩大:能够在不批改原始类的定义状况下,对性能进行扩大和批改。比方:增加埋点、解决日志记录、权限校验等。这个性能和装璜器设计模式性能统一。设计模式的应用能让咱们的代码设计更加优雅(更容易了解,健壮性也更好)。代码重用:一个装璜器函数能够在多个类、办法、属性上进行重复使用。装璜器设计模式很难这点(要做到就很难,抽象层次很高,把装璜器类变成公交车,谁都能用才行)。装璜器的应用以及分类咱们把装璜器函数叫做装璜器(实际上就是一个函数),把利用@decoratorFunc 的形式叫做装璜器利用。来个简略的demo: // 应用 webDecorator 润饰器来润饰 User 类@webDecoratorexport class User { private name: string; constructor(name: string) { this.name = name; }}// 定义一个类润饰器, 只须要定义一个参数function webDecorator<T extends { new (...args: any[]): {} }>( TargetConstructor:T) { return class extends TargetConstructor { private registerOrigin = "WEB-SITE"; };}// 定义一个类润饰器function appDecorator<T extends { new (...args: any[]): {} }>( TargetConstructor:T) { return class extends TargetConstructor { private registerOrigin = "APP"; };}import { User } from './user.ts';function testUserRegister() { const user = new User('Tony'); console.log(user); // {"name":"Tony","registerOrigin":"WEB-SITE"} }testUserRegister();输入的后果: ...

July 12, 2023 · 3 min · jiezi

关于typescript:TinyNG开源Angular组件库助力Web应用快速开发

TinyNG 是基于 Angular + TypeScript 的前端 UI 组件库,旨在为开发人员带来更高效的开发体验和对立的视觉交互格调。TinyNG 曾经在华为外部应用四年,撑持数百个企业产品,领有弱小的稳定性和可靠性。当初,咱们将TinyNG开源,让更多的开发人员可能体验它所带来的惊喜和效率晋升。如果您正在寻找一款 Angular UI组件库,咱们真诚地邀请您来尝试应用TinyNG,并享受它所带来的卓越体验和有限可能。同时,咱们也期待您的反馈和倡议,让 TinyNG 变得更加欠缺和易用。咱们置信,开源后的 TinyNG 将会失去更多的重视和关注,并且会有更多的人参加其中,为它的倒退和壮大做出更大的奉献。欢送体验TinyNG ! 组件多TinyNG 蕴含了丰盛的用户界面组件,十分易于集成和应用。目前,TinyNG 曾经开源了 70 多个根底组件,并将逐渐开源 100 多个组件,涵盖了企业级全场景,能够满足各种不同畛域的需要。每个组件都提供了具体的性能介绍和示例,初学者也能够轻松地了解和应用。此外,咱们致力于不断完善和改良组件,以满足开发者日益增长的需要。 主题灵便TinyNG 能够依据业务需要疾速切换主题格调,非常灵活不便;也能够轻松打造独具特色的主题格调,进步开发效率。 内置主题TinyNG 独创零配置应用默认主题,无需手动写入加载 theme-default.css 的代码,从而简化了应用流程。此外,TinyNG还为用户提供了内置的四套主题,能够依据理论设计需要进行自在切换。这些主题蕴含丰盛的色彩和款式,满足了各种不同场景下的设计要求,使页面设计更加美观大方。theme-blue.css theme-green.css theme-purple.css theme-red.css 自定义主题业内传统的组件库个别采纳 Less/Sass 作为主题,须要编译后能力应用。这不仅减少了开发者的工作量,还侵入了业务我的项目的编译配置,给我的项目带来了不必要的麻烦。TinyNG采纳了全新的形式,应用 CSS Var 自定义主题,免编译主题,让主题定制更加便捷;同时也反对 JavaScript 在运行时更改变量。CSS Var 主题不仅简略易用,还能够让开发者更加专一于业务逻辑的实现。另外,TinyNG 还反对在 JavaScript 代码中指定一个品牌色,来疾速创立一套自定义主题,这样用户不须要本人编写简单的主题款式,最轻松实现主题的个性化定制。 主题配置平台TinyNG 领有一款弱小的主题配置平台,能够让主题定制变得更加简略和直观。通过所见即所得的形式,用户能够轻松编译主题色、场风景、组件色(色彩、字体、边框、暗影)等,实现个性化的主题定制,让我的项目更加好看和独特。除此之外,主题配置平台还提供了一键公布到 npmjs.org 的性能,让用户能够更加不便地分享和应用本人定制的主题。 微组件TinyNG 的微组件具备单组件独立版本号治理的特点,每个组件都能够独自装置或降级,这使得组件的治理更加灵便和不便。如果您应用了多个组件,只须要降级其中一个,就可能免去全量测试,进步开发效率和稳定性。 性能超高TinyNG 的组件库波及到海量数据的组件(如 Select、Tree、Table 等),都曾经内置虚构滚动性能,能够放弃丝滑稳固的用户体验。这一个性极大地晋升了组件的性能和响应速度,使得高负载的应用程序也可能轻松运行。虚构滚动是一种优化技术,它只在屏幕上显示以后可见的局部数据,而不是将所有数据一次性加载到页面中。这样能够防止大量的 DOM 操作,缩小页面的渲染工夫,从而进步了页面的性能和响应速度。除此之外,TinyNG 的组件库还反对高性能 OnPush 模式,这意味着当组件的输出属性发生变化时,组件只会在须要更新时才从新渲染,从而防止了不必要的 DOM 操作,进一步提高了组件库的性能和响应速度。 企业级平安企业级平安是咱们始终以来的外围关注点,咱们致力于保障客户的信息安全,所有接口杜绝XSS攻打,让您百分之百释怀。咱们的平安技术团队不断更新降级,采纳最先进的技术手段,为您的数据保驾护航。 国际化在国际化方面,TinyNG 不仅提供了五种罕用语言,还反对自定义新语言,以满足不同客户的需要。TinyNG 能够适应各种语言环境,让您的用户能够用本人相熟的语言应用您的产品,进步用户体验和满意度。 开箱即用TinyNG 采纳开箱即用的设计,让您可能立刻开始应用。详尽而易于了解的文档示例,让您可能轻松上手,疾速把握产品的应用形式。TinyNG 提供了 CLI 脚手架工具,只需一键我的项目初始化,让您能够疾速搭建我的项目。 同步降级同时,咱们与 Angular 放弃同步降级,TinyNG 反对所有 Angular 沉闷版。 ...

July 12, 2023 · 1 min · jiezi

关于typescript:现代TypeScript高级教程序言

点击在线浏览,体验更好链接古代JavaScript高级小册链接深入浅出Dart链接古代TypeScript高级小册链接序言可能是市面上比拟好的Typescript高级教程,适宜有肯定Typescipt根底的同学学习随着TypeScript的日益遍及,它曾经成为古代Web开发的重要工具。然而,只管TypeScript初学者能够轻松上手并开始编写代码,但深刻了解TypeScript的弱小性能和高级个性却是一项更具挑战性的工作。"古代TypeScript高级教程"就是为了帮忙您解开TypeScript的高级机密而编写的。 在这本教程中,咱们将深入探讨TypeScript的简单个性,包含装璜器、泛型、高级类型以及元数据反射等。咱们不仅会具体解释这些概念,还会展现如何在理论我的项目中使用这些高级个性,提供丰盛的代码示例和最佳实际,帮忙您更好地了解这些简单的概念。 这本教程适宜有肯定TypeScript根底,心愿进一步晋升技能的开发者。每一章都设计得既能够独立浏览,也能够作为整个教程的一部分。咱们坚信,无论您是心愿对TypeScript有更深刻的理解,还是心愿晋升在大型项目中应用TypeScript的技巧,本教程都将为您提供极大的帮忙。 书籍目录根底 概述类型函数接口和类枚举和泛型命名空间和模块进阶 类型零碎高级类型类型推断类型守卫泛型和类型体操结构化类型协变和逆变扩大类型定义装璜器解读TSConfig实战 fetch对于我笔名linwu,一枚前端开发工程师,曾入职腾讯等多家出名互联网公司,前面我会继续分享精品课程,欢送继续关注

July 11, 2023 · 1 min · jiezi

关于typescript:IntersectionObserver-实现加载更多组件

import { useEffect, useRef } from 'react';import { Spin } from 'antd';import type { FsFC } from './types';import './index.less';type LoadMoreProps = { root?: Element | null; // 跟哪个元素重叠不传默认则是 整个浏览器窗口,个别是父元素 isLoading: boolean; // 用来判断如果 没有在申请列表才回执行 more: () => void;};const LoadMore: FsFC<LoadMoreProps> = ({ root = null, isLoading, more }) => { const loadMoreRef = useRef(null); /** 建设加载更多观察者 */ const loadMoreOb = () => { if (!loadMoreRef.current) { return; } const ob = new IntersectionObserver( (entries) => { const [entry] = entries; // 有重叠,并且没有在申请 if (entry.isIntersecting && !isLoading) { more(); } }, { root, threshold: 1, }, ); ob.observe(loadMoreRef.current); }; useEffect(() => { loadMoreOb(); }, []); return ( <div className="load-more" ref={loadMoreRef}> <Spin /> </div> );};export default LoadMore;本文参加了 SegmentFault 思否写作挑战「摸索编码世界之旅 - 记我的第一份编程工作」,欢送正在浏览的你也退出。 ...

July 11, 2023 · 1 min · jiezi

关于typescript:大厂前端架构实战之modal模态对话框管理

前言 这是我新开的一个对于前端常识的模块,次要解说日常开发中罕用的前端技巧。此模块解说的常识都是能大幅晋升前端性能的奇技淫巧,供大家日常交换,同时也心愿大家不吝赐教,指出自己的有余。 本文应用的技术栈: vue3 + typescript + pinia + element-plus 背景 modal模态框又称之为弹出框、对话框,是前端日常开发最为频繁的组件之一。然而在日常开发过程中常常遇到一些性能、或者写法繁琐的问题。上面是我举例的一些常见问题: 1.modal框塞入以后页面会导致整个组件更新,影响性能 <template> <div class="about"> <el-button class="todo-list--add-btn" @click="showModal"> 增加工作 </el-button> <ul> <li class="todo-list--item-box" v-for="(item, index) in list" :key="item.title"> <div>{{ item.title }}</div> <div class="todo-list--add-btn" @click="handleDelToDoList(index)"> 删除 </div> </li> </ul>// 此种形式更新会带动组件的更新 <el-dialog :model-value="show" title="增加工作" width="30%"> <el-input v-model="todoListAddInput" placeholder="请输出" /> <template #footer> <span class="dialog-footer"> <el-button @click="modalStore.hideModal(ModalType.TODO_LIST)"> 勾销 </el-button> <el-button type="primary" @click="handleAddToDolist"> 提交 </el-button> </span> </template> </el-dialog> </div></template>许多后盾利用的modal框体量都是十分宏大的,一些流程modal框动辄成千盈百行代码很失常,如果在首次加载势必影响首次加载耗时vue应用teleport,react应用createPortal把modal框放到根节点是一些公司的次要优化伎俩,然而没有全局注册调用事件,导致modal框管理混乱,前端开发人员开发的modal框组件遍布我的项目各个文件夹上面我就针对以上问题做出解决方案 构造示意图:   全局注册modal框 应用pinia进行modal的全局治理不仅能使各个组件很不便的调用model框,还能对立modal入口,方便管理。 // 全局modal框惟一身份标识export enum ModalType { TODO_LIST,}// modal框所须要的参数注册接口export interface ModalDataType { [ModalType.TODO_LIST]: { onSubmit: (value: string) => void; };}// modal框实例对象接口interface ModalInstance<T extends ModalType> { type: T; // modal框标识 component: any; // modal框vue组件 data?: ModalDataType[T]; // modal框传值 onEnter?: (data: ModalDataType[T]) => void; // 生命周期钩子,在modal框显示之后调用 onExit?: (data: ModalDataType[T]) => void; // 生命周期钩子,在modal框显暗藏之后调用}type ModalListItem = { [key in ModalType]: ModalInstance<ModalType> };通过以上代码咱们就设计好了全局modal框的所用到的属性。通过对这些属性的使用,咱们能够很不便的建设起一个全局数据中心,这一步解决了modal框的治理问题(具体代码详见文章结尾GitHub地址): ...

July 10, 2023 · 2 min · jiezi

关于typescript:TypeScript-infer-关键字让类型体操更灵活

title: TypeScript infer 关键字author: 剑大瑞category: TypeScripttag: typescriptdate: 2023-07-01 12:46:31明天咱们介绍一个 TypeScript 十分弱小的关键字 infer。 最近在练习 type-challenges。尽管在先前的博文中有介绍过 infer 关键字的应用,然而直到我在 type-challenges 中应用的时候,才领会到这个关键字的弱小之处。这个的感觉有多弱小,打个比喻: 好比你在做体操比赛的时候,人曾经飞到半空了,然而不晓得接下来该做什么动作?该用头着地还是用脚着地?这个时候你要是晓得 infer 关键字怎么用,那么它会给你答案!就是这么神奇! 接下来说闲事。首先 infer 关键字必须联合 TypeScript 中的条件类型进行操作,而后联合条件分支进行类型推导。 一个简略示例: type ArrayElement<T extends any[]> = T extends (infer Element)[] ? Element : neverArrayElement 类型能够承受一个数组类型,而后获取数组的元素类型。比方: type NumList = number[]type StrList = string[]type NumEle = ArrayElement<NumList> // numbertype StrEle = ArrayElement<StrList> // string就像下面这么操作就能够获取到数组的元素类型。 通过下面的示例,让咱们梳理下,infer 关键字做了什么? infer 这个单词本意是 推断、推论 的意思。当在条件类型中应用 infer 关键字的时候,显示的申明了一个新的类型变量 Element而 ts 联合条件操作将推断出泛型的元素类型赋值给了 Element整个过程就是这么简略。 ...

July 1, 2023 · 3 min · jiezi

关于typescript:React18-FC-props没有children类型问题

import type { FC, PropsWithChildren } from 'react';export type FsFC<T = any> = FC<PropsWithChildren<T>>;

June 29, 2023 · 1 min · jiezi

关于typescript:typescript的必要性及使用-京东云技术团队

1 前言作为一个前端语言,Javascript从最后只是用来写页面,到现在的挪动终端、后端服务、神经网络等等,它变得简直无处不在。如此广大的应用领域,对语言的安全性、健壮性以及可维护性都有了更高的要求。只管ECMAScript规范在近几年有了长足的提高,然而在类型查看方面仍然毫无建树。在这种状况下TypeScript应运而生。 2 为什么要应用TypeScript在JavaScript的开发过程中,置信常常会遇到以下这种场景: 场景一: 你须要调用一个他人开发的函数 function funcName(paramA,paramB,paramC,paramD){…},然而很可怜,这个家伙没有留下任何正文,为了弄清楚参数的类型,你不得不硬着头皮去读外面的逻辑;场景二: 为了保障代码的健壮性,你很负责任的对函数的每个输出参数进行了各种假如,导致函数内一多半代码都是对参数(类型、个数等)的判断逻辑;场景三: 老板很看好你,让你保护一个重要的底层类库,你殚精竭虑优化了一个参数类型,在提交代码前,不晓得有多少中央调用,你是否感到脊背发凉?等等…以上状况归纳底,是因为 JavaScript 是一门动静弱类型语言,对变量的类型十分宽容,而且不会在这些变量和它们的调用者间建设结构化的契约。如果你长期在没有类型束缚的环境下开发,就会造成“类型思维”的缺失,养成不良的编程习惯,这也是做前端开发的短板之一,因而应用TypeScript对于前端开发者而言是迫切并且必要的。 应用 TypeScript 还能带来其余益处。比方,Visual Studio Code 具备弱小的主动补全、导航和重构性能,这使得接口定义能够间接代替文档,同时也进步了开发效率,升高了保护老本。更重要的是,TypeScript 能够帮忙团队重塑“类型思维”,使前端开发者从代码的编写者变质为代码的设计者。 如果说 JavaScript 是一匹野马,那么 TypeScript 就是解放这匹野马的缰绳。作为骑士的你,天然能够张开双臂,放飞自我,但如果不是技能超群,恐怕会摔得很惨。然而如果抓住了缰绳,你即可闲庭信步,亦可策马扬鞭。这就是 TypeScript 的价值,它会让你在前端开发之路上走得更稳,走得更远。 3 什么是TypeScript什么是 TypeScript呢?依据官网的定义,它是领有类型零碎的 JavaScript 的超集,能够编译成纯JavaScript。在这里须要留神三点: 类型查看,TypeScript会在编译阶段进行严格的动态类型查看,这意味着你在代码编写阶段就能发现一些谬误,而不用带到线上运行时能力发现;语言扩大:TypeScript 会包含来自 ECMAScript 6 和将来提案中的个性,比方异步操作和装璜器,也会从其余语言借鉴某些个性,比方接口和抽象类;工具属性:TypeScript 可能编译成规范的 JavaScript,能够在任何浏览器、操作系统上运行,无需任何运行时的额定开销,从这个角度上讲,TypeScript 更像是一个工具,而不是一门独立的语言4 TypeScript根底应用4.1 根底类型Ts蕴含类型如下: 数字类型(number):用来标识双精度64为浮点值,蕴含整数、浮点数等,没有独自的整型、浮点型;字符串(string):一个字符系列,应用单引号(‘)或双引号(“)来示意字符串类型。反引号(`)来定义多行文本和内嵌表达式;布尔(boolean): 值只有true和false;数组: 无关键字,申明变量:let arr: number[] = [1, 3] let arr:Array<number> = [1,2]5.元组: 无关键字,元组类型用来示意已知元素个数和类型的数组,每个元素的类型不用雷同,然而对应地位的类型须要雷同; let x: [string, number];x = ['Runoob', 1]; // 运行失常x = [1, 'Runoob']; // 报错console.log(x[0]); // 输入 Runoobx.push(33)console.log(x[2]) // 报错// 留神x能够持续push多个字段,然而无法访问6.枚举(enum): 枚举类型用于定义类型汇合 ...

June 29, 2023 · 2 min · jiezi

关于typescript:TypeScript又出新关键字了

TypeScript 5.2将引入一个新的关键字:using。当它来到作用域时,你能够用Symbol.dispose函数来处理任何货色。 { const getResource = () => { return { [Symbol.dispose]: () => { console.log('Hooray!') } } } using resource = getResource();} // 'Hooray!' logged to console这是基于TC39提议,该提议最近达到了第三阶段,表明它行将进入JavaScript。 using将对管理文件句柄、数据库连贯等资源十分有用。 Symbol.disposeSymbol.dispose是JavaScript中一个新的全局symbol。任何具备调配给Symbol.dispose函数的货色都将被视为"资源":也就是具备特定生命周期的对象。并且该资源能够应用using关键字。 const resource = { [Symbol.dispose]: () => { console.log("Hooray!"); },};await using你也能够应用Symbol.asyncDispose和await来解决那些须要异步处理的资源。 const getResource = () => ({ [Symbol.asyncDispose]: async () => { await someAsyncFunc(); },});{ await using resource = getResource();}这将在持续之前期待Symbol.asyncDispose函数。 这对数据库连贯等资源来说很有用,你要确保在程序持续前敞开连贯。 应用案例文件句柄通过节点中的文件处理程序拜访文件系统,应用using可能会容易得多。 不应用using: import { open } from "node:fs/promises";let filehandle;try { filehandle = await open("thefile.txt", "r");} finally { await filehandle?.close();}应用using: ...

June 27, 2023 · 1 min · jiezi

关于typescript:使用依赖注入框架管理多实例服务以-InversifyJS-为例

在大型项目的治理中,管制反转的思维是十分重要的。它能够帮忙咱们解耦代码,进步代码的可维护性。同时防止了不必要的反复实例化,升高内存透露的可能性。 而在 JS/TS 技术栈中,咱们通常会应用依赖注入框架来帮忙咱们治理服务。这其中最佳的抉择当然是 Angular 这种大而全的大型工程开发框架。而对于应用了其余 UI 框架的我的项目来说,咱们同样能够额定引入一个轻量化的依赖注入框架。而 InversifyJS 就是其中的佼佼者。咱们能够通过应用它,来见微知著地理解依赖注入的原理与设计哲学。 但最近在应用 Inversify 进行我的项目重构时,遇到了一个问题:家喻户晓依赖注入框架天生适宜治理单例服务。它的设计哲学是 Everything as Service。然而在某些场景下,单例模式并不能解决所有问题,咱们同样须要进行多实例的治理。那么咱们该如何解决这个问题呢? 这并不是 Inversify 框架的问题,而其实是一个依赖注入框架下常见的设计纳闷,然而网上对此的解析材料却很少。 我看了很多应用了 InversifyJS 的我的项目,他们对此的形式就是间接在须要处实例化,不将其注册到容器中。这实际上是没有真正了解到依赖注入框架的内核。这样做的益处是简略,然而有很多弊病。因为咱们无奈在容器中对立治理这些实例,那么这些服务的生命周期将不受管制,在 dispose 时无奈在容器中对立销毁这些实例。与不引入依赖注入框架一样,这样同样会带来内存透露的可能性。 那么该如何正确地解决这种状况呢? 结构器注入一个最简便的革新形式是,咱们将类的构造函数绑定到容器中。须要的时候从容器中获取类的结构器,再进行实例化。这样咱们就能够在容器中对立治理这些实例了。 // 将 InstanceClass 的构造函数绑定到容器中container .bind<interfaces.Newable<InstanceClass>>("Newable<InstanceClass>") .toConstructor<InstanceClass>(InstanceClass);// 获取结构器public constructor( @inject("Newable<InstanceClass>") InstanceClass: Newable<InstanceClass>,) { this.instance1 = new InstanceClass(); this.instance2 = new InstanceClass();}实例会追随类的生命周期而存在,且该类能纳入容器中进行治理。然而这样做,实际上依然无奈在容器中对立治理这些实例的生命周期。如果咱们须要在 dispose 时销毁这些实例,那么咱们须要在类中手动实现 dispose 办法,并在 dispose 时手动销毁这些实例。 这样革新的益处是简略,然而很多时候并不是一个最优解,因为咱们心愿该实例自身能在注入框架的治理下,防止咱们去手动的管制与销毁。 工厂注入依赖注入框架天生不太好治理多实例的服务,然而如果利用工厂模式的设计思维,将这些服务的实例化过程封装到工厂中,而这样的工厂类肯定是单例的。那么咱们就能够通过治理工厂类来治理这些多实例服务的生命周期了。 在须要多实例服务实例化时,咱们不间接 import 类进行实例化,而是通过 import 工厂类来获取实例。这样咱们就能够在工厂中管制多实例服务的生命周期了。 在 InversifyJS 中,提供了工厂注入的办法: // 设置工厂函数const instanceFactory = () => { return context.container.get<InstanceClass>("Instance");};// 工厂创立器,这里设置高阶函数的目标是将 context 传递给工厂函数,不便获取容器const instanceFactoryCreator = (context: interfaces.Context) => { return instanceFactory;};// 绑定工厂container .bind<interfaces.Factory<InstanceClass>>("Factory<InstanceClass>") .toFactory<InstanceClass>(instanceFactoryCreator);// 获取结构器public constructor( @inject("Factory<InstanceClass>") private instanceFactory: () => InstanceClass,) { this.instance1 = this.instanceFactory(); this.instance2 = this.instanceFactory();}这样的实现十分优雅,也是 Inversify 举荐的多实例治理形式。 ...

June 27, 2023 · 2 min · jiezi

关于typescript:16个小的UI设计规则却能产生巨大的影响

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。快来收费体验ChatGpt plus版本的,咱们出的钱 体验地址:https://chat.waixingyun.cn 能够退出网站底部技术群,一起找bug,另外新版作图神器已上线 https://cube.waixingyun.cn/home 这篇文章介绍了一些对于用户界面设计的实用技巧,帮忙设计师们更好地设计直观、易用、好看的界面。首先,通过利用空间将相干元素进行分组,能够更好地组织和结构化界面,晋升用户了解和记忆的成果。其次,放弃一致性是要害,确保类似的元素在外观和性能上统一,进步可用性和缩小谬误。另外,类似的元素应具备类似的性能,防止产生混同。清晰的视觉档次有助于疾速扫描信息和凸显重要元素。同时,缩小不必要的款式和信息能够简化界面,升高认知负荷。应用色彩时应有目的地应用,防止纯正为装璜而应用,特地是须要留神色盲用户的可拜访性。抉择繁多无衬线字体,并应用具备较高小写字母和适当行高的字体,晋升可读性。同时,防止适度应用大写字母,因为它们难以浏览。此外,防止应用纯彩色文本,采纳较暗的灰色能够进步可读性并缩小眼部疲劳。最初,将文本左对齐,并确保注释文本具备适当的行高,加强可读性。 这些技巧的指标是通过应用逻辑和主观的规定,而非主观的意见,来简化UI设计过程,使其更加高效、直观和易用。 总的来说,这篇文章提供了一些贵重的UI设计技巧,对于心愿晋升设计技能和发明出杰出用户体验的设计师们来说,是一份有价值的参考资料。 ~~ 上面是注释 用户界面设计是一项艰难的工作。面对泛滥的布局、间距、排版和色彩选项,做出设计决策可能会令人感到压力山大。当你再加上可用性、可拜访性和心理学因素,工作难度进一步减少。 侥幸的是,UI设计并非总是如此艰巨。在近二十年的产品设计工作中,我意识到我大部分的视觉和交互设计决策都是受一套逻辑规定的领导。这不是艺术的激情或神奇的直觉,只是简略的规定。 领有一套逻辑规定能够帮忙你高效地做出理智的设计决策。没有逻辑体系,你只能凭直觉随便调整,直到它看起来好看。 我酷爱规定和逻辑,但设计决策很少是非黑即白的。与其将以下的倡议视为必须恪守的严格规定,不如把它们看作是在大多数状况下都能见效的有用指南。 学习最快的形式就是入手实际,所以让咱们开始吧。 应用逻辑规定来修复这个例子以下两个设计是短期房产租赁利用的房产详情页面。第一个是原始设计。第二个是利用了一些逻辑规定或指南后的后果。 即便没有太多的视觉或交互设计教训,你可能也会留神到原始设计感觉凌乱、简单,并且难以使用。这是因为它蕴含了许多可能对可用性形成危险的问题设计细节。兴许你曾经发现了其中的一些? 咱们应用以下的逻辑规定或指南,一次解决原始设计的一个问题: 应用空间来组合相干元素放弃一致性确保看起来类似的元素性能类似创立清晰的视觉档次移除不必要的款式有目的地应用色彩确保界面元素的对比度为3:1确保文字的对比度为4.5:1不要仅依赖色彩作为指示器应用繁多的无衬线字体应用小写字母较高的字体限度大写字母的应用只应用惯例和粗体字重防止应用纯彩色的文字左对齐文字注释行间距至多为1.51. 应用空间将相干元素分组将信息合成为相干元素的小组能够帮忙结构化和组织界面,这让人们更快、更容易地了解和记忆。 你能够通过以下办法将相干元素分组: 将相干元素放在同一个容器中将相干元素空间上凑近使相干元素看起来类似在一条间断线上对齐相干元素应用容器是将界面元素分组的最强烈的视觉提醒,但它可能会减少不必要的凌乱。寻找应用其余分组办法的机会,它们通常更加奥妙,能够帮忙简化设计。 特地是应用空间,是将相干元素分组的一种十分无效且简略的形式。你还能够联合分组办法,以更分明地展现分组。 在咱们的例子中,内容之间不足空间使得设计看起来凌乱且难以了解。减少间距有助于清晰地将内容分组,使其更有组织性,更容易了解。 2.放弃一致性在UI设计中,一致性意味着类似的元素看起来并且工作形式类似。无论是在你的产品外部,还是与其余曾经建设良好的产品相比,都应该如此。这种可预感的性能性能进步可用性并缩小谬误,因为人们不须要一直地学习事物的工作原理。 在咱们的例子中,图标的款式并不统一,有些是填充的,有些则不是。这可能会使一些人感到困惑,因为填充的图标通常示意一个元素被选中了。用2pt的笔触宽度和圆角勾画出所有图标能够进步一致性,并赋予每个图标类似的视觉分量。 图标上也增加了文字标签,以帮忙确保人们能够了解它们的含意,特地是那些应用屏幕阅读器的人(屏幕阅读器是一种用语音或盲文形容界面的软件,供视力障碍者应用)。 3.确保看起来类似的元素性能类似如果元素看起来类似,人们会冀望它们以类似的形式工作。所以,请尽量确保你对具备雷同性能的元素应用统一的视觉解决。反之,尝试确保具备不同性能的元素看起来不同。 在咱们的例子中,图标容器的视觉款式与“立刻预订”按钮类似。这使它们看起来像是能够交互的,只管它们并非如此。移除图标的蓝色和按钮款式有助于防止它们被误认为是能够交互的元素。 4.创立清晰的视觉档次界面中的所有信息并非都有雷同的重要性。你的指标应该是依照重要性的程序展现信息,使更重要的元素显得更突出。 清晰的重要性程序,或者说视觉档次,有助于人们疾速扫描信息并关注感兴趣的区域。它也通过发明一种秩序感来晋升美感。你能够应用大小、色彩、对比度、间距、地位和深度的变动来创立清晰的视觉档次。 以下是一个没有明确视觉档次的网站英雄横幅示例,前面是一个按重要性程序明确展现元素的示例。 一个疾速简便的检测你的视觉档次是否清晰的办法是应用"含糊测试"。只需眯起你的眼睛看你的设计,或者你能够离屏幕远一些,或含糊你的设计。你应该依然可能辨认出哪些是最重要的元素,并且可能辨认出界面的用处。 让咱们把含糊测试利用到咱们的例子上。咱们能够看到有多个元素的突出水平相当,竞相吸引注意力。与此同时,左下角的次要动作一点也不突出。 通常状况下,次要动作应该是界面上最突出的元素。给它一个高对比度的背景色彩和粗体字重能够帮忙实现这一点。这也修复了一个对于低对比度按钮的可拜访性问题,咱们稍后会深入研究这个问题。 将含糊测试利用到更新的设计上,次要动作显然是最突出的元素。 视觉档次当初更清晰了,但还有改良的空间。例如,与其重要性相比,注释文本块的突出水平依然过高。咱们稍后将学习一些疾速的排版指南,这将有助于修改视觉档次。 5. 移除不必要的款式不必要的信息和视觉款式可能会扩散注意力,减少认知负荷(应用界面所需的脑力)。防止不必要的线条、色彩、背景和动画,能够创立一个更简洁、更聚焦的界面。 在咱们的例子中,图片四周的红色空间和边框减少了不必要的视觉复杂性。它们并不需要传播信息或分组元素,所以咱们能够平安地移除它们,以简化设计。 6.有目的地应用色彩有节制且有目的地应用色彩。尽量避免纯正为了装璜而应用色彩,因为它可能会引起混同和分心。从黑白开始,当它能传播意义时再引入色彩。 一个简略无效的办法是将品牌色彩利用于文本链接和按钮等交互元素。这有助于让人们理解哪些是可交互的,哪些不是。尽量避免在非交互元素上应用品牌色彩。 你不须要给所有交互元素增加色彩,因为有些元素曾经有了示意它们可交互的视觉线索。例如,上面示例中的卡片,无论有无蓝色链接,都给人一种能够交互的感觉。 在咱们的原始示例中,蓝色的题目可能看起来很好,但它使文本看起来像是能够交互的。为了防止混同,咱们将非交互性题目的蓝色移除。 咱们还从其余非交互元素,如星级评估中移除蓝色。这样就更容易看出什么是可交互的,什么不是。 7.确保界面元素有3:1的对比度比例对比度是两种色彩之间的感知亮度差别的掂量。它以从1:1到21:1的比率来示意。例如,彩色背景上的彩色文本有最低的1:1对比度比例,而红色背景上的彩色文本有最高的21:1比例。有许多在线工具能够帮忙你测量不同色彩之间的对比度比例。 为了确保视力受损的人能清晰地看到界面细节,应至多满足网页内容可拜访性指南(WCAG)2.1 AA级色调对比度要求。这意味着用户界面元素,如表单字段和按钮,须要有至多3:1的对比度比例。 在咱们的例子中,箭头图标的对比度太低。在图标上加上暗影,并在图像的上方第三局部上增加突变叠加层,能够使图标取得足够的3:1对比度,无论它处于什么样的图像上。 ...

June 25, 2023 · 1 min · jiezi

关于typescript:联合类型Union-Types交叉类型Intersection-Types有什么区别

联结类型(Union Types)和穿插类型(Intersection Types)是 TypeScript 中的两种类型操作符,它们具备不同的行为和用处。 联结类型(Union Types): 用竖线 | 分隔多个类型,示意一个值能够是其中的任意一种类型之一。联结类型实用于变量或参数能够承受多种类型的状况。联结类型应用的是"或"的逻辑关系。例如,number | string 示意一个值能够是数字类型或字符串类型。let value: number | string;value = 10; // 非法value = "hello"; // 非法value = true; // 不非法,因为布尔类型不在联结类型中穿插类型(Intersection Types): 应用 & 符号将多个类型组合在一起,示意一个值必须同时具备所有这些类型的特色。穿插类型实用于须要将多个类型的属性和办法合并成一个类型的状况。穿插类型应用的是"与"的逻辑关系。例如,A & B 示意一个值必须同时具备类型 A 和类型 B 的属性和办法。type Person = { name: string;};type Employee = { employeeId: number;};let person: Person & Employee;person = { name: "John Doe", employeeId: 123 }; // 非法person = { name: "Jane Smith" }; // 不非法,因为短少 employeeId 属性总结: ...

June 18, 2023 · 1 min · jiezi

关于typescript:ts-如何给一个函数注释返回值类型

要为 TypeScript 中的函数正文返回值类型,能够应用函数的语法模式来指定返回类型。有两种形式能够实现这一点: 应用冒号(:)后跟返回类型正文。 function add(a: number, b: number): number { return a + b;}在上述示例中,: number 示意函数 add 的返回类型为 number,即返回一个数字类型的值。 应用箭头函数(=>)和返回类型正文。 const multiply = (a: number, b: number): number => { return a * b;};在这个示例中,(a: number, b: number): number => 示意箭头函数 multiply 的参数类型和返回类型,同样指定了返回一个数字类型的值。 在这两种状况下,你能够依据函数的理论逻辑和需要来指定正确的返回类型。TypeScript 将应用这些正文来查看函数的实现是否合乎预期的返回类型,并提供相应的类型检查和安全性。 须要留神的是,对于没有明确指定返回类型的函数,TypeScript 会尝试依据函数的实现逻辑进行推断,并推断出最合适的返回类型。然而,显式正文返回类型能够提供更明确的类型信息,并在代码中更好地表白你的用意。

June 18, 2023 · 1 min · jiezi

关于typescript:TS中-Arrayreduce提示没有与此调用匹配的重载

起因一个feature开发, 后果需要评审、工时预估, 几乎是事变级别的. 最初, 迫于无奈, 全组人都得下来救火... 明天, 帮忙改bug的时候, 发现新checkout下来的代码, 还带着陈腐的语法错误...几乎大无语. 翻了遍代码, 发现很多中央都存在Array.reduce类型重载相干的问题, 简略记录一下解决过程. 排查过程大家的vscode都不装语法提醒插件么? 代码挂着红线, 就扔代码库了??? 抽时间, 得把hook安顿上了// 业务代码不不便外流, 简略写了个demo, 问题起因雷同const nums = [1, 2, 3, 4, 5];const sum = nums.reduce((pre, cur) => { return [...pre, { count: cur }];}, []);sum.push({ count: 6 });console.log(sum);// 这段代码, 编译成.js后, 其实是能够运行的. 但如果装了插件, 能够看到显著的TS语法错误..// 输入值// [// { count: 0 },// { count: 1 },// { count: 2 },// { count: 3 },// { count: 4 },// { count: 5 },// { count: 6 }// ](pre, cur)=>{} 会提醒没有对应的重载类型. 起因不简单, 就是类型不合乎推导预期, 但为什么不合乎预期, 还真没认真看过. 本着fixbug能够, 但不能满载而归的思维, 查看了对应的TS类型申明 ...

June 16, 2023 · 1 min · jiezi

关于typescript:type-challenge-middle-部分一

续接上篇:[easy 局部]https://segmentfault.com/a/1190000043777580 相熟了根本知识点之后,middle整体比拟顺畅,就是题目太多,更多是知识点的查漏补缺。 一眼过的局部type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never;// 实现Omittype Exclude<T, K> = T extends K ? never : T;type MyOmit<T, K extends keyof T> = {[k in Exclude<keyof T, K>]: T[k]}// 指定局部readonly,此处假如曾经实现了MyOmit..type MyReadonly2<T, K extends keyof T = keyof T> = {readonly [k in K]: T[k]} & MyOmit<T, K>type DeepReadonly<T> = { readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>;};type TupleToUnion<T extends any[]> = T[number];type Last<T extends any[]> = T extends [...any[], infer U] ? U : never;type Pop<T extends any[]> = T extends [...infer U, any] ? U : T;type LookUp<U, T> = U extends {type: T} ? U : never;// Trim相干,先实现Space类型type Space = ' '|'\n'|'\t';type TrimLeft<S extends string> = S extends `${Space}${infer U}` ? TrimLeft<U> : S;type Trim<S extends string> = S extends `${Space}${infer U}`|`${infer U}${Space}` ? Trim<U>: S;type Replace<S extends string, From extends string, To extends string> = From extends '' ? S : (S extends `${infer H}${From}${infer T}` ? `${H}${To}${T}` : S);DeepReadonly这块内容还是【调配条件类型】没把握好,能够参看另一篇文档. ...

June 15, 2023 · 3 min · jiezi

关于typescript:TypeScript中的satisfies操作符应该怎么玩儿

大家好,我苏学生,一名酷爱钻研、乐于分享的前端工程师,我最喜爱的一句话是:你只管致力,后果许已在路上! 前言TypeScript4.9中新引入了satisfies操作符,依照官网的说法,它用于在确保某些表达式与某种类型匹配的同时保留该表达式的最特定类型以进行推理 在我看来,它和as关键字的用法差不多,或者说它的呈现是对as关键字的一种优化。下边咱们以几个示例来切身感受下satisfies的不同之处 示例一之前,咱们想要去复用一个类型时,为了使其满足当下的需要,经常须要借助as帮咱们实现类型革新 interface MyElement{ class:string; src:string;}const a = { class:'test'} as Partial<MyElement>上边的代码,当你尝试从a.class上调用toString()办法时,TypeScript会报错,因为src是此时是一个可选的属性,咱们必须在调用前增加?以平安的拜访它。除此之外,咱们对a.src的拜访也不会引起TypeScript的类型谬误提醒 a.class?.toString()a.src对于前者,大多数状况下这都是能够承受的,无非就是每次调用的时候麻烦一点。然而对于后者则有可能导致致命性谬误。比方你开发了某个npm包,它进行了插件化设计,那么此时这个src属性就有可能对第三方开发者产生误导 当初,咱们应用satisfies来进行革新,它会对原类型与理论值联合后推断出一个新的类型 const a = { class:'http://'} satisfies Partial<MyElement> 此时,当咱们再次拜访a.src时,TypeScript就可能正确推断出类型谬误。并且咱们对toString的调用也不须要再增加?符号来进行守卫了 推广工夫: 我原本始终在推我的约定式路由库,不过目前看来收效甚微。如果它是我的世间现实的话,那挣票子则是我的面包,所以我选了几个我认为是咱们大多数前端开发者容易疏忽但又很重要的小册。有想要学习的掘友自行购买哈 深刻分析 Node.js 底层原理图解网络协议javascript设计模式原理与实战前端调试通关秘籍示例二因为类型推倒的存在,咱们不须要去手动定义类型 const sp = { name:'spp', id:410324}但这无奈限度a中存在的key的个数,这简略,咱们去创立类型并做断言即可,就像下边这样 interface Person{ name:string; id:number;}const sp = { name:'spp'} as Person当初,咱们想让id可能灵便一点,除了number外,传string也能够,所以革新后长这样 interface Person{ name:string; id:number | string;}const sp = { name:'spp', id:410324} as Person此时当咱们去读取id做解决时,因为TypeScript无奈判断以后到底是number还是string类型,导致在调用toFixed时就会被推断出类型谬误了 sp.id.toFixed()以前咱们须要利用括号的优先级再一次进行断言来解决这个问题 (sp as number).id.toFixed()当初,咱们通过satisfies操作符就能够从本源上杜绝该问题 const sp = { name:'spp', id:410324} satisfies Personsp.id.toFixed()总结通过两个示例的解说,咱们能够总结如下: ...

June 12, 2023 · 1 min · jiezi

关于typescript:开始使用Vue-3时应避免的10个错误

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。快来收费体验ChatGpt plus版本的,咱们出的钱体验地址:https://chat.waixingyun.cn能够退出网站底部技术群,一起找bug. Vue 3 稳固曾经有一段时间了。许多代码库正在生产中应用它,其他人最终也必须进行迁徙。我有机会与它一起工作,并记录了我的谬误,这可能是你想防止的。 1.应用响应式助手申明根本类型数据申明已经很简略,但当初有多个辅助工具可用。当初的个别规定是: 应用 reactive 代替 Object, Array, Map, Set应用 ref 代替 String, Number, Boolean对于原始值应用响应式会导致正告,并且该值不会被设置为响应式:/* DOES NOT WORK AS EXPECTED */<script setup>import { reactive } from "vue";const count = reactive(0);</script>[Vue warn]: value cannot be made reactive 事例:https://codesandbox.io/s/jolly-ishizaka-ud946f?file=/src/App.vue 矛盾的是,反过来却行得通!例如,应用 ref 申明 Array 将在外部调用 reactive 。 2.解构失去响应式值让咱们设想一下,有一个具备计数器和一个按钮以减少计数器的响应式对象。 <template> Counter: {{ state.count }} <button @click="add">Increase</button></template><script>import { reactive } from "vue";export default { setup() { const state = reactive({ count: 0 }); function add() { state.count++; } return { state, add, }; },};</script>这个过程相当间接,也能如预期般工作,但你可能会想利用 JavaScript 的解构个性来进行上面的操作。 ...

June 8, 2023 · 2 min · jiezi

关于typescript:使用Nextjs快速开发全栈导航网站

背景随着ChatGPT的炽热,国外很多开发者疾速响应,利用于不同场景的AI利用井喷式的暴发,并且根本集中在web畛域利用,而在疾速开发的背地,咱们能够看到,开发者大多抉择Next.js或者Nuxt.js全栈框架来开发,以疾速验证本人的产品。这种选型的背地,我感觉次要起因有: SEO的重要性 国外更加重视SEO的重要性,国内搜索引擎大多是靠花钱买搜寻流量,包含小程序、App这类对SEO的需要并不大 Edge Function的衰亡 Serverless使得前端开发能疾速开发全栈利用,不便的托管本人后端服务,而不必过多关注部署,然而他的毛病是,少数Serverless都是采纳容器化的计划,因而冷启动工夫长,如果在本人的云函数转发申请OpenAI接口,可能会产生申请工夫很长的状况。现在, Vercel、CloudFlare、Supabase等厂商都有了Edge Function的能力,使得函数能够在一些间隔用户更近的边缘节点运行,为了更快的冷启动工夫来疾速响应用户,这种计划个别也加了局部限度,然而仍旧失去很多开发者的青眼 云服务厂商的多样性 云服务厂商提供了很多根底服务,当把我的项目托管给Vercel等服务时,能够与Github集成进行继续部署,同时还会调配一个域名。很多其余厂商也提供了很多的收费后端存储服务,例如: Upsatsh提供的RedisSupabase提供的PostgreSQLPlantScale提供的MySQLClerk提供的用户认证和用户治理以上这些厂商的收费打算对于集体开发齐全够用,当然也能够依据产品规模应用付费打算 而本文旨在尝试开发一个简略的导航页面,满足本人的收集嗜好,用于解放本人的收藏夹,来学习Next.js开发,体验Next.js带来的开发全栈利用的便捷性。 初始化我的项目随着以tailwindcss、unocss这种原子化CSS计划的呈现,基于此衍生进去的UI组件库也很多,比方Radix、daisyUI、flowbite, 其中的RadixUI组件库相当重视网页的可拜访性,组件都遵循WAI-ARIA规范,这使得开发者构建可拜访的UI界面变得更加容易,而因为他专一于可拜访性、属于Headless UI也就是无具体款式类名代码,因而shadcn作者开发了shadcn/ui组件库,在此RadixUI组件库根底上赋予了简洁好看的款式,失去了很多开发者的青眼, 也十分举荐大家体验下。 这里间接抉择克隆该作者的Nextjs模版初始化我的项目 git clone https://github.com/shadcn/next-template该我的项目应用了Next.js最新的app router版本,并且曾经集成了tailwindcss和shadcn/ui组件库。这里抉择做导航网站也是因为它足够简略,要害款式是针对侧边栏,因为tailwindcss是挪动端优先,所以这里设置默认暗藏,当屏幕宽度大于sm时展现。 <div className="fixed z-20 hidden min-h-screen sm:block"> ...</div>而对于列表区域,采纳grid布局,默认挪动端优先一列,依据屏幕大小展现2列或者3列 <div className="grid grid-cols-1 gap-3 md:grid-cols-2 md:gap-6 lg:grid-cols-3"> ...</div>其余的款式能够借鉴一下他人的网站设计简略丑化下,对于不太熟悉css并且不足审美的我花了不少的工夫在调整,总感觉网站不够好看,然而又不晓得该如何丑化。 数据库集成定义模型数据库集成这里我抉择了Prisma,相似的比拟热门的还有Drizzle,针对Prisma的具体概念、应用和它的长处,能够参考我整顿记录的笔记。执行 npx prisma init会创立prisma/schema.prisma文件,创立模型如下 generator client { provider = "prisma-client-js"}datasource db { provider = "mysql" url = env("DATABASE_URL")}model Category { id String @id @default(cuid()) icon String title String description String rank Int? createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @default(now()) @map(name: "updated_at") links Link[] @@map(name: "category")}model Link { id String @id @default(cuid()) icon String url String title String description String rank Int? public Boolean @default(true) status Int @default(1) @db.TinyInt createdAt DateTime @default(now()) @map(name: "created_at") updatedAt DateTime @default(now()) @map(name: "updated_at") cid String catagory Category @relation(fields: [cid], references: [id]) @@map(name: "link")}其中DATABASE_URL为近程数据库地址,这里我应用的是PlantScale的MySQL。当然你也能够应用Supabase的PostgreSQL或者其余数据库,创立.env文件,填入服务地址 ...

June 7, 2023 · 3 min · jiezi

关于typescript:typescriptmixins

在这篇文章中,将用简略清晰的术语向你介绍 TypeScript 中的 mixins 概念,即便你是老手。 在 TypeScript 中拓展类就像许多面向对象的编程语言一样,TypeScript 也有类。类是创建对象的蓝图——它们基本上用于封装对象中的数据。TypeScript 类能够这样定义: class Subscribe { Remind() { console.log("Remember to subscribe to my channel"); }}该类蕴含一个名为 remind 的函数,该函数在 DOM 的控制台中记录字符串。如果你有一个新的命名为 Youtube 的类 class Youtube { Begin() { console.log("Hi, Welcome to my channel!"); } Ending() { console.log("Thank you for watching my video!"); }}如果你想有一个类来扩大咱们曾经定义的两个类,以便在这个新类中拜访它们,TypeScript 不容许这样做,所以它被标记为谬误。你能够这样试试: export class Recording extends Youtube, Subscribe{}如果你尝试过这样做,你会看到当你把鼠标悬停在 IDE 上时,会通知你 TypeScript 类只能扩大一个类的含糊行。当您第一次遇到这个问题时,您可能会想起 interfaces。 interfaces在 TypeScript 中,类只能继承一个类,但接口能够继承多个类。应用 TypeScript 接口来解决咱们的问题: export class Recording {}export interface Recording extends Youtube, Subscribe {}const recording = new Recording();recording.Remind();recording.Ending();咱们创立一个接口,而后尝试查看是否能够拜访曾经定义的两个类中的函数。如果你在终端上运行 build: ...

June 6, 2023 · 1 min · jiezi

关于typescript:关于vue-import-引入方法的简单介绍-import-name-或-import-name

日常开发中常常会遇到援用组件门路和定义名称明明是对的,然而浏览器却会报错未找到定义名称。或者开发工具语法提醒谬误,那大略就是这个问题了: 形式一:export const name = 'value' 调用引入import { name } form '...' 形式二:(留神{} 是要害!)export default 'value' 调用引入import anyName form '...' 形式三:export { name as newName } 调用引入import { newName } from '...' 形式四:export { name1,name2 as newName2 } 调用引入import { name1 as newName1,newName1 } from '...' 留神语法

May 22, 2023 · 1 min · jiezi

关于typescript:使用TypeScript构建健壮的React应用程序

React是一个十分受欢迎的JavaScript库,它被用于构建大型Web应用程序。随着工夫的推移,React曾经进化为一个功能强大且灵便的工具,能够与许多其余技术一起应用。最近公布的React 18版本和TypeScript联合应用能够提供更好的开发体验。 React 18是React的最新版本,在这个版本中,咱们看到了一些重要的变动和改良。其中最显著的是对组件渲染的更新,这将使React应用程序更快、更牢靠和更容易保护。此外,React 18还引入了一些新的API,以帮忙开发人员更轻松地开发高性能和可保护的应用程序。 当然 如果您想在React 18中应用TypeScript,您须要装置TypeScript并将其配置为与React一起应用。侥幸的是,React团队曾经为此提供了十分具体的文档,因而您能够轻松地开始应用这两个技术。当您在React应用程序中应用TypeScript时,首先须要将TypeScript增加到我的项目中并配置它以与 React一起应用。以下是一个根本的TypeScript配置示例:{ "compilerOptions": { "target": "es5", "module": "commonjs", "lib": ["dom", "es6"], "jsx": "react", "strict": true, "esModuleInterop": true }}这个配置文件通知TypeScript编译器如何编译代码,并且包含了一些常见的选项,例如指标版本、模块类型、JSX语法反对、严格模式等。 接下来,您能够开始编写React组件并为它们定义类型。以下是一个简略的组件示例:import React from 'react';interface Props { name: string;}const Hello: React.FC<Props> = ({ name }) => { return <div>Hello, {name}!</div>;};export default Hello;在这个示例中,咱们定义了一个名为“Hello”的组件,并应用Props接口定义了组件的属性类型。在组件中,咱们将Props作为泛型参数传递给React.FC类型,并应用解构赋值从属性对象中提取出name属性。最初,咱们返回一个蕴含{name}的div元素。 要在另一个组件中应用此组件,您只需导入它并将其出现即可:import React from 'react';import Hello from './Hello';const App: React.FC = () => { return <Hello name="World" />;};export default App;在这个示例中,咱们将“Hello”组件导入到“App”组件中,并将其出现为一个带有name属性的元素。TypeScript会在编译时验证传递给Hello组件的属性是否具备正确的类型。 总结:应用React 18和TypeScript能够使您的代码更加强壮、易于保护,并提供更好的开发体验。如果您正在思考在您的下一个React我的项目中应用TypeScript,我强烈建议您开始尝试一下!

May 21, 2023 · 1 min · jiezi

关于typescript:React18TSNestJSGraphQL-全栈开发在线教育平台南朝四百八十寺

download:React18+TS+NestJS+GraphQL 全栈开发在线教育平台深刻理解 TS+NestJSTS(TypeScript)和 NestJS 是两个在 Node.js 生态系统中十分风行的开发工具。TS 是一种由微软推出的动态类型语言,能够使 JavaScript 代码更加牢靠、易于保护和调试。NestJS 则是一个基于 TS 的高度模块化的框架,能够帮忙咱们疾速构建可扩大和可保护的 Web 应用程序。本文将深入探讨 TS 和 NestJS 的相干概念和技术。 TS 的长处TS 作为 JavaScript 的超集,它可能为咱们带来很多长处: 动态类型查看TS 能够在编译时对代码进行类型查看,从而防止因类型谬误导致的运行时谬误。这能够大幅提高代码的可靠性和稳定性。 强类型反对TS 反对强类型编程,能够让咱们更轻松地治理变量和函数的类型,从而使代码更加可读和易于保护。 新性能反对TS 实现了 ECMAScript 的最新规范,同时也反对一些新个性,例如装璜器、异步和 await 等,这些都能够使咱们更不便地编写高效的代码。 NestJS 的长处NestJS 是一个基于 TS 的高度模块化的框架,它能够为咱们带来很多长处: 可扩展性NestJS 采纳模块化开发的形式,使得应用程序更容易扩大和治理。咱们能够应用不同的模块来组织业务逻辑、中间件和其余性能。 可测试性NestJS 通过依赖注入(Dependency Injection,DI)和模块化开发的形式,使得咱们能够更轻松地编写自动化测试,并确保代码的品质和正确性。 设计模式反对NestJS 反对常见的设计模式,例如 MVC、微服务和事件驱动架构等,这些都能够使咱们更加灵便地解决简单的业务逻辑和交互。 NestJS 的基本概念在深入探讨 NestJS 的技术之前,咱们须要先理解一些基本概念: 控制器(Controller)控制器是解决 HTTP 申请和响应的外围组件。每个控制器都映射到一个或多个路由,以便解决特定类型的申请。控制器通常蕴含一个或多个办法,每个办法对应于一个特定的申请 URI 和 HTTP 办法。 提供者(Provider)提供者是实现业务逻辑和数据拜访的要害组件。提供者能够是服务、存储库或工厂等。NestJS 通过依赖注入来治理提供者的生命周期和依赖关系。 中间件(Middleware)中间件是用于解决 HTTP 申请和响应的组件。中间件能够在申请达到控制器之前或之后执行一些逻辑。NestJS 通过 MiddlewareInterface 接口来定义中间件。 模块(Module)模块是组织和治理代码的根本单元,每个模块都应该有一个清晰的职责,并且应该尽可能遵循繁多职责准则。NestJS 应用 @Module 装璜器来定义模块。 ...

May 21, 2023 · 2 min · jiezi

关于typescript:typescript-type-分配条件类型

接上文type challenge(easy局部)对于调配条件类型,官网文档形容地址。 之前看的时候没真正了解,对于联结类型的调配条件,官网文档其实也没有讲得很明确,和翻译无关,英文文档一样很含糊,这些天做type challenge,发现有些题做进去的后果和预期不太统一,所以从新梳理这块内容。 先说论断联结类型什么时候会调配,必须合乎4个条件(前面间接用条件1、条件2等代指上面条件): 首先,只调配extends前的内容 无论这个extends是不是子断言语句中的例如type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;, 其中的T extends 'b'在子语句中,但事实上仍旧是无效的调配的内容未做任何解决 type Test<T> = keyof T extends null ? never: false;,T被keyof操作符解决了,因而不会调配官网文档中,提到防止调配的办法type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;,能躲避调配也是这个情理调配内容必须作为参数传入传入时是联结类型相干题目与解析验证条件1type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;Test<'a'| 'b'> // boolean可见在子条件中的extends也合乎主动调配,否则'a'|'b' extends 'b'会返回false,而不是true|false 验证条件2发现这个问题是在DeepReadonly,题目地址 这一题一看看过来,间接写出如下: type DeepReadonly<T> = keyof T extends never ? T : {readonly [k in keyof T]: DeepReadonly<T[k]>};然而发现对于测试用例X2不失效 ...

May 16, 2023 · 2 min · jiezi

关于typescript:Vue3PiniaViteTS-还原高性能外卖APP项目芙蓉如面柳如眉

download:Vue3+Pinia+Vite+TS 还原高性能外卖APP我的项目React Native技术体系的学习和实际指南React Native是一种基于React的跨平台挪动利用开发框架,它能够让开发者应用JavaScript语言来开发iOS和Android应用程序。然而,对于初学者来说,学习和把握React Native技术体系可能会面临很多艰难和挑战。本文将介绍如何从0到1构建残缺的RN技术体系。 第一步:学习React基础知识 在学习React Native之前,须要先把握React的基础知识。React是一个用于构建用户界面的JavaScript库,能够帮忙开发者更加高效地构建用户界面。须要理解React的组件、状态、属性等概念,并联合实际进行深刻了解。 第二步:学习React Native基础知识 在理解React之后,须要学习React Native的基础知识。须要理解React Native的布局、款式、导航、网络申请等概念,并联合实际进行深刻了解。 第三步:学习Redux状态治理 在React Native中,应用Redux状态治理能够帮忙开发者更加高效地管理应用程序的状态。须要理解Redux的基本原理、Action、Reducer等概念,并联合实际进行深刻了解。 第四步:学习React Native的高级利用 在把握React Native的基础知识和Redux状态治理之后,须要学习React Native的高级利用。比如说,应用React Native开发动画成果、应用第三方库、调试技巧等。通过学习这些高级利用,能够让开发者更加高效地开发React Native应用程序。 第五步:参加开源我的项目或本人编写应用程序 最初,在学习React Native技术体系的过程中,最好可能参加到开源我的项目中,或者编写本人的应用程序进行练习。通过实际,能够更加深刻地了解React Native技术体系的应用和原理,并锤炼本人的开发能力。 总之,学习React Native须要急躁和毅力。从0到1构建残缺的RN技术体系,须要把握React基础知识、React Native基础知识、Redux状态治理、React Native的高级利用等常识,并联合实际进行深刻了解。只有坚定不移地学习和实际,就能把握这一风行的挪动利用开发框架。

May 15, 2023 · 1 min · jiezi

关于typescript:TypeScript-React-Hooks-封装通用图表Echarts组件

在 React Hooks 日常开发中可能会遇到多个Echarts数据图表需要,为了便于复用和治理,开发一个通用型公共图表组件是十分有必要的。 首先定义用于图表的类型文件IChart.ts: import { CSSProperties } from 'react';import * as echarts from 'echarts/core';import { // 系列类型的定义后缀都为 SeriesOption BarSeriesOption, LineSeriesOption} from 'echarts/charts';import { TitleComponentOption, TooltipComponentOption, GridComponentOption, DatasetComponentOption,} from 'echarts/components';// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型export type IECOption = echarts.ComposeOption< | BarSeriesOption | LineSeriesOption | TitleComponentOption | TooltipComponentOption | GridComponentOption | DatasetComponentOption>;export interface IOnEvents{ [index: string]: (param: unknown, instance: echarts.ECharts) => void;}type RendererType = 'canvas' | 'svg';interface IEChartsInitOpts { readonly locale?: string ; readonly renderer?: RendererType; readonly devicePixelRatio?: number; readonly useDirtyRect?: boolean; readonly useCoarsePointer?: boolean; readonly pointerSize?: number; readonly ssr?: boolean; readonly width?: number | string; readonly height?: number | string;}export interface IChartProps { readonly option: IECOption; readonly loading?: boolean; readonly onEvents?: IOnEvents; readonly onChartReady?: (echartsInstance: echarts.ECharts) => void; readonly style?: CSSProperties; readonly className?: string; readonly theme?: string | object; readonly opts?: IEChartsInitOpts;}IChartProps为Chart组件的入参。 ...

May 13, 2023 · 4 min · jiezi

关于typescript:白鹭游戏引擎网络棋牌搭建步骤

前言我的项目是一个游客登录型的棋牌联网游戏,前端是白鹭引擎,后端PHP开发。分为登录和获取根本信息的Http层和websocket通信的游戏层。后盾须要有一个分布式网关服务器(php游戏网关)。以下为了搭建更快捷,应用宝塔进行操作,前提曾经通过宝塔装置结束了LNMP。 步骤下载完源码地址的源码,解压失去以下四个目录,别离的用处见标注。 2. EgretWing工具导入client中的代码,web整个文件夹的代码放入服务器(我是本地应用VM搭的centOS虚拟机)。3. 宝塔中的应用的PHP装置yaf扩大,重启PHP后拜访查看phpinfo()可能找不到yaf 4. 通过宝塔的创立网站增加web中的代码,使得能通过域名申请到web目录下的api.php就行。次要是三个接口,别离返回登录信息,websocket的地址和端口,图片代理等。 代码client文件中的代码批改”src/scene/Login.ts”的onLoginTouch办法中申请网络接口为下面web中配置的域名,”src/Main.ts”中的initGame办法同样批改网络申请地址为下面web配置的域名。接口别离是昵称和登录token,另一个是websocket地址和端口。下载下面的Fooking的源代码,并将代码放入服务器中,目录构造如下。 7. 关上服务器命令面板,cd进入fooking目录(以我的为例,名字能够自定义)。而后make进行编译。Src目录中多出后缀为0的文件,面板也会显示编译完结。 8. 关上fooking目录下的router.lua文件。PROT能够自行定义,确定下了这个端口,我的是8015。就须要在centOS防火墙中对其放行,宝塔是间接点击平安增加8015进行放行。 9. 仍然是同级目录,关上config.lua文件,端口就是游戏中webscket进行连贯的端口。次要配置的有路由服务器地址(下面router设置的端口和地址),后端服务器列表的“BACKEND_SERVER”,以及fastcgi params,配置标注如下。--监听IP和端口HOST = "0.0.0.0";PORT = 9005;--守护进行--DAEMONIZE = 1;--日志文件(为空则不输入日志, stdout-输入到规范输入上, 其它则按文件解决)LOG_FILE = "stdout";--间接屏幕打印--LOG_FILE = "/tmp/fooking-gateway.log";--输入到文件--1: 仅error--2: error与info--3: 所有LOG_LEVEL = 3;--是否路由服务器(0-否, 1-是)--如果是路由,ROUTER以下的配置将被疏忽)ROUTER = 0;--服务器IDSERVER_ID = 1;--工作过程WORKER_NUM = 2;--最大连接数MAX_CLIENT_NUM = 10000;--缓冲区大小MAX_BUFF_SIZE = 4096;--路由服务器ROUTER_HOST = "192.168.234.128";ROUTER_PORT = 8015;--SSL配置--SSL = 1--SSL_CERT = "/tmp/cert.pem"--SSL_PKEY = "/tmp/pkey.pem"--指定工夫内连贯没有数据包申请,将会踢掉连贯(单位秒),为0不解决IDLE_TIME = 0;--脚本SCRIPT_FILE = "../scripts/Websocket.lua";--后端服务器列表BACKEND_CONNECT_TIMEOUT = 5;--连贯超时工夫(单位秒)BACKEND_READ_TIMEOUT = 10;--数据接管超工夫(单位秒)BACKEND_KEEPALIVE = 10;--最大维持长连贯数量BACKEND_SERVER = { ["unix:/tmp/php-cgi-73.sock"] = 5,--第一列是socket选项,第二列是权重(跟nginx的upstream差不多一个意思)};--新连贯是否告诉(0-不告诉, 1-告诉)--申请头会有EVENT=1EVENT_CONNECT = 0;--敞开连贯是否告诉(0-不告诉, 1-告诉)--申请头会有EVENT=2EVENT_CLOSE = 1;--fastcgi paramsFASTCGI_PREFIX = "";--go下要应用HTTP_作为前缀,否则拿不了SESSIONID和EVENTFASTCGI_ROOT = "/www/wwwroot/san_zhang_pai/server/";--必须以/结尾FASTCGI_FILE = "server.php";FASTCGI_PARAMS = { ["SERVER_SOFTWARE"] = "fooking", ["SERVER_PROTOCOL"] = "HTTP/1.1", ["GATEWAY_INTERFACE"] = "CGI/1.1", ["REQUEST_METHOD"] = "POST", ["SCRIPT_FILENAME"] = FASTCGI_ROOT..FASTCGI_FILE, ["SCRIPT_NAME"] = FASTCGI_FILE, ["DOCUMENT_ROOT"] = FASTCGI_ROOT, ["SERVER_NAME"] = "server.yafgame.com/", ["QUERY_STRING"] = "a=10&b=20",}; ...

May 12, 2023 · 1 min · jiezi

关于typescript:type-challengeeasy-部分

type-challenge刷题type-challenge挑战地址 easy一眼过的局部type MyPick<T, K extends keyof T> = {[k in K]: T[k]};type MyReadonly<T> = {readonly [k in keyof T]: T[k]};type TupleToObject<T extends readonly (string|number|symbol)[]> = {[k in T[number]]: k};type First<T extends any[]> = T extends [infer Head, ...unknown[]] ? Head : never;type Length<T extends readonly unknown[]> = T["length"]; // 题目要求readonly数组type If<C extends boolean, T, F> = C extends true ? T : F;type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];type Push<T extends unknown[], U> = [...T, U];type Unshift<T extends unknown[], U> = [U, ...T];type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer U) => any ? U : never;Exclude原题地址 ...

May 11, 2023 · 2 min · jiezi

关于typescript:Part2JavaScript生态加速攻略模块解析

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。快来收费体验ChatGpt plus版本的,咱们出的钱体验地址:https://chat.waixingyun.cn能够退出网站底部技术群,一起找bug. 作者 @marvinhagemeist 于2023年1月15日论述了如何优化JavaScript的模块解析以进步开发效率。文章提到,无论是构建、测试还是查看 JavaScript 代码,模块解析都是其中的外围环节。然而,只管模块解析在咱们的工具中占据着要害位置,但目前尚未投入足够的工夫来进步这一方面的速度。 在本系列的第一局部中,咱们找到了一些减速JavaScript工具中应用的各种库的办法。尽管这些低级别的补丁将总构建工夫数字挪动了很大一部分,但我想晓得咱们的工具中是否有更根本的货色能够改良。像捆绑、测试和linting这样的常见JavaScript工作的总工夫影响更大的货色。 在接下来的几天里,我收集了来自咱们行业罕用的各种工作和工具的大概十几个 CPU 剖析文件。通过一番查看,我发现了一个在我查看的每个剖析文件中都存在的反复模式,它会影响这些工作的总运行工夫高达 30%。它是咱们基础设施中如此要害和有影响力的一部分,值得有一篇专门的博客文章来介绍。 那个要害局部被称为模块解析。在我查看的所有跟踪中,它所破费的总工夫比解析源代码还要多。 捕捉堆栈跟踪的老本在这些跟踪中最耗时的局部是在 captureLargerStackTrace 中破费的,这是一个负责将堆栈跟踪附加到 Error 对象的外部节点函数。思考到两个工作都胜利实现而没有显示任何谬误被抛出,这仿佛有点不寻常。 在浏览了一堆性能数据的产生后,一个更清晰的图片浮现进去,即正在产生什么。简直所有的谬误创立都来自于调用节点的本地 fs.statSync() 函数,而这反过来又被调用在一个名为 isFile 的函数内。文档提到 fs.statSync() 基本上相当于 POSIX 的 fstat 命令,并且通常用于查看磁盘上的门路是否存在、是文件还是目录。思考到这一点,咱们只应该在异常情况下呈现谬误,例如文件不存在、咱们短少读取它的权限或相似状况。是时候看一眼 isFile 的源代码了: function isFile(file) { try { const stat = fs.statSync(file); return stat.isFile() || stat.isFIFO(); } catch (err) { if (err.code === "ENOENT" || err.code === "ENOTDIR") { return false; } throw err; }}这看起来是有害的函数,但依然在跟踪中显示进去。值得注意的是,咱们疏忽了某些谬误状况,并返回 false 而不是转发谬误。 ENOENT 和 ENOTDIR 错误代码最终意味着磁盘上不存在该门路。兴许这就是咱们看到的开销?我的意思是,咱们在这里立刻疏忽了这些谬误。为了测试这个实践,我记录了 try/catch 块捕捉的所有谬误。后果每个抛出的谬误都是一个 ENOENT 代码或一个 ENOTDIR 代码。 ...

May 10, 2023 · 2 min · jiezi

关于typescript:TypeScript-编程规范最佳实践

作为 JavaScript 的超集。以后的 TypeScript 十分风行,TypeScript解决了许多在 JavaScript 中编程的痛点,进步了健壮性、可读性、开发效率、开发体验,所以学好TypeScript是十分有必要的。 想要学好 TypeScript 离不开良好的编程标准和最佳实际。本文蕴含某些技巧在JavaScript 中也能实用,当然在 JavaScript 中的开发标准仍然可能在 TypeScript 中应用,然而要转变到 TypeScript 开发中时要对以往的开发思维、习惯进行一些扭转。 语法禁止应用 //@ts-ignore 、any。tsx中必须应用as断言,因为 <> 容易跟jsx标签、泛型语法起抵触。禁止批改任何原生js内置原型xxx.prototype。倡议尽量不应用unknown、双重断言,请应用更精确的类型或类型守卫,不要滥用类型断言。对一些援用类型数据进行批改时倡议要先进行浅/深拷贝、或对象解构再进行批改,防止毁坏原数据。优先应用对象开展运算符 ... 来做对象浅拷贝而不是应用 Object.assign、Array.from。倡议应用可选链(ES11新增的个性) ?. 代替 a && a.b && a.b.c 这样的代码。倡议应用空值合并运算符 ?? 代替const name = nickName || loginName || '' 这样的代码。让泛型变量更加语义化,常见泛型变量如下: T(Type):示意一个 TypeScript 类型 K(Key):示意对象中的键类型 V(Value):示意对象中的值类型 E(Element):示意元素类型排版格调(可读性)倡议给interface申明程序,只读参数放第一位,必选参数第二位,而后是可选参数,不确定参数放最初: interface IProps { readonly x: number; readonly y: number; name: string; age: number; height?: number; [propName: string]: any;}倡议应用 === 和 !== 而非 == 和 != ,如条件过于简单,倡议封装判断条件,晋升可读性。 ...

May 8, 2023 · 2 min · jiezi

关于typescript:防抖和节流

防抖(debounce)和节流(throttle)是优化高频触发事件的技术,它们能够进步性能,防止不必要的计算和函数执行。以下是一些理论场景的示例: 防抖(Debounce):防抖用于确保一个函数在肯定工夫内只触发一次。它在短时间内屡次触发同一个事件时,会勾销之前的触发,直到最初一次触发后的肯定工夫距离内没有新的触发才执行函数。常见的利用场景包含: 输入框实时搜寻:当用户在输入框中输出时,能够应用防抖技术提早执行搜寻查问,缩小不必要的查问和服务器压力。窗口大小调整:当用户调整浏览器窗口大小时,能够应用防抖技术防止在调整过程中频繁地从新计算布局。表单验证:当用户在表单输出时,能够应用防抖技术在用户进行输出一段时间后再执行验证,缩小验证的次数。节流(Throttle):节流用于确保一个函数在肯定工夫内最多只触发一次。它会在触发事件期间以固定的工夫距离执行函数,而不论事件触发得多频繁。常见的利用场景包含: 滚动事件监听:例如监听页面滚动到底部加载更多数据时,能够应用节流技术缩小查看滚动地位的频率,进步性能。鼠标挪动事件:例如实现一个拖拽性能,能够应用节流技术缩小鼠标挪动事件的解决频率。动画成果:当实现一个基于工夫的动画成果时,能够应用节流技术限度动画帧率,升高计算开销。总之,防抖和节流技术都能够在不同场景下进步利用性能。防抖实用于屡次触发只需执行一次的状况,而节流实用于限度间断触发事件的执行频率。 /** * @description 防抖函数 * @param {Function} fn * @param {number} delay * @param {boolean} immediate * @returns {Function} */export function debounce<T extends (...args: any[]) => any>( fn: T, delay: number, immediate: boolean = false): T & { cancel(): void } { let timerId: ReturnType<typeof setTimeout> | null = null; // 存储定时器 // 定义一个cancel办法,用于勾销防抖 const cancel = (): void => { if (timerId) { clearTimeout(timerId); timerId = null; } }; const debounced = function ( this: ThisParameterType<T>, ...args: Parameters<T> ): void { const context = this; if (timerId) { cancel(); } if (immediate) { // 如果 immediate 为 true 并且没有正在期待执行的定时器,立刻执行指标函数 if (!timerId) { fn.apply(context, args); } // 设置定时器,在延迟时间后将 timeoutId 设为 null timerId = setTimeout(() => { timerId = null; }, delay); } else { // 设置定时器,在延迟时间后执行指标函数 timerId = setTimeout(() => { fn.apply(context, args); }, delay); } }; // 将 cancel 办法附加到 debounced 函数上 (debounced as any).cancel = cancel; return debounced as T & { cancel(): void };}/** * 节流函数 * @param func 要进行节流的指标函数 * @param delay 节流的工夫距离(毫秒) * @returns 返回一个通过节流解决的函数 */export function throttle<T extends (...args: any[]) => any>( fn: T, delay: number): T { let lastCall: number | null = null; // 上一次调用的工夫戳 return function ( this: ThisParameterType<T>, ...args: Parameters<T> ): ReturnType<T> | void { const now = Date.now(); //以后工夫戳 // 如果之前没有调用过,或者工夫距离超过了设定的值,执行指标函数 if (!lastCall || now - lastCall >= delay) { lastCall = now; return fn.apply(this, args); } } as T;}

May 8, 2023 · 2 min · jiezi

关于typescript:如果你用TypeScript写Vue3你可以来看看这篇文章

① 我的项目介绍我的项目的装置与初始化请先查看宿主我的项目https://gitee.com/hamm/AirPowerDemo 为了满足前端开发标准化、工程化、系统化等等需要,咱们设计并开发了一个开发组件库和罕用类库和办法库的汇合根底脚手架,其中蕴含了一些页面通用的布局、罕用的弹窗和交互、提示信息以及网络申请,强类型面向对象的束缚标准等,以满足日常开发的快捷、持重、标准化等要求。 ② 我的项目依赖AirPower目前依赖 Vue + TypeScript + Element Plus + class-transformer 等组件,其中还蕴含了一些第三方模块的依赖,具体能够参考我的项目的 package.json。 ③ 模块阐明AirPower内置了以下一些模块: component 组件蕴含了罕用的 AInput AButton ATable AToolBar APage等罕用的组件; config 配置蕴含了 实体配置、字段在 Table Search Form 中的个性配置、Props传参配置、图像配置等罕用的配置类、配置办法等; decorator 装璜器:提供了表格配置、表单配置、类和属性自定义名称配置、搜寻配置等装璜器; dto 数据传输模型蕴含了一些分页、排序、罕用类、形象基类等规范的数据传输模型; enum 枚举提供了目前曾经达成规范和标准的一些枚举信息,如色彩、日期格局、反馈图标款式、搜寻类型、HTTP参数等; feedback 反馈基于 Element Plus 提供的规范反馈组件,定义了标准的一些弹窗、确认框、告诉信息等反馈组件; helper 助手类提供了工夫日期、文件、数据转换、弹窗、随机与加解密、路由等快捷操作的助手类和办法; interface 接口提供了一些罕用数据结构的标准化配置以及须要被实现的标准接口; model 数据模型提供一些根底的数据模型与操作方法; service 服务提供了一些根底的 CRUD 办法的根底网络申请服务和一些罕用的 API; view 页面提供了谬误页等罕用的内置页面; ④ 开发理念CaaS 配置即服务为了防止大量反复代码的呈现,咱们尽可能通过 TypeScript 的装璜器将一些类或属性的配置写入到原型链中,在须要应用这些配置的中央通过反射将保留的参数配置取出应用即可。 其中,如果波及一些默认值,将默认值通过 AirConfig 作为根底配置进行初始化到零碎中,通过配置项的应用范畴和配置老本进行调整后,应用方能够最小配置的形式进行零碎业务的接入和开发。 强面向对象的反对在雷同或类似业务中,咱们应用规范的强面向对象进行实现,基于继承、封装等个性进行代码的复用,通过泛型、接口等形式将类似的业务逻辑进行标准化束缚,实现类似但又不完全相同的一些灵便业务的疾速开发。 数据和类的转换器为了在后端因业务要求进行属性调整后前端不须要做大量的查找替换进行修复,咱们引入了 class-transformer 这个第三方库进行数据转换,通过自由选择 Expose 字段和配置转换规则来实现仅在配置层即可解决字段属性变更的问题。具体请浏览对于数据转换的局部。 ...

May 6, 2023 · 2 min · jiezi

关于typescript:ReactNative第三方库

依据第三方库地址集 lottie-react-native动画库github以及官网 import React, {FC} from "react";import {SafeAreaView, ScrollView, Text} from "react-native";import Lottie from 'lottie-react-native';interface Props {}const LottieReactNative: FC<Props> = () => { const animationRef = React.useRef<Lottie | null>(null); React.useEffect(() => { }, []); return <SafeAreaView> <ScrollView> <Lottie source={require('./animation.json')} autoPlay loop style={{width: 100}}/> </ScrollView> </SafeAreaView>;};export default LottieReactNative;

May 4, 2023 · 1 min · jiezi

关于typescript:TypeScript-进阶与实践二

内容接《TypeScript 进阶与实际(一)》,倡议在学习完上一篇内容后再持续浏览这一篇。三、类型编程3.1 泛型泛型是一种创立可复用代码组件的工具。泛型容许咱们在强类型程序设计语言中编写代码时应用一些当前才指定的类型,在应用时作为参数指明这些类型。泛型能够用于定义函数、接口或类,不事后定义好具体的类型,而在应用的时候再指定类型。泛型能够进步代码的可读性和可维护性,同时也能够进步代码的复用性和灵活性。 这部分以函数中如何应用泛型来开展解说,你还能够在类型别名、类和对象等场景应用泛型,应用形式大同小异,这里就不再赘述。 3.1.1 泛型类型变量假如要定义一个 reflect 函数 ,它能够接管任意类型的参数,并一成不变地返回参数的值,在没有应用泛型之前,咱们能够这样去实现: function reflect(param: unknown) { return param;}const str = reflect('string'); // str 类型为 unknownconst num = reflect(1); // num 类型为 unknown你会发现,这种实现形式,不论咱们传入的参数是什么类型,最终返回的值的类型都是 unknown,这样在应用返回值时还须要将类型放大能力平安的应用,并不是很不便。咱们曾经晓得 reflect 函数会一成不变的返回传入的参数了,那么有没有方法让返回值的类型依据传入的参数的类型变动而变动呢?答案是必定的,应用泛型类型变量就能够满足这个要求。 泛型类型变量的应用形式如上面示例所示: function reflect<T>(param: T) { return param;}// TS 会依据参数的值的类型来推断泛型类型参数的类型let str = reflect('string'); // str 的类型为 stringlet num = reflect(1); // num 的类型为 num// 显式传递泛型类型参数,会限度传入的参数类型必须与传入的泛型参数类型统一let value = reflect<string>(123); // str 的类型为 string下面示例中咱们在 reflect 函数名称的前面应用 <T> 申明了泛型类型变量 T,而后将参数 param 的类型指定为了 T ,函数体中一成不变的返回了参数 param ,返回值的类型会被隐式推断为 param 的类型,即返回值的类型也为 T 。 ...

April 27, 2023 · 7 min · jiezi

关于typescript:echarts-曲线配置

自定义配置折线及柱状图是否显示、色彩、线宽、最小值等 配置 <template> <a-modal v-model="visible" :width="dialogWidth" :centered="true" :title="title" @click="clickOutside" :destroyOnClose="true" @cancel="cancelFun" :keyboard="false" :maskClosable="false" @ok="confirmFun" > <div @click="clickOutside" style="max-height:530px;overflow:auto;position:relative"> <div class="title row"> <div class="name-item"></div> <div class="show-item">是否显示</div> <div class="min-item">最小值</div> <div class="line-item">线宽</div> <div class="color-item">色彩</div> </div> <div> <template v-for="(item, ind) in setData"> <div v-if="item.name" class="row-item" :key="ind + item.name"> <div class="name-item">{{ item.name }}:</div> <div class="flex show-item"> <a-switch v-model="item.show" @change="showChange($event, ind)" /> </div> <div class="flex min-item"> <a-input-number v-model="item.min" @change="minChange($event, ind)"></a-input-number> <!-- {{ ind }} --> </div> <div class="flex line-item"> <a-input-number v-model="item.lineWidth" @change="lineWidthChange($event, ind)" :min="1"></a-input-number> </div> <div class="flex color-item"> <div class="color-box" @click="setColorSelect(ind)" style="width:10px;height:10px;cursor:pointer;position:relative" :style="{ background: item.color }" > <div v-if="showColorInd == ind"> <sketch-picker id="color-select-box" class="sketch-picker" style="width:200px;position:absolute; left: -100px; z-index: 10;" :style=" ind >= 7 ? 'top: -312px;left: -207px;' : ind >= 2 && ind <= 4 ? 'left: -227px;top:-100px' : ind === 5 || ind === 6 ? 'left: -227px;top:-186px' : 'bottom:-312px;left: -207px;' " v-model="item.colors" @input="updateColor($event, ind)" /> </div> </div> </div> </div> </template> </div> </div> </a-modal></template><script>import { Chrome, Sketch } from 'vue-color'export default { components: { 'sketch-picker': Sketch, 'chrome-picker': Chrome }, props: { title: { type: String, default: '曲线配置' }, dialogWidth: { type: Number, default: 600 } }, data() { return { showColorInd: -1, setData: [], visible: false } }, mounted() {}, methods: { clickOutside(event) { const current = document.getElementById('color-select-box') let that = this if (current && event.target.className != 'color-box' && that.showColorInd != -1) { if (!current.contains(event.target)) { that.showColorInd = -1 } } }, initData(data) { let arr = [] data.forEach(item => { let obj = arr.find(itm => { return itm.name === item.name }) if (!obj) { item.min = item.min ? item.min : 0 item.lineWidth = item.lineWidth ? item.lineWidth : 1 item.show = item.show === false ? false : true item.colorSelectShow = false item.colors = { hex: item.color } arr.push(item) } }) this.setData = arr }, lineWidthChange(value, ind) { let obj = Object.assign({}, this.setData[ind], { lineWidth: value }) this.$set(this.setData, ind, obj) }, setColorSelect(ind) { // let haveShow = this.setData.find(item => { // return item.colorSelectShow === true // }) // let obj = Object.assign({}, this.setData[ind], { colorSelectShow: haveShow ? false : true }) // this.$set(this.setData, ind, obj) this.showColorInd = ind }, updateColor(value, ind) { let obj = Object.assign({}, this.setData[ind], { colors: value }, { color: value.hex }) console.log('obj=', obj) this.$set(this.setData, ind, obj) }, minChange(value, ind) { // console.log('minChange=', value) let obj = Object.assign({}, this.setData[ind], { min: value }) this.$set(this.setData, ind, obj) }, showChange(value, ind) { let obj = Object.assign({}, this.setData[ind], { show: value }) this.$set(this.setData, ind, obj) }, show(data) { this.visible = true this.initData(data) }, hide() { this.visible = false }, cancelFun() { this.$emit('cancel') }, confirmFun() { console.log('setData=', this.setData) this.hide() this.$emit('ok', this.setData) } }}</script><style scoped lang="less">.row-item { display: flex; align-items: center; justify-content: center; border: 1px solid #ccc; align-self: center; margin-bottom: 6px; padding: 0 20px; .flex { min-width: fit-content; display: flex; align-items: center; // justify-content: center; width: 150px; } .show-item { width: 90px; } .name-item { font-weight: bold; font-size: 16px; min-width: 140px; text-align: right; width: fit-content; } .min-item { width: 90px; } .color-item { width: 80px; margin: 10px auto; } .line-item { margin-left: 10px; }}.title { margin-bottom: 10px; display: flex; div { font-size: 16px; font-weight: bold !important; // min-width: 100px; width: 100px; text-align: center; &.show-item { width: 120px; padding-left: 40px; } &.min-item { width: 105px; } &.color-item { width: 108px; text-align: center; margin-left: -10px; } }}</style>曲线显示组件 ...

April 26, 2023 · 9 min · jiezi

关于typescript:ts报错Property-xxx-does-not-exist-on-type

问题在catch中对立解决异样信息,就想着写到一个函数外面,而后须要用到的中央自行调用就能够。 个别两种办法,要不通过mixin,要不绑定到vue的prototype下面。 这里采纳的是后者。 在以前没引入ts之前,是那么简略的一件事件。 // 先绑定 Vue.prototype.$catchRequestError = function () {} // 再援用 this.$catchRequestError()可是IDE缺给出谬误提醒了。 谬误提醒是:Property '&dollar;catchRequestError' does not exist on type 'InstanceList'. 解决看起来说是$catchRequestError不存在InstanceList的type下面。 详情: https://mp.weixin.qq.com/s?__biz=Mzg5Mjc2NDYwMg==&mid=2247484... 有问题可群征询:https://public-1253796280.cos.ap-nanjing.myqcloud.com/%E5%89%...

April 19, 2023 · 1 min · jiezi

关于typescript:TypeScript-Map实现一个公共数据管理模块DataMap

在大型中后盾我的项目开发中,尤其是在应用React进行开发时,咱们会遇到很多下拉框数据、多选框数据、或者编码中多处应用到的业务型公共映射表。为了便于保护,能够把这些数据都集中放到一个模块中,而不是扩散的写在各个中央。 实现思路咱们定义一个IMapExtra接口扩大一下Map实例,建设两个类MapExtra和DataMap,MapExtra是为了在应用数据时更不便获取Map类型数据。最初把map(数据映射)都存储在DataMap类的成员中。 开始首先咱们创立一个DataMap.ts文件用于公共数据治理的模块,并在外面创立一个MapExtra类实现IMapExtra接口,MapExtra性能次要是对原生Map进行一个简略的封装。起因是咱们须要这个MapExtra实例来存储数据并可更不便的应用.get间接获取到对应的数据项。 DataMap.ts import * as utils from '@/utils';type MapType<T> = Array<[T, T]>;interface IMapExtra { map: Map<string| number, string| number>; has: ( key: string) => boolean; get: ( key: string) => string| number; getOptions: () => TYPE.IOption[];}class MapExtra implements IMapExtra { public map; private _map; public constructor( map: MapType<string| number>) { this._map = new Map(map); this.map = new Map(map); } public getOptions: IMapExtra['getOptions'] = () => utils.mapToOption(this._map); public has: IMapExtra['has'] = ( key) => this._map.has(key); public get: IMapExtra['get'] = ( key) => this._map.get(key) ?? key;}同时下面减少了一个getOptions办法更不便的拿到对应以后数据的下拉框构造,当然这里还能够扩大map转其余构造的数据。 ...

April 16, 2023 · 3 min · jiezi

关于typescript:推荐一个将Eolink-Api精确转换TS类型的开源Chrome插件

在ts实际中,将eolink api接口的出参入参准确转换为ts类型,真是十分苦楚。尤其出参入参挺特地多的时候,分分钟都想掀桌子。 这里举荐一个疾速将eolink api接口准确转换为ts类型的开源chrome插件。先上成果: 真是太香了!!!

April 16, 2023 · 1 min · jiezi

关于typescript:Property-context-does-not-exist-on-type-NodeRequirets2339

最近应用vue3官网脚手架创立的我的项目,在执行上面的代码后报错:const files = require.context('./modules', false, /\.js$/)查阅相干材料,有人提出解决办法如下,装置@types/webpack-env依赖: npm i -D @types/webpack-env批改tsconfig.json: { "compilerOptions": { "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": ["es6", "dom"], "module": "es6", "moduleResolution": "node", "sourceMap": true, "target": "es5", "types": [ "webpack", "webpack-env" // 退出这个 ] },}然而发现,开始的报错并没有隐没。 在我的项目根目录找到tsconfig.vitest.json,在"types": ["node", "jsdom"]中退出"webpack-env" { "extends": "./tsconfig.app.json", "exclude": [], "compilerOptions": { "composite": true, "lib": [], "types": ["node", "jsdom","webpack-env"] }}报错隐没。

April 13, 2023 · 1 min · jiezi

关于typescript:历史性的时刻OpenTiny-跨端跨框架组件库正式升级-TypeScript10-万行代码重获新生

依据 《2022 前端开发市场状态调查报告》数据显示,应用 TypeScript 的人数曾经达到 84%,和 2021 年相比减少了 7 个百分点。 TypeScript 堪称逐年炽热,使用者出现逐年回升的趋势,再不学起来就说不过去。 近期OpenTiny做了一次大的降级,将原来运行了 9年 的 JavaScript 代码降级到了 TypeScript,并通过 Monorepo 进行子包的治理,还在用 JavaScript 的敌人能够放松降级了,这边特意筹备了一份《JS我的项目革新TS指南》文档供大家参考,顺便介绍了一些 TS 基础知识和 TS 在 Vue 中的一些实际。 通过本文你将播种: 通过理解 TS 的四大益处,压服本人下定决心学习 TS5 分钟学习 TS 最根底和罕用的知识点,疾速入门,包教包会理解如何在 Vue 中应用 TypeScript,给 Vue2 开发者切换到 Vue3 + TypeScript 提供最根本的参考如何将现有的 JS 我的项目革新成 TS 我的项目1 学习 TS 的益处1.1 益处一:紧跟潮流:让本人看起来很酷如果你没学过 TS 你的前端敌人:都 2023 年了,你还不会 TS?给你一个眼色你本人感悟吧 如果你学过 TS 你的前端敌人:哇,你们的我的项目曾经用上 Vue3 + TS 啦,看起来真棒!教教我吧 如果说下面那个益处太虚了,那上面的3条益处可都是实实在在能让本人受害的。 1.2 益处二:智能提醒:晋升开发者体验和效率当循环一个对象数组时,对象的属性列表能够间接显示进去,不必到对象的定义中去查问该对象有哪些属性。 ...

April 12, 2023 · 8 min · jiezi

关于typescript:重温Typescript

对TS有些陌生了,想着来总结一波,可作为日后工作中的疾速参考手册。 TypeScript具备类型零碎,且是JavaScript的超集。 它能够编译成一般的JavaScript代码。 TypeScript反对任意浏览器,任意环境,任意零碎并且是开源的。 TS是JS的超集,我的了解是:JS + 类型零碎 = TS,对于相熟JS的同学来说,TS的学习老本很低! 我的项目引入TS益处也很显著: 让程序更加强壮,更易保护。在编译器中的类型提醒让一些低级谬误在编译阶段就被发现。防止一些有效的沟通。据说你很会Ts? 来,让我看看!!初学者倡议移步 【TS中文网】 进行学习 若行文有误,欢送指出 一些筹备工作这些工作更多的是为了测试ts个性。当然这不是必须的,也能够到 Typescript练习场 去练习和测试。装置 typescript 和 ts-node 。前者是装置一个ts环境,将编译ts文件为js,不便查看其编译状况,后者反对终端运行ts文件。 npm install -g typescript # 全局装置 tstsc -v # 查看装置的版本# Version 5.0.3npm install -g ts-node # 全局装置 ts-nodets-node -v# v10.9.1新建一个名 summary 的目录,进入目录新建 helloTS.ts 文件。 mkdir summarycd summarytouch helloTs.ts下面步骤进行顺利的话,此时能够初始化目录、编译文件、运行文件了。 helloTs.ts里写下一点想法 const hello: string = '你好,ts, 我顶你个肺啊,哈哈哈'终端 tsc --init # 初始化,同目录下会生成 tsconfig.json 文件tsc helloTs.ts # 编译,首次运行会在同目录下生成 helloTs.js 文件,这外面就是编译的后果ts-node helloTs.ts # 执行 helloTs.ts 文件,有点像 node xxx.jstsconfig.json 文件定义着 会对哪些文件进行编译,如何编译(细则,束缚),见最初。 ...

April 8, 2023 · 13 min · jiezi

关于typescript:为什么你永远不应该在CSS中使用px来设置字体大小

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。 在Josh Collinsworth的博客文章“永远不要用px作为字体大小”中,作者探讨了为什么不应该应用像素(px)作为网页字体大小的单位[1]。作者指出,绝对于容器、浏览器或用户的字体大小,px值是动态的。无论用户的字体偏好设置如何,当咱们以动态像素设置值时,它将笼罩用户的抉择,以咱们指定的确切值代替。这意味着,如果我wu7的样式表应用像素单位,可能导致拜访网站的用户难以浏览。 因而,作者倡议应用绝对单位,如em、rem或百分比,而不是像素。这些单位是基于用户的字体大小偏好设置进行缩放的,从而提供了更好的可拜访性和可读性。尤其是在设计响应式网站时,绝对单位可能进步跨设施的兼容性。通过应用绝对单位,设计师能够确保网站在不同设施和浏览器中以适合的字体大小显示[1]。 上面是注释: 在 Web 开发畛域中,有很多误会流传,即便它们被反驳了很屡次也依然存在。"内部链接应该总是在新标签页中关上" 就是一个很好的例子。CSS Tricks 在将近十年前就对此进行了具体的解释(简而言之:大多数状况下是谬误的),但它仿佛依然在某些角落中存在。 案例证实:在CSS中, px , em 或 rem 单位之间没有性能上的区别的想法是一个我一遍又一遍听到的误会,因而我想在这里发帖来解决这个问题。 咱们要十分分明:在CSS中应用的单位相对很重要。并且在设置时 font-size 应尽可能防止应用 px 。 咱们在议论什么单位,它们是做什么的?在咱们探讨为什么应该防止应用 px 作为 font-size 之前,让咱们确保咱们都分明咱们正在议论哪些单位,以及它们的个别行为。 pxpx 是像素的缩写……尽管当初大多数状况下它不再是一个真正的像素。在显示器通常是一个绝对可预测的低分辨率像素比例,比方1024×768的时代, 1px 通常等于屏幕上的一个理论像素。 屏幕应用称为像素的黑白光点阵来显示图像。一个像素是显示器上的一个黑白光点;硬件可能出现的最小可能的“点”。这就是我在本节中所说的“字面上的”、“理论的”或“设施”像素;物理世界中的一个像素。然而,当高分辨率(有时称为“视网膜”)屏幕呈现时,设施开始将更多的像素压缩到更小的空间中,这些物理设施像素变得十分渺小。在高分辨率屏幕上浏览网页,如果CSS中的 1px 依然对应于一个字面设施像素,那么甚至浏览任何内容都将十分艰难,因为像素自身正在迅速放大。毕竟,古代智能手机的分辨率甚至比高清电视还要高。 所以当初, 1px 通常对应于放大的“缩放”像素的大小,而不是理论硬件上的字面像素。在咱们的 CSS 中, 1px 的货色可能会占用多个物理硬件像素,而咱们没有任何纯 CSS 的办法来指定一个字面设施像素。但这没关系,因为它们通常太小了,咱们不想去解决它们。 一个例子:iPhone 14 Pro 上的像素十分渺小,16px 在字面上的设施像素大小大概相当于2pt字号的印刷字体大小。好在浏览器为咱们缩放了它们!大多数状况下,这些并不在本探讨的语境中真正重要,但我认为理解这些还是很好的。重要的局部是: 1px 等于浏览器视为单个像素的任何内容(即便在硬件屏幕上它不是真正的像素)。 em 和 rem这就带咱们来到了 em 和 rem ,它们彼此类似。持续讲述不严格相干但依然乏味的小常识: "em" 是一个排版术语,实际上比计算机早了几十年。在排版上,一个 em 等于以后字体大小。 如果你将字体大小设置为 32pt(“pt”是另一个依然有时应用的旧排版术语),那么 1em 就是32pt。如果以后字体大小为 20px ,那么 1em = 20px。 ...

April 4, 2023 · 3 min · jiezi

关于typescript:在typescript项目中解决cycle依赖的一种方案

在typescript中,如果你不小心建设了相似以下两个文件,那么则会产生一个依赖正告。在个别的时候,还可能导致build失败的状况。 import Foo from "foo";export class Bar { private foo: Foo; barFun() { this.foo.xxx(this); }}import Bar from "bar";export class Foo { xxx(bar: Bar) { console.log("xxx"); }}此时因为 bar 中 import 了 foo, 而后 foo 又import 了 bar,所以产生了cycle. bar -> foo -> bar -> foo -> bar -> ... 此时咱们则可引入 interface 来解决这个循环的依赖. 引入interfaceexport interface BarInterface { barFun(): void;}import Foo from "foo";export class Bar { private foo: Foo; barFun() { this.foo.xxx(this); }}import BarInterface from "bar-interface";export class Foo { xxx(bar: BarInterface) { console.log("xxx"); }}此时,在进行引入时,则不会产生clcle了: ...

April 4, 2023 · 1 min · jiezi

关于typescript:历史性的时刻OpenTiny-跨端跨框架组件库正式升级-TypeScript10-万行代码重获新生

大家好,我是 Kagol,OpenTiny 开源社区经营,TinyVue 跨端、跨框架组件库外围贡献者,专一于前端组件库建设和开源社区经营。 微软于3月16日公布了 TypeScript 5.0 版本。微软示意新版本体积更小、开发者更容易上手且运行速度更快。 依据 The Software House 公布的《2022 前端开发市场状态调查报告》数据显示,应用 TypeScript 的人数曾经达到 84%,和 2021 年相比减少了 7 个百分点。 TypeScript 堪称逐年炽热,使用者出现逐年回升的趋势,再不学起来就说不过去。 咱们 OpenTiny 近期做了一次大的降级,将原来运行了 9年 的 JavaScript 代码降级到了 TypeScript,并通过 Monorepo 进行子包的治理,还在用 JavaScript 的敌人放松降级哦,我特意筹备了一份《JS我的项目革新TS指南》文档供大家参考,顺便介绍了一些 TS 基础知识和 TS 在 Vue 中的一些实际。 通过本文你将播种: 通过理解 TS 的四大益处,压服本人下定决心学习 TS5 分钟学习 TS 最根底和罕用的知识点,疾速入门,包教包会理解如何在 Vue 中应用 TypeScript,给 Vue2 开发者切换到 Vue3 + TypeScript 提供最根本的参考如何将现有的 JS 我的项目革新成 TS 我的项目1 学习 TS 的益处1.1 益处一:紧跟潮流:让本人看起来很酷如果你没学过 TS 你的前端敌人:都 2023 年了,你还不会 TS?给你一个眼色你本人感悟吧 ...

April 4, 2023 · 8 min · jiezi

关于typescript:浅析TypeScript中的命名空间

引言在 TypeScript 1.5 之前只反对命名空间的形式来组织代码,防止全局命名空间净化和命名抵触问题,在过后这是一种十分好的实际形式,尽管当初更举荐应用 ESModule 的形式来进行模块化地治理,然而应用 namespace 来结构命名空间的形式仍旧被应用,还是倡议大家学习下。 我这里会把过后学习和应用 namespace 时的一些纳闷列举进去,看看本人有没有不分明的点 namespace 的实现原理间接通过代码来看实现原理 namespace Qing { interface Person { name: string; age: number; } let name = "qing"; let age = 18; function createPerson(name: string, age: number): Person { return { name, age }; }}编译成 js 后 "use strict";var Qing;(function (Qing) { let name = "qing"; let age = 18; function createPerson(name, age) { return { name, age }; }})(Qing || (Qing = {}));简略地解释下,就是申明了一个全局变量,而后利用函数立刻执行表达式构建了一个部分的作用域,使得内部无法访问到命名空间中的变量和函数。 ...

April 2, 2023 · 2 min · jiezi

关于typescript:TypeScript中的枚举

引文枚举是 TypeScript 引入的新类型,在 JavaScript 中是没有枚举的。TypeScript 官网对枚举是这么定义的 Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.翻译过去的大略意思就是:开发人员能够利用枚举来定义具名常量汇合,应用枚举可能让人更快地记录代码用意或者是创立清晰的案例汇合。TypeScript 反对数字和字符串的枚举类型。 数字类型枚举如果枚举变量的所有成员没有进行初始化,那么第一位成员的值为 0,其它成员顺次递减。 enum E { X, // 0 Y, // 1 Z, // 2}如果枚举变量中有成员进行了初始化,那么在它后面的成员的值依照从 0 开始的形式顺次递减,在它之后的成员的值是在以后成员的数值根底上递减。 enum E { X, // 0 Y = 3, // 3 Z, // 4}这里有个须要留神的中央:没有初始化的成员须要放在首位或者是搁置在应用常量或常量表达式前面,例如上面应用函数来初始化的形式就会引发谬误。 ...

March 26, 2023 · 2 min · jiezi

关于typescript:加更-泛型加深理解-下饭下饭

大家好,这里是皮哥饭店,帮忙大家下饭,再不吃饱就要被赶回家啦。泛型的定义和作用泛型是 TypeScript 中的一种高级类型,它容许你在定义函数、类、接口时不指定具体类型,而是将类型作为参数传入,从而实现通用性更强的代码。 在学习泛型的时候,你须要理解以下概念: 泛型类型参数(type parameter):用于指定泛型类型的占位符。泛型函数(generic function):应用泛型类型参数的函数。泛型类(generic class):应用泛型类型参数的类。泛型束缚(generic constraint):用于对泛型类型参数进行束缚,以保障泛型类型参数的特定属性或办法存在。上面是一个简略的泛型函数示例: function identity<T>(arg: T): T { return arg;}在这个函数中,<T> 示意这是一个泛型函数,并且 T 是一个泛型类型参数。这个函数接管一个参数 arg,类型为 T,并将其一成不变地返回。 泛型函数的调用形式与一般函数相似,不同之处在于调用时须要指定具体类型参数: const result1 = identity<string>("hello");const result2 = identity<number>(123);在这个示例中,咱们别离调用了 identity 函数,并指定了具体的类型参数。第一个调用中,类型参数为 string,返回值类型也为 string;第二个调用中,类型参数为 number,返回值类型也为 number。 通过这个例子,你能够初步理解泛型的根本用法,包含泛型函数的定义和调用。接下来,你须要更深刻地理解泛型的应用和束缚。 泛型函数应用泛型函数应用泛型函数时,须要在函数名前面用尖括号(<>)指定类型参数。例如: function identity<T>(arg: T): T { return arg;}let output = identity<string>("hello world");在这个例子中,identity是一个泛型函数,类型参数为<T>,传入的参数和返回值都是类型T。在调用identity函数时,将类型参数指定为string,函数返回值为"hello world"。 泛型接口定义泛型接口泛型接口是一种能够指定参数类型的接口。定义泛型接口的语法如下: interface interfaceName<T> { propertyName: T;}这里的<T>示意一个类型参数,能够依据须要自定义类型参数的名称。泛型函数能够蕴含多个类型参数,每个参数之间用逗号分隔。 应用泛型接口应用泛型接口时,须要在接口名前面用尖括号(<>)指定类型参数。例如: interface GenericIdentityFn<T> { (arg: T): T;}function identity<T>(arg: T): T { return arg;}let myIdentity: GenericIdentityFn<number> = identity;在这个例子中,GenericIdentityFn是一个泛型接口,类型参数为<T>,接口中定义了一个承受类型为T的参数并返回类型为T的函数。在调用myIdentity函数时,将类型参数指定为number,函数返回值为一个number类型的值。 ...

March 26, 2023 · 3 min · jiezi

关于typescript:如何使用CSS创建高级动画这个函数必须掌握

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。咱们每天都在网上摸鱼,作为前端开发人员,网站上奥妙的细节变动通过比他人会更关注。我始终留神到的一件事是网站上的动画的流畅性。动画对于用户体验来说是十分好的,有时咱们能够一些乏味的动画来留住用户。 创立高级动画听起来是一个很难的话题,但好消息是,在CSS中,能够将多个简略的动画互相叠加,以创立一个更简单的动画 在这节课中,咱们会学习如下几点: 什么是贝塞尔曲线,以及如何用一行CSS来创立一个 "简单"的动画如何将动画互相叠加以创立一个高级动画如何通过利用下面学到的两点来创立一个过山车动画什么是贝塞尔曲线CSS中的 cubic-bezier 函数是一个缓动函数,能够让咱们齐全管制动画在工夫上的体现。上面是官网的定义: 贝塞尔缓动函数是一种由四个实数定义的弛缓函数,指定了贝塞尔曲线的两个控制点P1和P2,其端点P0和P3别离固定在(0, 0)和(1, 1)。P1和P2的x坐标被限度在[0, 1]范畴内。 什么是缓动函数?线性曲线设想两个点P0和P1,其中P0是动画的终点,P1是完结点。当初设想另一个点在两点之间线性挪动,如下所示 这就是所谓的线性曲线,也是最简略的动画。 二次贝塞尔曲线如下图所示,有三个点。P0、P1和P2。咱们想让动画从P0挪动到P2。在这种状况下,P1是一个控制点,管制动画的曲线。 二次方贝塞尔概念: 在P0和P1之间以及P1和P2之间(用灰线示意)连贯虚线点Q0沿着P0和P1之间的直线挪动。同时,点Q1沿着P1和P2之间的直线挪动在Q0和Q1之间连贯一条虚线(用绿线示意)在Q0和Q1开始挪动的同时,点B开始沿着绿线挪动,B点所走的门路就是动画门路 请留神,Q0、Q1和B不以雷同的速度挪动。它们都必须在同一时间开始,并在同一时间实现它们的门路。因而,每一个点都是依据它所挪动的线长以适当的速度挪动的。 三次贝塞尔曲线三次贝塞尔曲线由4个点组成。P0, P1, P2和P3。动画开始于P0,完结于P3。P1和P2是咱们的控制点。 三次贝赛尔的工作原理如下: 在(P0, P1)、(P1, P2)和(P2, P3)之间连贯虚线,由灰线示意点Q0、Q1和Q2别离沿直线(P0,P1)、(P1,P2)和(P2,P3)挪动在(Q0, Q1)和(Q1, Q2)之间连贯虚线,它们由绿线示意。点R0和R1别离沿直线(Q0, Q1)和(Q1, Q2)挪动连贯R0和R1之间的线(用蓝线示意)最初,B点沿着R0和R1之间的连接线挪动,B点所走的门路就是动画门路 如果你想更好地理解三次体贝塞尔的工作原理,倡议你看看这个desmos链接。玩玩控制点,看看动画如何随工夫变动。(留神,链接中的动画是由黑线示意的)。 叠加动画有很多步骤的大动画能够被分解成多个小动画。在 css 中,通过增加animation-delay属性来实现这一点。计算提早很简略,把你要计算动画提早的那个动画之前的所有动画的工夫加起来。 例如: animation: movePointLeft 4s linear forwards, movePointDown 3s linear forwards;这里,咱们有两个动画,movePointLeft和movePointDown。movePointLeft的动画提早是零,因为它是咱们想先运行的动画。movePointDown的动画提早是4秒,因为movePointLeft将在这段时间后实现。 因而,animation-delay属性: animation-delay: 0s, 4s;留神,如果有两个或更多的动画同时开始,它们的动画提早将是一样的。此外,当你计算行将开始的动画的提早时,把它们视为一个动。例如 : animation: x 4s linear forwards, y 4s linear forwards, jump 2s linear forwards;假如x和y同时开始。在这种状况下,x和y的动画提早都将为零,而 jump 动画的提早将为4秒(而不是8秒!)。 ...

March 21, 2023 · 2 min · jiezi

关于typescript:前端进阶在-Web-中使用-C我让学妹另眼相看

这是一个对于矩形排样问题和 WebAssembly 初体验的故事,但所有还要从真才实学的小学妹说起…… 1. 问题起因小学妹的课题须要写一个程序解决矩形排样(即二维矩形装箱)问题。 依据给定的一系列矩形,须要将它们打包到指定大小的二维箱子中,且要求任意两个矩形不能相交或蕴含。 问:如何排列矩形可使须要的箱子数量起码,且利用率最大? 这是一个极具现实意义的问题,在工业利用中十分重要,排样后果与经济利益密切相关。 同时,这也是一个NP-Hard问题——既无奈通过一个简略公式计算,也不可能将所有状况枚举(超级计算机也算不过去)。 2. 解决思路小学妹真才实学,而我对算法无所不通,因而只好借前人教训遮荫避凉。历经重重波折,终于找到一个 RectangleBinPack 库。它提供了一篇介绍二维矩形装箱问题的各种算法的文章,以及各种算法的具体实现。 对算法感兴趣的搭档能够自行获取 Wasm 仓库中的《算法介绍》文件理解。 Wasm 仓库传送器:https://github.com/ununian/RectangleBinPack-Wasm目前理解到,解决二维矩形装箱问题有 4 种算法,别离是:货架算法、断头台算法、最大矩形算法、天际线算法,每个算法都有一些策略选项。 小课题不必宰牛刀,我将问题简化,在此只思考一个箱子的状况。 3.计划抉择该库是用 C++ 写的,然而我对 C++ 并不相熟,所以须要用我所相熟的语言应用。在其余语言中应用 C++ 有两种计划: 第一,间接改写成对应语言,实用于简略的库。尽管这个库很适宜间接改写,但却无奈(在学妹背后)展示我的高超程度❌ 第二,将 C++ 库编译成动态库,再通过跨语言调用机制间接调用。这一看就是会吸引崇拜眼光的高端玩法,I WANT YOU!✅ 那么,要在哪个语言中应用这个库呢? 第一个想到的是 C#,毕竟在 C# 中调用 C++ 是很常见的操作,也有成熟的 Binding 工具(如 Swig);而且之前也做过这样的尝试,整体筹备工作量也会少一点。但应用 C# 有两个问题: 应用过程麻烦。毕竟是桌面程序,波及散发、装置、兼容性等。编译后果不跨平台。尽管 C++ 和 C# 自身都能跨平台,但须要针对每个平台都编译一次,而且 C# 的 GUI 局部跨平台写起来有点麻烦……紧接着,我想到了 WebAssembly——一个能够完满解决上述问题的计划,既不必放心跨平台,又能间接应用前端技术实现 GUI 局部。不便又高端,还能在小学妹背后装(消音),几乎非它莫属。 4. 具体实现4.1 环境需要最好应用 Linux 环境,能够防止许多奇怪的问题;如果是 Windows,能够试试 WSL。 装置 Emscripten。具体请参考 Download and install - Emscripten 2.0.27 (dev) documentation ...

March 20, 2023 · 4 min · jiezi

关于typescript:TypeScript-从零开始初体验

介绍● 百度百科介绍 TypeScript 是微软开发的一个开源的编程语言,通过在 JavaScript 的根底上增加动态类型定义构建而成. TypeScript 通过 TypeScript编译器 或 Babel 转译为 JavaScript 代码,可运行在任何浏览器,任何操作系统 ● 看了下面的介绍, 还是不太明确 TypeScript 是什么, 来看上面的例子 例子○ 一段很简略的 js 代码 // 封装函数, 求两数之和function and(a, b) { return a + b}接下来就调用一下试试const res = and(10, 20) ○ 这么简略的内容, 谁不会, 这玩意会有什么问题 ? ○ 咱们来思考一下, 假如这个函数你在调用的时候 ■ 你少传递了一个数字 ■ 你传递了一个字符串 ■ 会不会呈现问题呢 ?○ 你可能不禁要问 : 我为什么要少传递一个数字, 为什么要传递字符串呢 ? ○ 可能这个函数略显简略了一些 ○ 那么咱们在看一个略微简单一些的代码 var times = ''function move(ele, target, way) { clearInterval(times) times = setInterval(function () { var onOff = true for (let attr in target) { let now = parseInt(getPos(ele, attr)) let speed = (target[attr] - now) / 10 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if (now == target[attr]) { onOff = true } ele.style[attr] = now + speed + 'px'; } for (var tip in target) { if (target[tip] !== parseInt(getPos(ele, tip))) { onOff = false; break; } } if (onOff) { clearInterval(times); way && way(); } }, 30)}这个代码封装的是什么并不重要, 你不必焦急认真看他 ...

March 20, 2023 · 3 min · jiezi

关于typescript:一个公式让你35岁以后越过越好修炼心法

前言Cocos 的老铁,如果你这几天没有被麒麟子给卷到?那阐明你还没有真正进入 Cocos 圈子里来。为什么这么说呢?看上面。 3月1号 23:57 | 2800+字 麒麟子全方位解读 Cocos Cyberpunk 工程源码 - 开篇!3月2号15:54 | 3500+字 麒麟子全方位解读 Cocos Cyberpunk 工程源码 - 我的项目构造3月3号 23:08 | 15000+字 一文讲透游戏逻辑框架-麒麟子全方位解说Cocos Cyberpunk 工程源码3月6号 23:36 | 5800+字 抽离并复用自定义渲染管线-麒麟子全方位解说 Cocos Cyberpunk 工程源码3月7号 00:09 | 3900+字 手把手教你写 Shader 后效- 麒麟子全方位解读 Cocos Cyberpunk 工程源码3月9号 16:55 | 6800+字 一文讲透高中低端机型性能适配 - 麒麟子全方位解读 Cocos Cyberpunk 工程源码自 Cocos 赛博朋克我的项目 2月27号正式上线 Cocos Store 以来,麒麟子就像一只脱缰的野马,驰骋在赛博朋克的源代码外面,庖丁解牛般全方位火力输入教程已超过40000字。 这本不是麒麟子开发的游戏我的项目,他却如何对此如此地着迷?我除了对麒麟子的技术拜服的嗤之以鼻以外,晓衡还感觉到,我还发现了点什么——那就是 大神修炼之路! 大神 = 技术专家 × 影响力 × 变现思维忽然,晓衡有点按捺不住了,想分享分享近些年的一些思考和总结。 ...

March 15, 2023 · 2 min · jiezi

关于typescript:从零搭建一个前端开发环境配置eslintprettierhusky等代码规范检查工具

前端开发开发环境系列文章的 github 在这,如果您在看的过程中发现了什么有余和谬误,感谢您能指出! 上一篇讲了如何创立一个简略的开发环境搭建,然而在一个我的项目中,只有这些是不够的。每个人的代码品质不同,格局不同。所以须要用到代码标准校验eslint它次要性能蕴含代码格局校验,代码品质校验 1. 首先,装置eslintyarn add eslint -D(目前我用的是eslint v8.25.0, 高版本的eslint须要比拟新的vscode,不然eslint插件可能无奈工作) 2. 配置eslint规定和.eslintignore后面咱们用到了react和typescript,所以也须要装置一下对应的插件和解析器yarn add eslint-plugin-react @typescript-eslint/parser @typescript-eslint/eslint-plugin -D .eslintrc.js module.exports = { "env": { "browser": true, "es2021": true }, "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, "plugins": [ "react", "@typescript-eslint", ], "rules": { "arrow-body-style": "off", "prefer-arrow-callback": "off", "no-var": 2, "no-console": 1, "consistent-return": 1, "default-case": 1, "no-alert": 2, "no-irregular-whitespace": 0, "no-extra-boolean-cast": 0, "no-unused-vars": "off", "@typescript-eslint/indent": ["error", 2], // tab 缩进2空格 }}.eslintignore ...

March 11, 2023 · 2 min · jiezi

关于typescript:从零搭建前端开发环境ReactTsWebpack基础搭建

我的掘金前端开发开发环境系列文章的 github 在这,如果您在看的过程中发现了什么有余和谬误,感谢您能指出! 尽管目前市面上有很多的前端脚手架以及一体化的框架,比方create-react-app、umi等。然而作为一个程序员,本人写过更有助于晋升在开发过程中发现问题和解决问题的能力。 Webpack根底Webpack是一个动态模块打包器,它将所有的资源都看作模块。通过一个或多个入口,构建一个依赖图谱(dependency graph)。而后将所有模块组合成一个或多个bundle <div align="center"> <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f6c514b8cdf54d19b073a85dc297390a~tplv-k3u1fbpfcp-zoom-1.image" width = "300" alt="" align=center /></div> 能够通过一个简略的例子来初步理解Webpack 比方: 咱们想要应用es6的箭头函数来写一个性能,然而有的浏览器不反对(IE6-11或其余老版本浏览器)。那么这个用户在加载这个js资源的时候就会报错。 但这显然不是咱们想要的后果,这时候就须要用到webpack或像gulp这样的构建工具来帮忙咱们将es6的语法转化成低版本浏览器可兼容的代码。 那么用webpack来配置一个构建工具时如下: 创立一个目录,并yarn init初始化一个包管理器装置webpack yarn install webpack webpack-cli -D想要将es6转化为es5语法,须要用到babel插件对代码进行编译,所以须要装置babel和相应的loader yarn add @babel/core @babel/preset-env babel-loader -D配置.babelrc { "presets": [ [ "@babel/preset-env", { "modules": false } ] ]}创立src/index.js 入口 const sum = (a, b) => a + b;console.log(sum(1, 2))创立输入文件 dist/html <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <script src="./bundle.js"></script></body></html>而后就是配置webpack.config.js const webpack = require('webpack');const path = require('path');const config = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ } ] }};module.exports = config;最初通过构建命令./node_modules/.bin/webpack --config webpack.config.js --mode development 运行配置,会生成一个dist/bundle.js文件,这就是转换后的js文件/* * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). * This devtool is neither made for production nor for readable output files. * It uses "eval()" calls to create a separate source file in the browser devtools. * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) * or disable the default devtool with "devtool: false". * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). *//******/ (() => { // webpackBootstrap/******/ var __webpack_modules__ = ({/***/ "./src/index.js":/*!**********************!*\ !*** ./src/index.js ***! \**********************//***/ (() => {eval("var sum = function sum(a, b) {\n return a + b;\n};\nconsole.log(sum(1, 2));\n\n//# sourceURL=webpack://webpack-config/./src/index.js?");/***/ })/******/ });/************************************************************************//******/ /******/ // startup/******/ // Load entry module and return exports/******/ // This entry module can't be inlined because the eval devtool is used./******/ var __webpack_exports__ = {};/******/ __webpack_modules__["./src/index.js"]();/******/ /******/ })();下面这个例子就应用了webpack的几个外围概念 ...

March 11, 2023 · 7 min · jiezi

关于typescript:Matlab常用图像处理命令108例一

文章和代码以及样例图片等相干资源,曾经归档至【Github仓库:digital-image-processing-matlab】或者公众号【AIShareLab】回复 数字图像处理 也可获取。1.applylut在二进制图像中利用lookup 表进行边际操作。 语法: A = applylut(BW,lut) 举例 lut = makelut('sum(x(:)) == 4',2); BW1 = imread('text.tif'); BW2 = applylut(BW1,lut); imshow(BW1) figure, imshow(BW2) 相干命令: makelut 2.bestblk性能:确定进行块操作的块大小。 语法: siz = bestblk([m n],k) [mb,nb] = bestblk([m n],k) 举例 siz = bestblk([640 800],72) siz = 64 50 相干命令: Blkproc 3.blkproc性能:实现图像的显式块操作。 语法: B = blkproc(A,[m n],fun) B = blkproc(A,[m n],fun,P1,P2,...)B = blkproc(A,[m n],[mborder nborder],fun,...)B = blkproc(A,'indexed',...)举例 I = imread('alumgrns.tif');I2 = blkproc(I,[8 8],'std2(x)*ones(size(x))');imshow(I)figure, imshow(I2,[]); ...

March 11, 2023 · 3 min · jiezi

关于typescript:打不过AI就拉拢ChatGPT和MidJourney已成我小秘书

为了体验AI,晓衡这两周战斗力爆棚了! 每天大略睡了四~五个小时,而且中午也没有劳动过,但精力却还很亢奋。 直到周一下午,身材才有种被掏空的感觉,早晨 10 点就睡了。可能是兴奋劲还在,晚上不到 6 点就醒了,立马就有一种想去战斗的激动! 我想了想,还是算了,还是先好好总结一下,不要扯到蛋了。 01说真心话,之所以这么肝,次要是晓衡内心深处有一种,情不自禁的恐惧感! 2022 年底,大量公司疯狂裁员,很多公司连年会都没了。 企业为了存活上来,说不准,各种意想不到的事件就会落到本人身上。三体中有一句话说得很粗浅:我灭掉你,却与你无关! 晓衡负责的 Cocos Store 业务,尽管说在 2022 年有了些问题,但 Store 商城的流水又不抽成,还要代卖家向购买的用户提供发票,整个业务线对公司来说,齐全是亏损的。 而我这两年,技术齐全在 TM 地进化,我也放心那一天 Cocos 会不要我了。 所以 2023 开年来,我就开始要求本人,肯定要把之前欠下的债补上,老老实实从 Creator 3.x 的根底开始。 02因而,才有了前段时间,晓衡花了10天工夫写的一篇文章《Creator 3.x 入门修炼指南》。 并严格按文章中所说的进行修炼,在麒麟子《方块学生》教程根底上,编写一到两个本人的跑酷游戏来。 说到这里,我想给一些人泼点冷水! 因为在这段时间里,我收到一些初学者的反馈。 有些人是想要的太多,办法也太多,但大多数都停留在表面上,却做得很少。 罗翔老师说过这样一句话:我感觉人最大的苦楚,就是无奈逾越晓得和做到的鸿沟。 想通过,仅仅是看视频、抄抄代码、报个班什么的,就想学会游戏开发,能够说是痴心妄想,首先这个认知就是谬误的! 你想想,咱们从小到大,老师在讲台上亲面授课,学会了的有多少?而咱们身材中,先天成长进去的,能用于养家糊口的技能,它是怎么炼就进去的? 这个问题,真的值得去思考!来看下这张图——学习金字塔模型。 1964年埃德加.戴尔提出学习金字塔学习模型,起初成为美国缅因州的国家训练实验室研究成果。 该模型将学习分成两种:被动学习和被动学习。 钻研发现,一个人只是通过听讲、看书、看视频这类形式,接触到一个新的常识时,两周后,它在大脑中的留存率,最高不会超过 30%。 而通过对知识点的探讨,学习效果能达到 50% 以上,能亲自去实际应用它,能达到 75%。最好是能输入成绩来,就像我这样去做一个新的游戏,或是写一篇总结文章,甚至是去教其他人,这样的学习效果能达到 90%。 在实际的过程中,你会遇到各种意外,使用你原有的旧知,去驯服新知的过程中,让它们产生关联,并融合在一起,只有这样能力将新常识内化为本人身材的一部分。 说实话,这个过程在刚开始时是很苦楚的!但越是苦楚,你的播种将会越大。 因而,晓衡的想法是,先将《方块学生》中的知识点尽可能吃透、延长,做出本人的一款跑酷游戏来(玩法残缺的游戏 Demo),并要将它上线到微信或 Cocos Store 上。 只有将学习到的常识,应用起来且转化为经济价值,才算是实现了整个闭环。真的有了成绩,我才会进入下一个阶段,学习巧哥的《3D仰视角割草》。 03第二件事是对于 AI 的,想必大家都曾经感触到了!没玩过ChatGPT看上面。 AI都曾经能够写代码了,而且仅仅不到两月工夫,ChatGPT 在以肉眼可见的速度变得聪明起来。 下面说了,很多公司面临裁员求生存的地步,利用 AI 晋升企业效力,这将更加加剧一般打工人被淘汰的速度。 ...

March 9, 2023 · 1 min · jiezi

关于typescript:TypeScript类型编程中extends和infer

引文在刚接触TypeScript的时候,应用最多的就是type和interface这两个关键字,用来申明类型,其实这样也根本满足日常需要。然而如果须要设计一些高级类型的话,那么仅仅用原来所把握的TypeScript常识是无奈满足需要的。 设计高级类型的话波及到类型编程的知识点,而类型编程中有两个关键字十分重要,别离是extends和infer。 extends用来束缚入参的类型以及进行条件判断,infer用来申明部分的类型变量。 extends条件判断咱们举个简略的例子来阐明 type isOne<T extends number> = T extends 1 ? true : false咱们独自看T extends 1 ? true : false这部分,这里和JavaScript中的三元表达式并无二致,然而有些同学不分明其中extends示意的是什么含意。 T extends 1 ? true : false示意的含意其实就是传入的T类型是否可能赋值给字面量1这个类型,如果能够的话,就返回true,否则返回false束缚参数类型持续应用下面的例子,咱们独自看T extends number,这里extends的意思就是限度传入的T类型必须是number类型,否则报错。 为什么须要有这个限度? 因为咱们是要判断类型T是否可能赋值给字面量类型1,然而如果传入的参数都不是number类型,那么就没必要做后续的条件判断了。 束缚infer推导的局部变量类型type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest] ? `${FirstChar}` : never;type Res = GetFirst<['1', '2', '3']>;来看看报错信息,咱们传入的参数类型限度为sting类型的数组,然而infer推导进去的类型实际上是unknown类型,所以导致类型不匹配。 解决办法有三种: 对FirstChar应用extends先做过滤 type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]? FirstChar extends string ? `${FirstChar}` : never: never;FirstChar和string进行穿插运算 ...

March 8, 2023 · 2 min · jiezi

关于typescript:耗资百万的TPS第三人称射击『赛博朋克』游戏免费开源啦下载攻略奉上

Cocos引擎最近开源了《赛博朋克》游戏源码,这是一个TPS第三人称视射击游戏。 我的项目蕴含13W行源代码,50W外包美术资源,并且它演示了Cocos Creator引擎最新的渲染能力。 喜爱3D射击游戏与引擎渲染感兴趣的敌人,千万不要错过。 如果你还没有应用过 Cocos Creator 引擎,本文就带你从引擎的下载、装置、到游戏源码运行。只须要3分钟搞定,Let's Go! 01 下载 Cocos Dashboard关上浏览器,进入Cocos Store资源商城,间接到找 《赛博朋克》 游戏我的项目。 链接地址: https://store.cocos.com/app/detail/4543点击右侧获取按钮,注册登录你的 Cocos 账号。 输出账号密码,点击登录,胜利当前会主动返回资源页面。 再点击【获取】按钮会变成【创立新我的项目】。 持续点击按钮,这时会揭示你下载 Cocos Dashboard。 点击文字链接,返回下载 Cocos 引擎官网,下载安装 Cocos Dashboard。 这里简略说一下 Cocos Dashboard 是个什么东东? Cocos Dashboard 是用来下载和治理游戏引擎版本、游戏我的项目的工具,以及在 Cocos商城中下载游戏资源。 须要留神 Cocos Dashboard 、Cocos Creator引擎、Cocos Store和我的项目之间的关系。 02 下载游戏源码Dashboard下载实现后间接装置运行,启动 Dashboard 登录你的 Cocos 账号。 Cocos Dashboard 默认语言为英语,可点击右上角齿轮进入:设置->Language,可设置为简体中文。 点击右下角 【Back】 按钮保留返回,并回到之前的Web页再次点击【创立新我的项目】。 在弹出提示框中,点击【关上 Cocos Dashboard】。 ...

March 8, 2023 · 1 min · jiezi

关于typescript:layuivue-190-发布一个-Vue-3-UI-框架

本次推送,预示着这将是一个值得信赖的版本。 截至 1.9.0 公布,已在 Gitee 播种 1926 Star。实现 Issues 541 个。 冲破 npm 周下载 3000 次。 更新日志: [新增] input 组件 focus 与 blur 办法。 [新增] textarea 组件 focus 与 blur 办法。 [优化] select 组件开启多选,传递非 array 类型数据时的异样信息。 [优化] upload 组件裁剪框自适应图片尺寸。 [重要] upload 组件单文件上传,file 字段不再采纳 file [index] 格局。 [降级] layer-vue 到 1.6.0 版本。 更多详情: 随着 layui-vue 1.9.0 的公布,同时 layer-vue 也公布了 1.6.0 里程碑版本, 让咱们看看它带来了哪些变动? 独立网站:http://layer.layui-vue.com 新增 btn 按钮 disabled 配置,用于开启禁用状态,值得注意是,它具备响应式的能力。area 属性设置为 "auto" 时,它将自适应内容尺寸,包含动态资源。值得注意是,第二点间接改善了 upload 的裁剪框性能。音讯告诉款式重构,通过留白,间距解决,使其更具观赏性。加强 offset 属性,你能够通过 t l b r 四个字母的自由组合,体现出更多的内设地位和动画成果。 ...

March 8, 2023 · 1 min · jiezi

关于typescript:qiankun微前端从搭建到部署大型踩坑记录片一镜到底

前言近两年始终会有遇到须要微前端框架的需要,同时在招聘上,微前端的需要也是挺多的,最近整顿了一下之前经手过的几个qiankun微前端我的项目,分享给大家。 我的项目构造预览后期筹备工作 主利用的搭建、基座的配置。子利用template的搭建(react)。搭建主利用在workspace建设mirc-project目录来寄存主利用和微利用 mkdir mirc-project // 创立目录cd mirc-projectmkdir main // 创立主利用我的项目目录cd mainnpm init //初始化package.json为主利用装置qiankun yarn add qiankun根目录下新建src目录,并新建index.html,依据构造预览划分html构造,同时,新建index.ts文件,并在index.html援用,如下: <body> <div id="wrapper"> <div id="sidebar-slot"></div> <div id="container"> <div id="navbar-slot"></div> <div id="micro-app-wrapper"> <!-- loading icon --> <div id="loading-wrapper"> <div class="sc-bdnxRM cCKQJl"> <div class="sc-gtsrHT kzzTWM"></div> <div class="sc-gtsrHT kzzTWM"></div> <div class="sc-gtsrHT kzzTWM"></div> <div class="sc-gtsrHT kzzTWM"></div> </div> </div> <div id="micro-app-slot"></div> </div> </div> </div> <script type="module" src="./index.ts"></script></body>装置一下ts+react开发环境 yarn add --dev typescript ts-node react react-dom @types/react @types/react-dom ejs jest @types/ejs @types/jest下载babel yarn add --dev babel-jest @babel/core @babel/preset-env @babel/preset-typescript配置babel.config.json { "presets": [ ["@parcel/babel-preset-env", { "targets": { "node": "current" } }], "@babel/preset-typescript" ], "plugins": ["@parcel/babel-plugin-transform-runtime"]}为主利用增加一个打包的库,这里抉择Parcel, 以及微前端的一个库single-spa。 ...

March 6, 2023 · 7 min · jiezi

关于typescript:换个视角来看TypeScript中的交叉运算

引文置信只有接触过ts的同学就有理解穿插类型这两个概念,以前我对穿插类型感到十分纳闷,明明叫穿插类型,为何对对象类型应用了穿插运算后类型反而会进行属性的合并?不晓得大家有没有和我一样的困惑。这篇文章我会分享我最近感悟到的用不同视角来解释呈现上述问题的起因,如有谬误,恳请斧正。 穿插运算在ts中,应用&这个符号来对两个类型进行穿插运算,上面举几个小例子来开始解说。 例一type A = number & string // never例二type A = 1 & number // 1type B = "hello" & string // "hello"例三type A1 = {a: number}type A2 = {aa: string}这里的例子正是我在引文中提到的状况,依照穿插这个字面意思来了解,{a: number}和{aa: string}两个如同也没有什么交加,依照例一的思路来思考,后果应该是never,为何后果是{a: number, aa: string}? 首先来思考一个问题,假如有这么几个对象: {a: 1, b: 2}{aa: "11", bb: "22"}{a: 1, b: 2, aa: "11", bb: "22"}这几个对象别离赋值给类型为A1、A2、A的变量,哪个类型的变量在被赋值的时候有比拟大的可能会呈现谬误? 置信大家可能很容易的猜到答案,那就是下面的这三个对象在给类型为A的变量赋值的时候前两个对象都会报错,只有最初一个对象是合乎类型要求的。 上述中的A1、A2类型,A1类型的变量只须要值中有属性名为a,属性值类型为number的属性即可满足,而A2类型的变量只须要值中有属性名为aa,属性值类型为string的属性即可满足,而A类型的变量对值的要求是必须要同时有a和aa这两个属性。 那么合乎A1、A2、A类型的值各有几个?能够归类下 合乎A1类型的值:{a: 1, b: 2}、{a: 1, b: 2, aa: "11", bb: "22"}合乎A2类型的值:{aa: "11", bb: "22"}、{a: 1, b: 2, aa: "11", bb: "22"}合乎A类型的值:{a: 1, b: 2, aa: "11", bb: "22"}能够看到在A1 & A2后失去的A类型,其值绝对于A1和A2这两个类型对应的值的范畴是变小的,这也合乎穿插运算的后果趋势。 ...

March 2, 2023 · 1 min · jiezi

关于typescript:实践制作一个高扩展可视化低代码前端详实完整

RxEditor是一款开源企业级可视化低代码前端,指标是能够编辑所有 HTML 根底的组件。比方反对 React、VUE、小程序等,目前仅实现了 React 版。 RxEditor运行快照: 我的项目地址:https://github.com/rxdrag/rxeditor 演示地址( Vercel 部署,须要迷信的办法能力拜访):https://rxeditor.vercel.app/ 本文介绍RxEditor 设计实现办法,尽可能包含技术选型、软件架构、具体实现中碰到的各种小坑、预览渲染、物料热加载、前端逻辑编排等内容。 注:为了不便了解,文中援用的代码滤除了细节,是理论实现代码的简化版 设计准则尽量减少对组件的入侵,最大水平应用已有组件资源。配置优先,脚本辅助。根底性能原子化,组合式设计。物料插件化、逻辑组件化,尽可能动静插入零碎。 根底原理我的项目的设计指标,是可能通过拖拽的形式操作基于 HTML 制作的组件,如:调整这些组件的蕴含关系,并设置组件属性。 不论是 React、Vue、Angluar、小程序,还是别的相似前端框架,最终都是要把 JS 组件,以DOM节点的模式渲染进去。 编辑器(RxEditor)要保护一个树形模型,这个模型形容的是组件的附属关系,以及 props。同时还能跟 dom 树交互,通过各种 dom 事件,操作组件模型树。 这里要害的一个点是,编辑器须要晓得 dom 节点跟组件节点之间的对应关系。在不侵入组件的前提下,并且还要疏忽前端库的差别,比拟现实的办法是给 dom 节点赋一个非凡属性,并跟模型中组件的 id 对应,在 RxEditor 中,这个属性是rx-id,比方在dom节点中这样示意: <div rx-id="one-uuid"> </div>编辑器监听 dom 事件,通过事件的 target 的 rx-id 属性,就能够辨认其在模型中对应组件节点。也能够通过 document.querySelector([rx-id="${id}"])办法,查找组件对应的 dom 节点。 除此之外,还加了 rx-node-type 跟 rx-status 这两个辅助属性。rx-node-type 属性次要用来辨认是工具箱的Resource、画布内的一般节点还是编辑器辅助组件,rx-status 打算是多模块编辑应用,不过目前该性能尚未实现。 rx-id 算是设计器的基础性原理,它给设计器内核抹平了前端框架的差别,简直贯通设计器的所有局部。 Schema 定义编辑器操作的是JSON格局的组件树,设计时,设计引擎依据这个组件树渲染画布;预览时,执行引擎依据这个组件树渲染理论页面;代码生成时,能够把这个组件树生成代码;保留时,间接把它序列化存储到数据库或者文件。这个组件树是设计器的数据模型,通常会被叫做 Schema。 像阿里的 formily,它的Schema 根据的是JSON Schema 标准,并在下面做了一些扩大,他在形容父子关系的时候,用的是properties键值对: { <---- RecursionField(条件:object;渲染权:RecursionField) "type":"object", "properties":{ "username":{ <---- RecursionField(条件:string;渲染权:RecursionField) "type":"string", "x-component":"Input" }, "phone":{ <---- RecursionField(条件:string;渲染权:RecursionField) "type":"string", "x-component":"Input", "x-validator":"phone" }, "email":{ <---- RecursionField(条件:string;渲染权:RecursionField) "type":"string", "x-component":"Input", "x-validator":"email" }, ...... }}用键值对的形式存子组件(children)有几个显著的问题: ...

March 2, 2023 · 11 min · jiezi

关于typescript:使用Vite快速构建前端React项目

一、Vite简介Vite是一种面向古代浏览器的一个更轻、更快的前端构建工具,可能显著晋升前端开发体验。除了Vite外,前端驰名的构建工具还有Webpack和Gulp。目前,Vite曾经公布了Vite3,Vite全新的插件架构、丝滑的开发体验,能够和Vue3完满联合。  相比Webpack和Gulp等构建工具,Vite有如下一些劣势: Vite次要对应的利用场景是开发模式,跳过打包按需加载,因而更新的速度十分快;在大型项目上能够无效进步本地开发编译打包的速度,解决“改一行代码等半天”的问题;浏览器解析 imports,利用了 type="module"性能,而后拦挡浏览器收回的 ES imports 申请并做相应解决;闪电般的冷启动速度;即时热模块更换(热更新);真正的按需编译; 总的来说,Vite心愿提供开箱即用的配置,同时它的插件API和JavaScript API带来了高度的可拓展性。不过,相比Vue-cli配置来说,Vite构建的我的项目还是有很多的配置须要开发者本人进行解决。  Vite构建工具由两局部组成: 开发服务器:基于原生 ES 模块提供了丰盛的内建性能,如模块热更新(HMR)。构建指令:应用 Rollup 打包代码,并且它是预配置的,能够输入用于生产环境的优化过的动态资源。 同时,在浏览器反对方面,Vite也辨别了开发环境和生产环境: 开发环境:Vite须要在反对原生 ES 模块动静导入的浏览器中应用。生产环境:默认反对的浏览器须要反对通过脚本标签来引入原生 ES 模块。能够通过官网插件 @vitejs/plugin-legacy 反对旧浏览器。 二、环境搭建“工欲善其事,必先利其器”。首先,咱们须要的是代码编辑器和浏览器,举荐VSCode和Chrome浏览器。其次,是装置Node.js,如果还没有装置Node.js,能够从Node,js官网下载相应的安装包并手动装置。  Vite须要Node.js 12.0.0 及以上版本,如果低于这个版本,举荐装置一下nvm工具,而后装置多个Nodo.js版本并进行多版本切换。同时,Node.js自带的npm和yarn镜像源是在国外,因而包管理器方面我举荐应用 pnpm,或者应用上面的命令更改镜像源: pnpm config set registry https://registry.npmmirror.com/三、初始化我的项目环境搭建实现之后,接下来咱们就进入到我的项目初始化阶段。首先,在终端命令行中输出如下的命令: npm create vite在执行完下面的命令后,npm 首先会主动下载create-vite这个第三方包,而后执行这个包中的我的项目初始化逻辑。输出项目名称之后按下回车,此时须要抉择构建的前端框架: ✔ Project name: vite-project? Select a framework: › - Use arrow-keys. Return to submit. vanilla // 无前端框架 vue // 基于 Vue > react // 基于 React preact // 基于 Preact(一款精简版的类 React 框架) lit // 基于 lit(一款 Web Components 框架) svelte // 基于 Svelte此处,咱们抉择构建的框架为React。接着,执行如下命令在启动本地我的项目: ...

February 27, 2023 · 2 min · jiezi

关于typescript:可拖动滑块的实现-带有输入框支持百分比和数值两种显示模式

先看实现的成果:次要性能点:反对传入分组的组数,反对传入不同的色彩色条,可拖动左侧滑块扭转占比,可通过输出右侧input框实现更改占比,反对百分比和数值两种显示模式 间接上代码:正文写的很具体了: import React, { useEffect, useState } from 'react';import styles from './index.less';import { CaretLeftOutlined } from '@ant-design/icons';import { InputNumber } from 'antd';import Slider from 'rc-slider';import 'rc-slider/assets/index.css';import { bignumberFc } from '@/utils/bigNumber';type colorBlockProps = { groupCount: number; //分的组数 colorGroupArrayHex: string[]; //色彩色块的固定数组 type: 'percent' | 'value'; //百分比或数值的显示模式 min?: number; //数值显示模式的最小值 max?: number; //数值显示模式的最大值 currentColorBlockInfo?: { //保留的以后的组件的信息,还原时候须要 sliderValues: number[]; numberValues: number[]; groupRangeArrs: number[][]; }; // 最大值最小值变动的flag,因为我组件外层会有多个中央触发最大最小值的变动,避免反复渲染,所以传入一个flag去监听,而不是监听min和max minmaxChangeFlag?: string;};const ColorBlock: React.FC<colorBlockProps> = (props: colorBlockProps) => { const { groupCount, colorGroupArrayHex, type, min, max, currentColorBlockInfo, minmaxChangeFlag } = props; // 滑动条组件的values,实现是利用从从0到1,示意百分比,同时也是百分比模式下input框的显示值 const [sliderValues, setSliderValues] = useState<number[]>([]); // 数值类型的数组,它的值与sliderValues与min max 是一一对应的,是数值模式下input框的显示值 const [numberValues, setNumberValues] = useState<number[]>([]); // input输入框的层级数组,聚焦的时候把以后的input框的z值调大,避免被遮挡 const [zIndexArray, setZIndexArray] = useState<number[]>([]); // 拖动滑块的响应函数 const handleSliderChange = (values: number[] | number) => { let valueArray = values as number[]; if (valueArray.includes(0) && valueArray.includes(1)) { setSliderValues(valueArray); } }; // 更改inputNumber提早失效定时器 let timer: any = null; // input输入框手动输出的响应(百分比显示模式) const handlePercentInputChange = (index: number, value: any) => { const newSliderValues = [...sliderValues]; if (typeof value === 'number') { // 解决成整数并且勾销百分比模式 const newValue = Math.round(value) / 100; if (newValue < newSliderValues[index + 1] && newValue > newSliderValues[index - 1]) { newSliderValues[index] = newValue; } if (timer) clearTimeout(timer); timer = setTimeout(() => { setSliderValues(newSliderValues); }, 500); } }; // input输入框手动输出的响应(数值显示模式) const handleValueInputChange = (index: number, value: any) => { const newSliderValues = [...sliderValues]; const newNumberValues = [...numberValues]; if (typeof value === 'number' && max !== undefined && min !== undefined) { // 首先判断输出的范畴是否在相邻两个值的步长范畴内 if ( value < newNumberValues[index + 1] - (max - min) / 100 && value > newNumberValues[index - 1] + (max - min) / 100 ) { // 算出新的占比 newSliderValues[index] = (value - min) / (max - min); } if (timer) clearTimeout(timer); timer = setTimeout(() => { setSliderValues(newSliderValues); }, 500); } }; // 聚焦的input输入框永远在最上方,避免被遮蔽看不到信息 const handleInputOnFocus = (index: number) => { let newZIndexArray = [...zIndexArray]; for (let i: number = 0; i < newZIndexArray.length; i++) { if (i === index) { newZIndexArray[i] = 9999; } else newZIndexArray[i] = 1000; } setZIndexArray(newZIndexArray); }; // 初始化函数,若最大值最值,或分组的组数,或显示模式变动,则从新初始化 useEffect(() => { const initSliderValues: number[] = []; const initZIndexArray: number[] = []; for (let i: number = 0; i < groupCount + 1; i++) { initSliderValues.push(Math.round((1 / groupCount) * i * 100) / 100); initZIndexArray.push(1000); } setSliderValues(initSliderValues); setZIndexArray(initZIndexArray); }, [minmaxChangeFlag, groupCount, type]); // 因数值类型的数组,它的值与sliderValues与min max 是一一对应的,所以sliderValue变动的时候同时更新数值型的数组 useEffect(() => { if (sliderValues && min !== undefined && max !== undefined) { const newNumberValues: number[] = []; for (let i: number = 0; i < groupCount + 1; i++) { newNumberValues.push(min + (max - min) * sliderValues[i]); } setNumberValues(newNumberValues); } }, [sliderValues]); // 还原数据 useEffect(() => { if (currentColorBlockInfo) { setSliderValues(currentColorBlockInfo.sliderValues); setNumberValues(currentColorBlockInfo.numberValues); } }, []); // 组件的要害值的变动,将要害值 交给下层进行存储或者变更解决 useEffect(() => { const groupRangeArrs: number[][] = []; const newSliderValues = [...sliderValues]; const newNumberValues = [...numberValues]; // 百分比显示模式 if (type !== 'percent' && newSliderValues.length > 2) { for (let i: number = 0; i < newSliderValues.length - 1; i++) groupRangeArrs.push([newSliderValues[i], newSliderValues[i + 1]]); } // 数值显示模式 else if (type === 'percent' && newNumberValues.length > 2) { for (let i: number = 0; i < newNumberValues.length - 1; i++) groupRangeArrs.push([newNumberValues[i], newNumberValues[i + 1]]); } // 上面正文掉的为我本人的更新currentColorBlockInfo 的信息的办法,是交给下层进行解决,可依据理论状况本人去实现属性的存储,只需存储这三个属性即可 // { // sliderValues: sliderValues, // numberValues: numberValues, // groupRangeArrs: groupRangeArrs, // }, // setAttr( // { // colorBlockSlider: { // sliderValues: sliderValues, // numberValues: numberValues, // groupRangeArrs: groupRangeArrs, // // timeFlag:moment().format('YYYYMMDDHHmmss') // }, // }, // 'setOtherAttr', // ); }, [sliderValues, numberValues]); return ( <div className={styles.container}> <div> percent <Slider range step={0.01} min={0} max={1} count={groupCount} value={sliderValues} pushable={0.01} trackStyle={colorGroupArrayHex.map((item: string) => { return { width: 30, backgroundColor: item as string }; })} vertical reverse allowCross={true} onChange={handleSliderChange} /> <div> {sliderValues.map((item: number, index: number) => { return type !== 'percent' ? ( // 百分比显示模式 <div key={item} style={{ border: '0px solid #000', marginLeft: 30, marginTop: item === 0 ? -11 : 0, height: sliderValues[index] === 1 ? '1%' : `${(sliderValues[index + 1] - sliderValues[index]) * 100}%`, }} > <CaretLeftOutlined /> <InputNumber disabled={item === 0 || item === 1} size="small" value={item * 100} className={zIndexArray[index] === 9999 ? 'onFocusInput' : ''} precision={0} step={1} onChange={(value) => { handlePercentInputChange(index, value); }} onFocus={() => { handleInputOnFocus(index); }} ></InputNumber> <span>%</span> </div> ) : ( // 数值显示模式 <div key={item} style={{ border: '0px solid #000', marginLeft: 30, marginTop: item === 0 ? -11 : 0, height: sliderValues[index] === 1 ? '1%' : `${(sliderValues[index + 1] - sliderValues[index]) * 100}%`, }} > <CaretLeftOutlined /> <InputNumber // addonAfter={<span>%</span>} disabled={item === 0 || item === 1} size="small" style={{ width: 150 }} value={numberValues[index]} className={zIndexArray[index] === 9999 ? 'onFocusInput' : ''} precision={ numberValues.length > 1 ? bignumberFc .divide(bignumberFc.subtract(numberValues[numberValues.length - 1], numberValues[0]), 100) .toString() .split('.')[1] ? bignumberFc .divide(bignumberFc.subtract(numberValues[numberValues.length - 1], numberValues[0]), 100) .toString() .split('.')[1].length : 0 : 0 } step={ numberValues.length > 1 ? bignumberFc.divide( bignumberFc.subtract(numberValues[numberValues.length - 1], numberValues[0]), 100, ) : 1 } onChange={(value) => { handleValueInputChange(index, value); }} onFocus={() => { handleInputOnFocus(index); }} ></InputNumber> </div> ); })} </div> </div> </div> );};export default ColorBlock;ps:bigNumberFc是基于bignumber.js封装的更高精度的计算方法,也贴在上面: ...

February 27, 2023 · 6 min · jiezi

关于typescript:TypeScript-如何把数组转换为字符串字面量联合类型

想要把字符串数组转换为字符串字面量联结类型,能够先应用as const关键字定义只读字符串数组,而后对数组中的全副值应用typeof操作符。 // 只读的字符串数组const namesArr = ["John", "Lily", "Roy"] as const;// 把数组转换为字符串字面量联结类型type Names = typeof namesArr[number]; // "John" | "Lily" | "Roy"这可能须要一些工夫去了解产生了什么。因而让我带你一步一步地剖析:第一步,初始化字符串数组 // 字符串数组const namesArr = ["John", "Lily", "Roy"];咱们的指标是把它转换为字符串字面量联结类型接着,在TypeScript中必须应用as const关键字能力把数组转换为只读的在各个方面都是常量的数组。就像这样做: // 只读的字符串数组const namesArr = ["John", "Lily", "Roy"] as const;把字符串数组转换为只读模式之后,就不能在应用惯例的push, pop, slice等数组办法。它在各个方面都是一个常数而后,咱们须要把只读的数组转换为字符串字面量联结类型。为此咱们定义一个叫做Names的新类型,而后对namesArr数组的全副值都是用typeof操作符。如下所示: // 只读的字符串数组const namesArr = ["John", "Lily", "Roy"] as const;// 把数组转换为字符串字面量联结类型type Names = typeof namesArr[number]; // "John" | "Lily" | "Roy"当初你可能会问咱们为什么对namesArr应用number类型,这就是通知TypeScript编译器去获取来自于namesArr的所有编号的索引值,而后通过这些值去创立一个类型。因而,当TypeScript试图推断namesArr数组中蕴含的所有值的类型时,它将创立一种字符串字面量联结类型,因为数组中的所有值都是常量和只读的。最初,Names类型将蕴含如下内容: type Names = "John" | "Lily" | "Roy";这就是咱们想要的,当初就能够在TypeScript中应用Names类型 ...

February 27, 2023 · 1 min · jiezi

关于typescript:antd-table组件-勾选行-实现-单选可取消多选双击后只选中当前行的效果

敬爱的产品经理和boss,始终想要这样的一个成果表格中勾选行 实现 单选可勾销,多选双击后只选中以后行的成果基于我的项目中应用的antd table组件,听取了leader给出的计划倡议,算是实现了该性能最要害的是利用table组件中rowSelcton的rederCell属性,外围实现计划:利用renderCell在该地位渲染一个CheckBox,而该CheckBox可拿到以后的record的信息,可利用表格的rowKey去保护一份selectedKeys数组 1、CheckBox的变动会更新该selectedKeys数组,而CheckBox的选中与否的渲染也由该数组是否还有该行record的key来断定。 2、在CheckBox外层包裹一层div,div上绑定双击事件的监听,div也能够拿到该行record信息,响应事件去批改全局保护的selectedKeys数组来实现双击只选中以后行的成果 3、单选也利用CheckBox实现,不利用表格本身的单选性能 要害代码实现如下: PS:我的项目中利用了全局的状态治理来保护选中项的keys,命名为selectedValues,可依据本身状况更改 table组件中rowSelection的配置: rowSelection={{ selectedRowKeys: selectedValues, // PS:逻辑上来讲,这一行也不须要了,不过没有通过删除掉的测试,留着也没啥大问题 fixed: true, hideSelectAll: true, preserveSelectedRowKeys: true, renderCell(value, record, index, originNode) { return ( <div onDoubleClick={() => handleCheckBoxDoubleClick(record.key)}> <Checkbox checked={(selectedValues || []).includes(record.key)} onChange={(e) => handleCheckBoxChange(e, record.key)} ></Checkbox> </div> ); }, }}CheckBox的选中变动的响应: const handleCheckBoxChange = (e: CheckboxChangeEvent, recordKey: string) => { let newSelectedValues: string[] = selectedValues || []; // 多选模式 if (slicerSetting?.selectType === 'more') { //我的项目中断定用户抉择的多选模式或单选模式的setting,依据本身应用更改 if (e.target.checked) { newSelectedValues = [...newSelectedValues, recordKey]; // newSelectedValues.push(recordKey); } else { newSelectedValues = newSelectedValues.filter((item) => item !== recordKey); } } // 单选模式 else { newSelectedValues = e.target.checked ? [recordKey] : []; } //更新全局的选中项keys的数组 dispatch(setSlicerSelectedValues({ selectedValues: newSelectedValues as string[], chartId: chartId })); };多选模式下双击CheckBox的响应: ...

February 27, 2023 · 1 min · jiezi

关于typescript:基于-Pipeline-的-TSJS-API-代码自动生成apipgen

大家写我的项目的时候联调对接后端,写相应的 API 函数的时候会不会感觉很麻烦,我是这么感觉的,如果应用的 Typescript ,确保和后端的类型保持一致,还要手写类型,接口申请和返回参数定义类型成了繁琐的一件事件。 如果后端有提供接口形容的数据源(swagger、yapi 或其余源)等等,咱们就能够利用 aippgen 主动的生成接口与类型。 /** * @summary uploads an image * @method post */export function postPetPetIdUploadImage(data: FormData, paths: OpenAPITypes.PostPetPetIdUploadImagePath, config?: AxiosRequestConfig) { const url = `/pet/${paths?.petId}/uploadImage` http.request<Response<OpenAPITypes.ApiResponse>>({ url, data, ...config })}/** * @summary Add a new pet to the store * @method post */export function postPet(data: OpenAPITypes.Pet, config?: AxiosRequestConfig) { const url = '/pet' http.request<Response<void>>({ url, data, ...config })}export type Response<T> = T;export interface ApiResponse { code?: number; type?: string; message?: string;}export interface Category { id?: number; name?: string;}export interface Pet { id?: number; category?: Category; name: string; photoUrls: string[]; tags?: Tag[]; /** @description pet status in the store */ status?: string;}aippgen(API Pipeline Generator)是 API 生成工具,其中 Pipeline 是管道的意思,apipgen 通过不同的管道反对不同的源和输入格局,目前 apipgen 官网默认反对 swag-ts-axios、swag-js-axios 两种管道,反对自定义管道,不同管道间能够复用和重组。 ...

February 25, 2023 · 3 min · jiezi

关于typescript:算法思维体操基于generator生成器自己实现AsyncAwaitTypeScript

实现Async/Await要挑战的工作是应用JavaScript的generator生成器来实现Async/Await。 问题形容上面是一个Async/Await函数的示例。 async function doSomething(value) { const result1 = await fetchFromNetwork(value + '-1'); const result2 = await fetchFromNetwork(value + '-2'); try { const result3 = await failedFetchFromNetwork(); } catch (error) { console.error('Error fetching from network'); } return result1 + ' ' + result2;}doSomething('http://google.com') .then(r => console.log(`Got result: ${r}`)) .catch(console.error)咱们须要应用generator生成器和一个特地的封装函数“asynk”来实现同样性能。等效的示例为: const doSomething = asynk(function* (value) { const result1 = yield fetchFromNetwork(value + '-1'); const result2 = yield fetchFromNetwork(value + '-2'); try { const result3 = yield failedFetchFromNetwork(); } catch (error) { console.error('Error fetching from network'); } return result1 + ' ' + result2;});doSomething('http://google.com') .then(r => console.log(`Got result: ${r}`)) .catch(console.error)对于“asynk“的注意事项: ...

February 25, 2023 · 7 min · jiezi

关于typescript:vitetsvue3环境变量和模式配置

依据不同的模式,设置http接口申请地址的baseURL。依据我本人的了解记录一下,如有不正确的中央请斧正。先说一下配置的要求:在开发环境(执行命令vite dev/serve)下,接口地址能够在测试服务器和正式服务器之间切换。在生成环境(vite build)下,接口地址能够在测试服务器和正式服务器之间切换。 配置实现:1. 在根目录下新建文件://.env.development VITE_BASE_API = https://***-test.cn:8391//.env.production VITE_BASE_API = https://***.cn//.env.staging VITE_DEV_SERVER = https://***-test.cn:8391VITE_SERVER = https://***.cn2.在申请封装文件request.ts中援用 let baseURL = ''if(import.meta.env.MODE === 'staging') { // 准备模式 baseURL = process.env.NODE_ENV === 'development' ? import.meta.env.VITE_SERVER : import.meta.env.VITE_DEV_SERVER} else { // development或production模式 baseURL = import.meta.env.VITE_BASE_API}3.在package.json的scripts项增加以下命令 "scripts": { "dev:staging": "vite dev --mode staging", "build:staging": "run-p type-check build-only-staging", "build-only-staging": "vite build --mode staging",}4.应用 开发环境下应用正式服务器:npm run dev:staging生成环境下应用测试服务器:npm run build:staging环境和模式参考:https://cn.vitejs.dev/guide/e...https://cn.vitejs.dev/config/... 默认状况下,执行命令vite dev/serve(开发环境),运行在development(开发)模式;执行命令vite build(生成环境)运行在production(生产)模式。模式能够通过vite.config.ts中的mode选项配置。然而会把serve和build时的模式都笼罩掉。举荐通过命令行--mode选项来重写。 .env 文件Vite应用dotenv从环境目录中的下列文件加载额定的环境变量:环境目录:vite.config.ts的envDir选项可配置,默认root。 .env # 所有状况下都会加载.env.local # 所有状况下都会加载,但会被 git 疏忽.env.[mode] # 只在指定模式下加载.env.[mode].local # 只在指定模式下加载,但会被 git 疏忽比方:当执行vite build时,它会主动加载我的项目根目录下的.env.production中可能存在的环境变量。 ...

February 24, 2023 · 1 min · jiezi

关于typescript:使用springbootangular实现web端微信扫码登陆

概述当初微信的应用用户越来越多,如果网站增加上微信登录,就能节俭很多用户注册工夫,极大放大了注册流程。会让用户感觉特地不便。接下来咱们就说一下怎么来实现Web端微信扫码登录。 筹备工作1.实现内网穿透,举荐工具:飞鸽,疾速跳转2.申请微信公众平台测试账号并进行配置,点击查看更多 Websocket实时通信咱们通常有三种办法实现实时通信:1.ajax轮询 ajax轮询的原理非常简单,让浏览器每隔几秒就像服务器发送一个申请,询问服务器是否有新的信息.2.http 长轮询长轮询的机制和ajax轮询差不多,都是采纳轮询的形式,不过过来的是阻塞模型(始终打电话,没收到就不挂电话),也就是说,客户端发动链接后,如果没有音讯,就始终不返回response给客户端.晓得有新的音讯才返回,返回完之后,客户端再此建设连贯,周而复始.3.WebSocketWebSocket是HTML5开始提供的一种在单个TCP连贯上进行全双工通信的协定.在WebSocket API中,浏览器和服务器只须要做一个握手的动作,而后,浏览器和服务器之间就造成了一条快速通道。两者之间就间接能够数据相互传送,不须要繁琐的询问和期待. 比照:ajax轮询和长轮询都是十分消耗资源的,而WebSocket,只须要通过一次HTTP申请,就能够与服务端进行源源不断的音讯收发了.实现过程sockjsSockJS是一个浏览器的JavaScript库,它提供了一个相似于网络的对象,SockJS提供了一个连贯的,跨浏览器的JavaScriptAPI,它在浏览器和Web服务器之间创立了一个低提早,全双工,跨域通信通道. SockJS提供了浏览器兼容性,优先应用原生的WebSocket,如果某个浏览器不反对WebSocket,SockJS会主动降级为轮询. STOMPSTOMP(Simple Text-Orientated Messaging Protocol) 面向音讯的简略文本协定: WebSocket是一个音讯架构,不强制应用任何特定的音讯协定,它依赖于应用层解释音讯的含意.与HTTP不同,WebSocket是在传输层上进行数据实现和解决的,会将字节流转化为文本/二进制音讯,因而,对于理论利用来说,WebSocket的通信模式层级过低,因而,能够在WebSocket之上应用STOMP协定,来为浏览器 和 server间的 通信减少适当的音讯语义。 STOMP与WebSocket 的关系:1.HTTP协定解决了web浏览器发动申请以及web服务器响应申请的细节,假如HTTP协定不存在,只能应用TCP套接字来编写web利用.2.间接应用WebSocket(SockJS)就很相似于应用TCP套接字来编写web利用,因为没有高层协定,就须要咱们定义利用间发送音讯的语义,还须要确保连贯的两端都能遵循这些语义.3.同HTTP在TCP套接字上增加申请-响应模型层一样,STOMP在WebSocket之上提供了一个基于帧的线路格局层,用来定义音讯语义. 实战微信扫码登陆过程: 1.实现前后台WebSocket连贯:前台首先装置sockjs-client 和 stompjs: npm install sockjs-clientnpm install stompjs前台建设websocket连贯简略示例: const socket = new SockJS('http://localhost:8080/demo-stomp-endpoint'); const stompClient = Stomp.over(socket); stompClient.connect({ 'ws-auth-token': this.uuid }, (frame: any) => { // 增加个uuid, 用于后续进行debug,看是否为单例. stompClient.id = uuid(); this.stompClientSubject.next(stompClient); });前台注册路由,充当后盾被动拜访的接口: /** * 注册路由 * @param router 路由 * @param subject 后盾回发webSocket时发送数据流 */ register<T>(router: string, subject: Subject<T>): void { if (this.observables[router]) { throw new Error('未可能反复注册关键字' + router); } console.log('register'); this.stompClient$.pipe(filter(v => v !== null), first()).subscribe(stompClient => { stompClient.subscribe(this.getUrl(router), (data: any) => { console.log(data); subject.next(data); }); }); }2.后盾引入相干依赖: ...

February 11, 2023 · 2 min · jiezi

关于typescript:浅析依赖注入框架的生命周期以-InversifyJS-为例

在上一篇介绍了 VSCode 的依赖注入设计,并且实现了一个简略的 IOC 框架。然而间隔成为一个生产环境可用的框架还差的很远。 行业内曾经有许多十分优良的开源 IOC 框架,它们划分了更为清晰地模块来应答简单状况下依赖注入运行的正确性。 这里我将以 InversifyJS 为例,剖析它的生命周期设计,来弄清楚在一个优良的 IOC 框架中,实现一次注入流程到底是什么样的。 InversifyJS 的生命周期在激活 InversifyJS 后,框架通常会监听并经验五个阶段,别离是: Annotation 正文阶段Planning 布局阶段Middleware (optional) 中间件钩子Resolution 解析执行阶段Activation (optional) 激活钩子本篇文章将着重介绍其中的三个必选阶段。旨在解释框架到底是如何布局模块实例化的先后顺序,以实现依赖注入能力的。 接下来的解析将围绕如下例子: @injectable() class FooBar implements FooBarInterface { public foo : FooInterface; public bar : BarInterface; constructor( @inject("FooInterface") foo: FooInterface, @inject("BarInterface") bar: BarInterface ) { this.foo = foo; this.bar = bar; } } const container = new Container(); const foobar = container.get<FooBarInterface>("FooBarInterface");Annotation 正文阶段在此阶段中,框架将通过装璜器为所有接入框架的对象打上标记,以便布局阶段时进行治理。 在这个阶段中,最重要的 API 就是 injectable 。它应用 Reflect metadata,对 Class 构造函数中通过 inject API 注入的 property 进行标注,并挂在在了该类的 metadataKey 上。 ...

February 10, 2023 · 2 min · jiezi

关于typescript:教TSJS小白学习Puerts一把Puerts集成到Unity工程里

应用Puerts须要用到的JS/TS/Node.js常识 ts和js的关系:Puerts说简略点就是一个在c#运行时执行的js运行环境。ts是js的扩大语法,而且ts并不能间接执行(临时不能),理论执行的其实是由ts生成的js代码。typescript中文官网学习材料Node.js:Node.js是一个电脑命令行环境下执行js的运行环境,在我了解Node.js和js语言的关系相似于.net和c#的关系。为了将ts生成为js,你须要在开发电脑上装置Node.js。Node.js中文网地址。下载长期反对版即可。npm包管理器:npm全名Node Package Manager,装置完Node.js之后电脑中就有npm命令了。npm install命令能够从npm网站上下载并装置罕用的js依赖包。npm run命令能够执行在package.json中配置快捷命令。npm命令官网文档 package.json官网文档先写一个Hello World Puerts运行原理是在运行时将js文件的内容作为字符串传给JsEnv对象。所以咱们应将ts文件寄存在Unity工程的Assets文件夹以外,以防止Unity为ts生成.meta,而将ts生成的js文件生成在Assets文件夹内,以供Unity运行时加载。咱们先在Assets文件夹的同级创立一个TsProj文件夹,在命令行中运行cd到这个文件夹,并运行npm init命令,并始终回车到命令运行完结,这会创立一个package.json文件。 接下来装置依赖,运行命令npm install typescript @types/node webpack-cli,这会创立一个node_modules文件夹,外面寄存着typescript,@types/node,webpack-cli这三个依赖包以及他们各自的依赖包,其中typescript依赖包中蕴含一个tsc可执行文件,即是将ts生成js的命令文件。其余依赖包稍后用到再解释。此时关上package.json,会看到外面多了dependencies字段,外面列举了刚刚装置的依赖包和版本信息。 另外同级还会呈现一个主动生成的package-lock.json文件,这个文件是用于锁定本次装置所有依赖包的具体版本号,必须保留。如果应用git,也必须一起提交。下一步咱们手动创立一个名为tsconfig.json的文本文件,其中书写如下内容 { "compilerOptions": { "target": "esnext", "module": "CommonJS", "sourceMap": true, "noImplicitAny": true, "typeRoots": [ "node_modules/@types" ], "moduleResolution": "node", "outDir": "../Assets/Resources" }}这个文件会通知tsc命令如何生成js文件,如outDir指定了生成门路等等。tsconfig.json官网中文文档 这里咱们把js文件的生成门路选在Assets/Resources文件夹,这是为了在本文例子中不便Unity加载到代码,理论我的项目中咱们为了热更新,更多时候把js代码生成在Assets/StreamingAssets或其余地位期待打包成AssetBundle,这个我将在前面文章中具体阐明。 而后咱们手动编辑一下package.json文件,在scripts字段中退出如下内容 ..."scripts": { "dev": "tsc --watch", "build": "tsc"},...这里的dev和build就是定义了两个npm run快捷指令。比方当你命令行中,在TsProj文件夹下运行npm run dev,即等同于运行tsc --watch,即便你的电脑系统全局环境中不存在tsc这个命令,npm也会主动去以后文件夹的node_modules/.bin文件夹上来寻找tsc可执行文件。 而这个tsc --watch命令的作用即是把以后文件夹下的所有ts文件依照tsconfig.json中指定的规定生成为js文件。--watch的意思是实时监控以后文件夹的文件变动,并立即从新生成变动的文件。这个机制就非常适合写代码的时候开启,边写边生成,实时失效。这也是为什么咱们应用dev这个快捷词来代表这条命令。 npm build对应的理论命令是tsc,即只生成js而不监听变动。 筹备工作就绪,当初能够开始写ts代码了,创立index.cts文件,书写如下内容: console.log("hello world");index这个词在ts/js语言习惯中罕用来代表程序的入口 为什么后缀要用.cts而非.ts?因为.ts生成的js文件名是.js,又因为此范例中应用Puerts的默认Loader只能将js文件生成在Unity的Assets/Resources文件夹下,并应用Resources.Load函数加载文本资源,又因为Resources.Load不能辨认后缀为.js的文本资源。所以应用.cts生成进去的js文件名是.cjs,是为了不便Resources.Load函数辨认。同时,在Node.js的命名规范中,.cjs代表应用惯例js语法编写的js代码,.mjs代表应用新的es6语法编写的模块化js代码。所以应用.cts/*.cjs正好符合标准又合乎此处的须要。 后续文章中我会介绍如何在Puerts中应用自定义loader加载文本资源,那时就能够应用看起来失常一点的.ts和.js了 上面生成js,在命令行中执行npm run dev,此时命令行窗口进入继续监听状态,所以在后续开发过程中不要敞开这个窗口。如果须要运行其余命令就再开一个新窗口。此时查看Assets/Resources文件夹,该当曾经呈现了index.cjs文件,和index.cjs.map文件,.map文件是用于记录开发环境下js代码与ts代码中符号和行号映射关系的,个别是程序报错的时候才会用到。ts这边的配置和代码生成工作都实现了,下一步开始回到Unity这边。将Puerts插件引入Unity工程的Assets/Plugins文件夹。我这里应用的是github上间接下载的1.4.0 release的v8版。在Unity中关上一个空场景,在主相机上挂一个Test.cs脚本作为程序入口,在其中书写如下代码 using System.Collections;using System.Collections.Generic;using UnityEngine;using Puerts;public class Test : MonoBehaviour{ private JsEnv _jsEnv; void Start() { _jsEnv = new JsEnv(); _jsEnv.ExecuteModule("index.cjs"); }}此时查看Unity控制台输入 下集预报Hello world只是验证插件的可行性,想要将Puerts投入到商业我的项目的开发流程或生产环境中还须要定制很多方面的性能,例如实现ts文本资源的打包和热更新、ts与c#的互调传值、生成提醒文件和绑定代码、Inspector面板拖拽赋值等等。下一篇咱们从ts和c#互调开始缓缓道来。

February 8, 2023 · 1 min · jiezi

关于typescript:TS在实际开发中的使用

TS的根底应用// 数字let num = ref<number>(100)// 文字let str = rer<string>('文字')// booleanlet bo = ref<boolean>(true)// nulllet n = ref<null>(null)// undefinedlet u = ref<undefined>(undefined)// nanlet na = ref<NaN>(NaN)// 任意类型let a = ref<any>('任意类型') 数据类型不固定状况下的应用// 联结类型let s = ref<number | string>('文字') // 既能够保留文字也能够保留数字// 数字、boolean、数组等同理let s = ref<number[] | Array<string> | boolean>(true) TS在数组中的应用// 数字数组let numArr = ref<number[]>([1,2,3])let numArr2 = ref<Array<number>>([1,2,3])// 文字数组let strArr = ref<string[]>(['1','2','3'])let strArr2 = ref<Array<string>>(['1','2','3'])// 元组let arr : [string,number,boolean] = ['文字', 1 , true] ...

February 1, 2023 · 3 min · jiezi

关于typescript:不要用100vh做移动响应

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。一般来说,咱们应用 height:100vh 进行全屏布局,这是一种很不便的响应式办法。 .content { height: 100vh;}但当在理论设施上测试咱们的设计时,咱们遇到了几个问题。 大部分挪动端的Chrome和Firefox浏览器在顶部都有一个UI(地址栏等)。在Safari浏览器上,地址栏在底部,这就变得更加辣手了。不同的浏览器有不同大小的视口挪动设施计算浏览器视口为(顶栏+文档+底栏)=100vh整个文档应用 100vh 填充到页面中问题谷歌 已检测到滚动条问题。蹩脚的用户滚动和难以浏览的内容。 留神:在Safari上测试了这个问题,它更加蹩脚。 解决方案通过JS检测应用程序的高度const documentHeight = () => { const doc = document.documentElement doc.style.setProperty('--doc-height', `${window.innerHeight}px`)}window.addEventListener(‘resize’, documentHeight)documentHeight()应用 css 变量:root { --doc-height: 100%;}html,body { padding: 0; margin: 0; height: 100vh; /* fallback for Js load */ height: var(--doc-height);}最初后果 当初没有任何额定的垂直滚动条呈现,Safari也没有问题,这样的用户体验失去很大的晋升。 代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。 作者:nirazanbasnet 译者:前端小智 起源:dev 原文:https://dev.to/nirazanbasnet/... 交换有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

January 31, 2023 · 1 min · jiezi

关于typescript:Cocos-Creator-打包原生-Android-包该如何选择-NDK-版本

大家好,我是晓衡! 记得前段时间,在一些群里看到有小伙伴说 Cocos Creator 打包 Android 原生 APK 有问题:一种是构建失败,一种是运行起来报错。 晓衡也是有好长一段时间,没有碰过 Android 原生打包,我用的这台新电脑上环境都没有配置。 正好这两天,我将一个 2.0.10 的老我的项目,降级到了 Creator 3.6.2,并棘手测试了一下在 3.6.2 上打包 Android APK包。 不晓得为什么,出其不意的顺利,一次性构建胜利,装置到手机上运行也很丝滑。 起初我发现有个关键点,Android NDK 版本不能用太新的,Cocos官网文档中举荐在 r18 ~ 21 之间。 在此记录一下我的 Android 构建配置流程,如果有小伙伴,在打包 APK 遇到问题能够参考一下。 01 官网文档我在打包 Android 前,还是先认认真真地,看了下官网文档的。 《装置配置原生开发环境》 链接:https://docs.cocos.com/creato... 首先下载安装 Android Studio,下图是我装置好的版本:Android Studio Dolphin | 2021.3.1 装置好后,第一次运行 Android Studio 会有一大......顿的下载更新操作,须要有点急躁,基本上是跟着提醒来就行。 02 下载SDK 和 NDK依据官网文档,下载以后支流 Platform SDK,我这里下载的是 Level 33、Level 32 两个版本。 而后切换到 SDK Tools 这一页,装置最新版本的 Build-Tools,我这里显示的是 33.0.1。如果在你的电脑上,不是像上图这样显示的,勾选面板底部的 Show Packages Details 复选框,就能看到了。 ...

January 18, 2023 · 1 min · jiezi

关于typescript:TypeScript之接口

接口就是定义一个类型,比方一个json数据或一个函数等,形容其具体的构造就能够应用接口来标准。 根底阐明先来看个例子: interface MyDataType { name: string, age: number}咱们定义了一个json的数据格式,能够且只能够蕴含值是字符串的name属性和值是数字的age属性,上面是一个正确的例子: let myData: MyDataType={ name:"小明", age:19};可选属性如果咱们认为age是可选的,也就是 {name:"小明"} 也是正确的值,那么就能够这样调整: interface MyDataType { name: string, age?: number}只读属性如果你心愿name不被后续批改,也就是只读的,能够这样批改: interface MyDataType { readonly name: string, age: number}如果一个数组类型 Array 心愿标记是只读的,能够应用新类型 ReadonlyArray 进行代替。 函数类型比方咱们想定义一个函数,传递一个字符串和一个数字,返回一个字符串: interface DoitFunc { (name: string, age: number): string}上面是一个正确的例子: let doit: DoitFunc = function (name: string, age: number): string { return "姓名:" + name + ",年龄:" + age;}可索引的类型根底应用也就是那些能够通过 索引 失去值的类型,典型的就是json和数组。 interface MyDataType { [index: number]: string}舒适提醒:比方这里的index能够是任意非法的标志符,具体是什么并没有什么意义。比方上面的值就是非法的: ...

January 16, 2023 · 1 min · jiezi

关于typescript:TypeScript之类型断言

解释比方你定义了一个变量类型是any,可是你明确晓得此处其实在的值肯定是一个字符串,那么你就能够通知编译器,"置信我,这是一个字符串"。 应用类型断言有两种模式,咱们以下面字符串为例来演示。 尖括号let someValue: any = "this is a string";let strLength: number = (<string>someValue).length;as语法let someValue: any = "this is a string";let strLength: number = (someValue as string).length;两种模式是等价的,至于应用哪个大多数状况下是凭集体爱好,然而,当你在TypeScript里应用JSX时,只有as语法断言是被容许的。

January 14, 2023 · 1 min · jiezi

关于typescript:TypeScript之基础类型

和JS相比,TS最大的区别就是其标准了定义的变量的类型,使得程序在运行前就能够在语法层面来判断传递的数据类型是否是非法的等。 布尔值let isDone: boolean = true;数字所有数字都是浮点数,这些浮点数的类型是 number , 除了反对十进制和十六进制字面量,TypeScript还反对ECMAScript 2015中引入的二进制和八进制字面量。 十进制let decLiteral: number = 6;十六进制let hexLiteral: number = 0xf00d;二进制let binaryLiteral: number = 0b1010;八进制let octalLiteral: number = 0o744;字符串能够应用双引号( ")或单引号(')示意字符串。 let projectName: string = "notebook";数组let list: number[] = [1, 2, 3];或 let list: Array<number> = [1, 2, 3];元组 Tuple元组类型容许示意一个已知元素数量和类型的数组,各元素的类型不用雷同。 let x: [string, number] = ['hello', 10];枚举enum 类型是对JavaScript规范数据类型的一个补充。 根底应用enum Color { Red, Green, Blue}let color: Color = Color.Green;下面color的值是1,默认状况下,从0开始为元素编号。 当然,你也能够手动批改: enum Color {Red = 1, Green, Blue}或者,全副都采纳手动赋值: ...

January 14, 2023 · 1 min · jiezi

关于typescript:TypeScript知识笔记进阶

二.进阶1.类型推断: 如果没有明确的指定类型,那么 TypeScript 会按照类型推论(Type Inference)的规定推断出一个类型。 如果定义的时候没有赋值,不论之后有没有赋值,都会被推断成 any 类型而齐全不被类型查看: let myFavoriteNumber;myFavoriteNumber = 'seven';myFavoriteNumber = 7;2.联结类型: 联结类型(Union Types)示意取值能够为多种类型中的一种,应用" | "分隔每个类型。联结类型的变量在被赋值的时候,会依据类型推论的规定推断出一个类型。 let myFavoriteNumber: string | number;myFavoriteNumber = 'seven';myFavoriteNumber = 7;myFavoriteNumber = true;//index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.3.类型别名: 类型别名用来给一个类型起个新名字。应用 type 能够创立类型别名,类型别名罕用于联结类型。 type Name = string;type NameResolver = () => string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name { if (typeof n === 'string') { return n; } else { return n(); }} 当 TypeScript 不确定一个联结类型的变量到底是哪个类型的时候,咱们只能拜访此联结类型的所有类型里共有的属性或办法。 ...

January 13, 2023 · 3 min · jiezi

关于typescript:使用-TypeScript-定义业务字典

本文作者:htl业务字典在业务开发中,咱们经常须要定义一些枚举值。假如咱们正在开发一款音乐利用,咱们须要定义音乐的类型,以便在业务代码中进行业务逻辑判断: const MUSIC_TYPE = { POP: 1, ROCK: 2, RAP: 3, // ...};if (data.type === MUSIC_TYPE.POP) { // 当音乐类型为流行音乐时,执行某些逻辑}随着业务逻辑的扩大,简略的枚举值往往会衍生出许多关联的字典。比方,咱们须要定义一个音乐的类型对应的名称 const MUSIC_TYPE_NAMES = { [MUSIC_TYPE.POP]: '流行音乐', [MUSIC_TYPE.ROCK]: '摇滚音乐', [MUSIC_TYPE.RAP]: '说唱音乐', // ...};// 展现音乐类型名称<div>{MUSIC_TYPE_NAMES[data.type]}</div>或者须要定义一个音乐类型对应的图标: const MUSIC_TYPE_ICONS = { [MUSIC_TYPE.POP]: 'pop.svg', [MUSIC_TYPE.ROCK]: 'rock.svg', [MUSIC_TYPE.RAP]: 'rap.svg', // ...};// 展现音乐类型图标<img src={MUSIC_TYPE_ICONS[data.type]} />在列表场景下,咱们可能须要定义一个数组模式的字典: const MUSIC_TYPE_LIST = [ { type: MUSIC_TYPE.POP, name: '流行音乐', icon: 'pop.svg', }, { type: MUSIC_TYPE.ROCK, name: '摇滚音乐', icon: 'rock.svg', }, { type: MUSIC_TYPE.RAP, name: '说唱音乐', icon: 'rap.svg', }, // ...];<div> {MUSIC_TYPE_LIST.map((item) => ( <div> <img src={item.icon} /> <span>{item.name}</span> </div> ))}</div>;又或者心愿应用 key-object 模式防止从多个字典取值: ...

January 13, 2023 · 4 min · jiezi

关于typescript:基于-Winston-实现-NestJS-应用日志服务

引言申请日志与谬误记录是后端服务中不可或缺的一环,对谬误排查和保障利用运行稳定性具备积极意义。综合 GitHub 活跃度和 Nest 官网举荐的因素,决定将 Winston 作为 Nest 利用的日志服务模块,本文将演示如何在 NestJS 中接入 Winston,实现日志记录性能。 引入与配置 Winston相干依赖:winston、nest-winston、winston-daily-rotate-file 其中 winston-daily-rotate-file 用于实现日志文件的定期归档。因为利用日志量个别都十分大,因而须要定期主动对日志文件进行轮换、归档与删除。app.module.ts(主模块) import { // ... Module,} from '@nestjs/common';import { WinstonModule } from 'nest-winston';import * as winston from 'winston';import 'winston-daily-rotate-file';// ...@Module({ controllers: [], imports: [ // ... WinstonModule.forRoot({ transports: [ new winston.transports.DailyRotateFile({ dirname: `logs`, // 日志保留的目录 filename: '%DATE%.log', // 日志名称,占位符 %DATE% 取值为 datePattern 值。 datePattern: 'YYYY-MM-DD', // 日志轮换的频率,此处示意每天。 zippedArchive: true, // 是否通过压缩的形式归档被轮换的日志文件。 maxSize: '20m', // 设置日志文件的最大大小,m 示意 mb 。 maxFiles: '14d', // 保留日志文件的最大天数,此处示意主动删除超过 14 天的日志文件。 // 记录时增加工夫戳信息 format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss', }), winston.format.json(), ), }), ], }), ], // ...})export class AppModule { // ... } ...

January 13, 2023 · 3 min · jiezi

关于typescript:变量声明

TypeScrpt中变量申明次要有三种形式:var,let和const。 var申明讲讲var的特点1.变量晋升2.可反复申明,后申明笼罩前申明3.var的作用域,来看上面的例子: function f(flag:boolean) { if(flag) { var x = 10; }}f(true); // returns "10"f(false); // returns "undefined"能够看到,咱们将变量X定义在if语句内,然而却能够在if语句里面拜访它。这是因为var申明能够在蕴含他的函数,模块命名空间或全局作用域外部的任何地位被拜访。此为var作用域或函数作用域,函数参数也应用函数作用域。 let申明let与var的写法统一 let hello = "Hello!";次要区别在语义上。 块作用域当用let申明一个变量,它应用的是词法作用域或块作用域。var申明的变量能够在蕴含他们的函数外拜访,与var不同的是,块作用域变量在蕴含他们的块或for循环之外是不能拜访的。来看上面的例子: function f(flag:boolean) { let a = 100; if(flag) { let b = a + 1; return b; } return b; // 报错}咱们在函数外部用let定义了a,b两个变量。a的作用域是f函数体内,而b的作用域是if语句内,if语句内能够拜访a,然而if语句外无法访问到b,因而在if语句外拜访b会报错。 块级作用域的特点之一是没有变量晋升,也就是不能在被申明之前读写,这也是与var不同的中央。 const申明const也是申明变量的一种形式。 const = 3.14const领有与let雷同的作用域规定,然而不能对他们从新赋值。 const age = 18;const Tom = { name: "Tom", age: age };//报错Tom = { name: "Jerry", age: age};//okTom.name = "tom";Tom.age--;通过以上例子不难看出,在给Tom从新赋值对象时报错,然而批改Tom的属性值时失常运行。这是因为const定义的变量的不能批改的含意是不能批改变量的援用。如果const定义的变量为简略数据类型:字符串、数字等类型,不能批改;如果const定义的变量为简单数据类型:对象、数组等,不能批改其援用,但能够批改其属性的值。 ...

January 12, 2023 · 2 min · jiezi

关于typescript:TypeScript的基础类型

布尔值(Boolean)最根本的数据类型就是布尔值 true/false let isDone: boolean = true;字符串(String)let myString: string = "字符串";数字(Number)和javascript一样,typescript中的所有数字都是浮点数。这些浮点数的类型是number,除了反对十进制和十六进制意外,typescript还是引入了ECMAScript 2015中引入的二进制和八进制字面量。 let decLiteral: number = 6;let hexLiteral: number = 0xf00d;let binaryLiteral: number = 0b1010;let octalLiteral: number = 0o744;数组(Array)数字类型数组 let numList: Array<number> = [1, 2, 3]; 字符串类型数组 let stringArr: string[] = ['1', '2', '3'];数字类型的泛型数组 let numList: Array<number> = [1, 2, 3]; 元组(Tuple)元组类型容许示意一个已知元素数量和类型的数组,各元素的类型阔以不雷同 let x: [string, number, string];x = ["张三", 10, "岁"];枚举(enum)enum类型是对javascript类型的补充,阔认为一组数赋予敌对的名字,默认从0开始编号。 enum Color {Red,Green,Blue};能够手动指定成员的数值,从1开始比编号 enum Color { Red = 1, Green, Blue }; let c: Color = Color.Green;也能够全副手动赋值 ...

January 12, 2023 · 1 min · jiezi

关于typescript:Creator-2x-升级-3x-基础-API-差异总结

上一篇咱们介绍了 Cocos Creator 2.x 我的项目降级 3.x 的大流程。 但最初一步,还须要手动将之前 2.x 写的函数正文一处处的放开。 并将 2.x 的代码写法改成 3.x 的,上面咱们就来看一下有那些差别。 1. 模块引入在 Creator 3.x 中废除了 cc.Node、cc.Sprite 这种全局模式的 API 调用。 取而代之的是,先要在脚本顶部 import 模块,代码如下: //从 cc 模块中解构出 Node、Sprite 变量import { Node, Sprite } from 'cc'好在 VSCode 编辑器,它会主动帮忙咱们增加 import 模块。 但你须要先在 3.x 引擎主菜单 开发者→Export.d.ts 装置 VSCode 提醒文件,看下图: 2. Node 根底属性变动Creator 3.x 中 Node 的属性变的极其的简洁了,只剩下 position、rotation、scale 这三个属性被保留。 而且它们都变成了 Vec3 类型,看上面应用办法。 设置节点地位//Creator 2.xthis.node.position = v2(100, 100)this.node.x = 100; //3.x中不可用this.node.y = 100; //3.x中不可用//Creator 3.x 中不能应用x、y、z重量设置节点地位//须要应用 position 属性或 setPosition 办法this.node.position = v3(100, 100, 100);//留神须要同时设置 xyz 三个重量this.node.setPosition(100, 100, 100);设置节点缩放//Creator 2.xthis.node.scale = 1.5;//Creator 3.x //留神 scale 不在是一个 number 而是 Vec3this.node.scale = v3(1.5, 1.5, 1.5);//留神 须要同时设置 xyz 三个重量this.node.setScale(1,1,1);节点在二维上的旋转//Creator 2.x rotation 属性在 2.3.x 之后是应用 angle 属性this.node.angle = 1.5;//Creator 3.x//节点的 rotation 属性其实是一个 Quat 类型//2D节点在属性查看器中的 rotation //对应的是节点的 angle 属性this.node.angle = 10//也能够应用 eulerAngles 来设置,留神它是设置的Z轴的旋转this.node.eulerAngels = v3(0, 0, 10);3. 节点色彩与通明咱们在 3.x 场景中增加一个 2D 精灵,你能够看到,节点的色彩与通明,曾经拆散到别的组件上了。 ...

January 11, 2023 · 2 min · jiezi

关于typescript:domvcr-纯客户端的录制-DOM-动画生成-GIF-MP4

装置npm i dom-vcr 应用录制 2s 生成 4 帧 GIF须要装置 gif.jsimport { createVcr } from 'dom-vcr'import GIF from 'gif.js'const dom = document.querySelector('#app')const vcr = createVcr(dom, { interval: 500, gif: new GIF({ workerScript: './node_modules/gif.js/dist/gif.worker.js', }),})vcr.record(2000) .then(() => vcr.render()) .then(blob => { window.open(URL.createObjectURL(blob)) })手动加帧生成 GIF须要装置 gif.jsimport { createVcr } from 'dom-vcr'import GIF from 'gif.js'const dom = document.querySelector('#app')const vcr = createVcr(dom, { interval: 1000, gif: new GIF({ workerScript: './node_modules/gif.js/dist/gif.worker.js', }),})async function generate() { dom.style.backgroundColor = 'red' await vcr.addFrame() dom.style.backgroundColor = 'yellow' await vcr.addFrame() dom.style.backgroundColor = 'green' await vcr.addFrame() const blob = await vcr.render() window.open(URL.createObjectURL(blob))}generate()CDN<script src="https://unpkg.com/dom-vcr"></script>github https://github.com/qq15725/do... ...

January 10, 2023 · 1 min · jiezi

关于typescript:独立产品灵感周刊-DecoHack-043-互联网从业者的灵感数据库

本周刊记录乏味好玩的独立产品设计开发相干内容,每周公布,往期内容同样精彩,感兴趣的搭档能够点击订阅我的周刊。为保障每期都能收到,倡议邮件订阅。欢送通过 Twitter 私信举荐或投稿。很完满的断更了2期,有一期是因为我新冠之后切实是懒没有更新,还有一期欠了很多工作在补作业,切实太懒没有更新,不过周刊还是会始终持续做的,往年争取不会断更太屡次(感激各位读者关注)早退的年度产品总结,让我再拖几天。另外,本期内容还是干货挺多,值得花点工夫看看。 产品举荐1. Notion converter - 笔记转换工具想在Notion中实现公众号的写作?Notion Converter帮你一键排版复制到公众号。感兴趣的敌人能够看看作者写的介绍文章。 2. EarlyBird这是个零代码制作 landing page 的产品,制作很不错的出海产品,作者正在 Twitter 上尝试 build in public,也在 V2EX 上公布了 Product Hunt 公布心得,如果有同样想要公开构建产品,或者打算利用出海的敌人,能够关注作者@LuoBaishun。 3. 小报童专栏导航这网站是一个集体作品,和小报童官网无关。作者整顿了小报童上一些好的内容,用户通过此网站的链接付费订阅专栏后,小报童导航将会取得一部分收益,以此来反对经营。这个玩法还是挺有意思的。作者还做了微信小程序。 4. CloakApp作者 @ezzz_au 公布的一款小工具 CloakApp, 能够将指定的 App 从 iPhone / iPad 上暗藏,主屏幕、App 资源库和告诉等都不再显示这些应用程序, 直到您将它们还原。「安全区」性能可在您来到住处或工作场合时自动隐藏选定的利用。应答「查手机」更加从容。 5. BeforeSunset:工作工夫管理工具BeforeSunset 最后是一款工夫跟踪软件,之后演变成了工作工夫管理工具。BeforeSunset 的次要场景是企业主监控灵便用工员工的工作时长,以及Freelancer统计本身工作时长以向甲方索要报酬。海内同类型产品还有一家名为 ActivTrak,它号称是生产力剖析工具,其实是通过截屏和录屏来理解员工的工作状况,在对隐衷如此器重的美国,ActivTrak 也曾经做到了B轮累计融资7000万美元,可见这一类产品如许刚需。目前 BeforeSunset 只提供Web版本,挪动版本还在研发中,其根底版收费,但只反对最多三名员工;专业版定价为3.9美元/月/人。 6. All Things Al - 人工智能工具和服务的导航一个精选的 AI 工具列表,分类内容十分多,帮忙人们开始应用 AI。 7. Hollywood Age Gap 好莱坞年龄差距这个网站十分有意思,整顿了好莱坞的电影中情侣之间的年龄差距。 ...

January 9, 2023 · 1 min · jiezi

关于typescript:TS-函数重载你还不会来我教你

前言: 明天在我的项目中遇到了后端接口参数类型和接口返回值须要批改的场景,因为这个函数在很多页面都用到了,就导致改完相干 api 函数的时候 TS 疯狂报错,所有的参数和返回值都须要跟着改,一时间头疼。正当我不知所措的时候,忽然想到之前看 vue 源码的时候看到 函数重载 的应用,于是我第一次在我的项目中应用了函数重载,完满解决了我的问题。 一. 场景再现咱们先不要想函数重载是什么意思,咱们从具体场景一步一步去理解这个名词的含意,你会了解的更粗浅。假如当初后端有一个接口,能够通过一个 ID 来获取用户信息。那么前端对应的 api 可能就有这样一个函数,当初还有一个接口,就是通过很多个 ID 来获取很多个用户的信息。那么这个函数就可能被设计成这样子。等等,先别着急喷。别说是你,我本人看着都感觉这种形式很蠢,为什么不把它设计成一个函数呢?哎,对哈,那咱们就入手革新一下这两个函数。既然参数类型不同,那么后端对应的返回值类型必定也是不一样滴,咱们还须要设定一下返回值类型。咱们顺手定一个一个 interface 来示意这个后端接口返回给咱们的数据类型。所以当初咱们的函数就变成了上面这个样子。这时候就须要前端手动去判断传递的参数到底是单个字符串还是一个字符串数组。乍一看感觉还挺好,然而你会发现当你在调用这个函数的时候,TS 的类型提醒如同不是那么对劲。什么意思呢?咱们间接调用这个函数看一下类型晋升当初是什么样子的。你可能会说,你骗谁呢?这类型提醒不是好好的吗?别着急,容咱们再申明一个变量筹备接管这个函数的返回值。当初我在一个组件外部很明确的晓得我要发送一个 ID数组 去获取很多用户的数据。那么我能够很分明的定义咱们的变量就是 DataType[] 的类型。(这里须要特地揭示:尽管当初我只产生了一个用户的数据,然而后端依据我的参数类型是一个数组,仍会返回一个数组类型的用户数据给我,即便那个数组只有一条用户数据。)那么咱们就能够很天然的写出上面的代码。随之你就会发现 TS 飘红了,你函数的返回值类型和变量定义时候规定的类型不合乎。谬误起因很简略,就是咱们人类的直觉。咱们很聪慧的认为,我给你传递的如果是一个字符串,那么你这个函数就应该很听话的给我返回 一 个用户信息就完事了。我给你这个函数如果传递的是一个字符串数组,那么我就是我想获取多个用户的信息,你就应该给我返回一个信息数组。然而很道歉 TS 没有这么智能,它的确不晓得你到底是想一个一个字符串 返回==>一个数据,还是 一个字符串 返回==> 多个数据。是的,TS 目前只晓得你的参数只有两个类型,你的返回值只有两个类型,然而它不晓得你的参数对应的你想返回哪个类型。二. 解决飘红的办法那么咱们如何解决目前 TS 飘红的问题呢?第一种办法也是最简略的办法,间接应用 TS 类型断言 as 关键词,明确的通知 TS 你这个函数的返回值是什么。as 的作用你能够类比于 CSS 中的 important ,我十分确定这个变量的类型是什么,不须要 TS 帮我做类型推导。这也是我最开始应用的办法,也是我最常常应用的办法。你可能也看进去了,这样的话我就须要在每一个应用这个函数的中央都 as 一下,十分十分笨也不优雅。那有没有什么办法让 TS 变聪慧一点,让它帮我主动分辨我各个参数对应什么返回值呢?你别说,还真有,引出咱们的配角----函数重载。三. 什么是函数重载(overload)在引出函数重载之前咱们须要理解一个前提常识,在 JS 里同一个函数是能够被申明屡次的,后果是会优先采纳最初一次的函数体。什么意思呢?如下图,这是一个 .js 文件,JS 不仅不会报错,并且还能够失常执行。然而在 TS 里这种形式是会引发类型报错的。尽管 TS 只是会揭示类型谬误,不影响这个文件的最终运行。然而明眼人都能够看出哪种开发模式更加适宜团队单干。很显著 TS 更加合乎咱们的直觉,不容许变量在同一作用域下屡次赋值。所以 JS 是没有重载签名这个概念的,这是 TS 所给你带来的劣势。对于函数重载更加粗浅的实现原理,因为应用的不多我临时无奈给你深刻解说原理,在这里我仅谈一谈目前我集体了解,可能有些大白话,然而应该能够帮你先浅浅的理解这个名词。 ...

January 8, 2023 · 1 min · jiezi

关于typescript:Typescript中类型Record的使用

咱们能够先来看一下源码是什么 /** * Construct a type with a set of properties K of type T */type Record<K extends keyof any, T> = { [P in K]: T;};能够把K类型转化为T类型。也就相当于一个K到T的映射表,能够依据传入的K值去查表返回对用的T值。而他的模式就是把K当作键值来获取T。咱们天经地义能够只是简略的减少对应关系,只实现将输出key值,输入相应对象的简略操作:demo1: interface EmployeeType { id: number fullname: string role: string} let employees: Record<number, EmployeeType> = { 0: { id: 1, fullname: "John Doe", role: "Designer" }, 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" }, 2: { id: 3, fullname: "Sara Duckson", role: "Developer" },} // 比方咱们想获取1对应的Employee,employees[1] => { id: 2, fullname: "Ibrahima Fall", role: "Developer" }然而咱们更多的应用这种办法去依据输出调用相应解决办法,使代码更加标准。比方咱们有三种角色,某个办法要求当传入不同角色时进行不同解决,然而办法可能比较复杂,咱们想方便管理并且想尽可能的简洁(不采纳大量ifElse),咱们就能够采纳如下形式。demo2: ...

January 4, 2023 · 1 min · jiezi

关于typescript:ts-高级工具类

关键字,技巧理解keyof,用来获得一个对象接口的所有 key 值interface Point { x: number; y: number;}// type keys = "x" | "y"type keys = keyof Point;in 则能够遍历枚举类型type Keys = "a" | "b"type Obj = { [p in Keys]: any} // -> { a: any, b: any }typeof 用来获取根本数据的类型let p = { name: 'zs', age:10}function p1(parmas: typeof p) { //它会去解析p。 而后变成 parmas : { name:string, age:number} console.log(p.age) console.log(p.name)}p1(p)留神只能用来查问变量或者属性的类型。无奈查问其余模式的类型。比如说:返回调用的类型。 extends 条件语句 extends可能用来继承一个class、interface,还可能用来判断条件类型 T extends U ? X : Y// T U X Y 四个是占位符,别离示意四种类型;// T extends U 示意 T类型能被赋值给U类型,,这里还波及到TS类型兼容性;// 条件类型的散发个性(再续)infer 申明一个变量来承载extends条件语句中的某些待推断的类型infer语法的限度如下: ...

December 29, 2022 · 4 min · jiezi

关于typescript:TypeScript-前端工程最佳实践

 作者:王春雨前言随着前端工程化的疾速倒退, TypeScript 变得越来越受欢迎,它曾经成为前端开发人员必备技能。 TypeScript 最后是由微软开发并开源的一种编程语言,自2012年10月公布首个公开版本以来,它已失去了人们的宽泛认可。TypeScript 倒退至今,曾经成为很多大型项目的标配,其提供的动态类型零碎,大大加强了代码的可读性、可维护性和代码品质。同时,它提供最新的JavaScript个性,能让咱们构建更加强壮的组件,新版本一直迭代更新,编写前端代码也越来越香。 typescript 下载量变化趋势(来自于 npm trends) 1 为什么应用 TypeScript微软提出 TypeScript 次要是为了实现两个指标:为 JavaScript 提供可选的类型零碎,兼容以后及将来的 JavaScript 个性。首先类型零碎可能进步代码的品质和可维护性,国内外大型团队通过一直实际后得出一些论断: 类型有利于代码的重构,它有利于编译器在编译时而不是运行时发现错误;类型是杰出的文档模式之一,良好的函数申明胜过简短的代码正文,通过申明即可晓得具体的实现;像其余语言都有类型的存在,如果强加于 JavaScript 之上,类型可能会有一些不必要的复杂性,而 TypeScript 在两者之间做了折中解决尽可能地升高了入门门槛,它使 JavaScript 即 TypeScript ,为 JavaScript 提供了编译时的类型平安。TypeScript 类型齐全是可选的,原来的 .js 文件能够间接被重命名为 .ts ,ts 文件能够被编译成规范的 JavaScript 代码,并保障编译后的代码全副兼容,它也被成为 JavaScript 的 “超集”。没有类型的 JavaScript 语法尽管简略灵便,应用的变量是弱类型,然而比拟难以把握,TypeScript 提供的动态类型查看,很好的补救了 JavaScript 的有余。 TypeScript 类型能够是隐式的也能够是显式的,它会尽可能平安地推断类型,以便在代码开发过程中以极小的老本为你提供类型平安,也能够应用显式的申明类型注解让编译器编译出咱们想要的内容,更重要的是为下一个必须浏览代码的开发人员了解代码逻辑。 类型谬误也不会阻止JavaScript 的失常运行,为了不便把 JavaScript 代码迁徙到 TypeScript,即便存在编译谬误,TypeScript 也会被编译出残缺的 JavaScript 代码,这与其余语言的编译器工作形式有很大不同,这也正是 TypeScript 被青眼的另一个起因。 TypeScript 的特点还有很多比方上面这些: 收费开源,应用 Apache 受权协定;基于ECMAScript 规范进行拓展,是 JavaScript 的超集;增加了可选动态类型、类和模块;能够编译为可读的、合乎ECMAScript 标准的 JavaScript;成为一款跨平台的工具,反对所有的浏览器、主机和操作系统;保障能够与 JavaScript 代码一起应用,毋庸批改(这一点保障了 JavaScript 我的项目能够向 TypeScript 平滑迁徙);文件扩展名是 ts/tsx;编译时查看,不净化运行时;总的来说咱们没有理由不应用 TypeScript, 因为 JavaScript 就是 TypeScript,TypeScript 能够让 JavaScript 更美妙。 ...

December 22, 2022 · 7 min · jiezi

关于typescript:kafka

kafka-zookeeper: image: confluentinc/cp-zookeeper:7.3.0 container_name: zookeeper restart: always environment: - ZOOKEEPER_CLIENT_PORT=12181 - ZOOKEEPER_TICK_TIME=2000 kafka-broker: image: confluentinc/cp-kafka:7.3.0 container_name: broker restart: always ports: - "29092:29092" depends_on: - kafka-zookeeper environment: - KAFKA_BROKER_ID=1 - KAFKA_ZOOKEEPER_CONNECT=zookeeper:12181 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.3.1:29092 - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1

December 19, 2022 · 1 min · jiezi

关于typescript:TypeScript-49-发布

TypeScript 是一种通过增加类型和类型查看构建在 JavaScript 之上的语言。类型能够形容诸如对象的形态、如何调用函数以及属性是否能够为 null 或 undefined 之类的货色。TypeScript 能够查看这些类型,以确保咱们不会在程序中出错,这样咱们就能够自信地编码。它还能够为编辑器中的主动实现、转到定义和重构等其余工具提供反对。事实上,如果您应用过 Visual Studio 或 VS Code for JavaScript 等编辑器,您其实曾经体验过由 TypeScript 提供的反对了! satisfies 运算符TypeScript 开发人员常常面临两难地步:咱们既要确保某些表达式匹配某些类型,又要保留该表达式的最具体类型以用于推理目标。 新的 satisfies 运算符让咱们验证表达式的类型是否匹配某种类型,而不更改该表达式的后果类型。例如,咱们能够应用 satisfies 来验证 palette 的所有属性是否与 string | number[] 兼容: type Colors = "red" | "green" | "blue";type RGB = [red: number, green: number, blue: number];const palette = { red: [255, 0, 0], green: "#00ff00", bleu: [0, 0, 255]// ~~~~ The typo is now caught!} satisfies Record<Colors, string | RGB>;// Both of these methods are still accessible!const redComponent = palette.red.at(0);const greenNormalized = palette.green.toUpperCase();应用 in 运算符放大未列出属性的范畴作为开发人员,咱们常常须要解决在运行时不齐全已知的值。事实上,咱们通常不晓得属性是否存在,无论咱们是从服务器取得响应还是读取配置文件。JavaScript 的 in 运算符能够查看对象上是否存在属性。 ...

December 15, 2022 · 2 min · jiezi