TypeScript 报错汇总

news2024/11/20 12:43:37

TypeScript 报错汇总

在这篇文章中将记录我遇到的ts错误,应该会持续更新。

有时候从错误点入手学习似乎是一个不错的选择,所以也欢迎你私信我一些ts的问题。

一、内置工具

1.1 Pick & Partial

先看看PickPartial工具的源码:

type Partial<T> = {
  [P in keyof T]?: T[P];
};
 
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

从代码和注释来看,

  • 通过Pick工具根据联合类型数据,筛选泛型T中的属性
  • 通过Partial工具将接口属性都变为可选属性

比如:

interface User {
  id: number;
  age: number;
  name: string;
};
 
// 相当于: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial<User>
 
// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">

现在实现一个需求:筛选出目标接口中的函数属性,删除其他属性。

// 目标接口
interface Part {
  id: number
  name: string
  subparts: Part[]
  firstFn: (brand: string) => void,
  anotherFn: (channel: string) => string
}

首先遍历接口,将非函数类型的属性设置为never,如果是函数类型,取其属性名,然后通过Pick拿到函数类型成员集合:

type FunctionFilterNames<T> = {
	[K in keyof T]: T[K] extends Function ? K : never
}[keyof T]

type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>

完整代码:

type FunctionPropertyNames<T> = { 
  [K in keyof T]: T[K] extends Function ? K : never 
}[keyof T]

type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>

interface Part {
  id: number
  name: string
  subparts: Part[]
  firstFn: (brand: string) => void,
  anotherFn: (channel: string) => string
}

// 过滤出所有的函数key
// type FnNames = "firstFn" | "anotherFn"
type FnNames = FunctionPropertyNames<Part>

// 根据对象的key获取函数接口集合
// type FnProperties = {
//    firstFn: (brand: string) => void;
//    anotherFn: (channel: string) => string;
// }
type FnProperties = FunctionProperties<Part>

let func: FnProperties = {
  firstFn: function (brand: string): void {
    throw new Error("Function not implemented.")
  },
  anotherFn: function (channel: string): string {
    throw new Error("Function not implemented.")
  }
}

如果需要深 Partial 我们可以通过泛型递归来实现

type DeepPartial<T> = T extends Function
  ? T
  : T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T

type PartialObject = DeepPartial<object>

1.2 Record

先看看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中的每个属性作为key值,以T作为value构建一个map结构

比如:

type pets = 'dog' | 'cat';
interface IPetInfo {
    name: string,
    age: number,
}

type IPets = Record<pets, IPetInfo>;

const animalsInfo: IPets = {
    dog: {
        name: 'Ryuko',
        age: 1
    },
    cat: {
        name: 'Ryuko',
        age: 2
    }
}

这个案例来源于这篇文章

现在实现一个需求,封装一个http请求:

首先思考请求方法一般需要哪些参数,比如请求类型、data数据、config配置

通过enum枚举几个常见的请求类型,然后每个具体的方法返回值都是一个Promise:

enum IHttpMethods {
    GET = 'get',
    POST = 'post',
    DELETE = 'delete',
    PUT = 'put',
}

interface IHttpFn<T = any> {
    (url: string, config?: AxiosRequestConfig): Promise<T>
}

// 以enum参数为key,每个key对应一种请求方法
// type IHttp = {
//   get: IHttpFn<any>;
//   post: IHttpFn<any>;
//   delete: IHttpFn<any>;
//   put: IHttpFn<any>;
// }
type IHttp = Record<IHttpMethods, IHttpFn>;

接下来设置一个methods数组,稍后通过reduce方法遍历这个数组,目的是将所有的方法体放在一个对象httpMethods中,形式如下:

httpMethods = {
  get: [Function ()],
  post: [Function ()],
  delete: [Function ()],
  put: [Function ()]
}

最后将httpMethods暴露出去,那么外面就可以通过httpMethods.get(...)等方法直接调用:

const methods = ["get", "post", "delete", "put"];

// map为total对象,method为当前遍历到的方法
const httpMethods: IHttp = methods.reduce(
	(map: any, method: string) => {
		map[method] = (url: string, options: AxiosRequestConfig = {...}) => {
         	const { data, ...config } = options;  \
           	return (axios as any)[method](url, data, config)
              .then((res: AxiosResponse) => {
                  if (res.data.errCode) {
                      //todo something
                  } else {
                      //todo something
                  }
            });
         }
    },{} 
)

export default httpMethods

完整代码:

enum IHttpMethods {
    GET = 'get',
    POST = 'post',
    DELETE = 'delete',
    PUT = 'put',
}

interface IHttpFn<T = any> {
    (url: string, config?: AxiosRequestConfig): Promise<T>
}

type IHttp = Record<IHttpMethods, IHttpFn>;

const methods = ["get", "post", "delete", "put"];

const httpMethods: IHttp = methods.reduce(
	(map: any, method: string) => {
		map[method] = (url: string, options: AxiosRequestConfig = {...}) => {
         	const { data, ...config } = options;  \
           	return (axios as any)[method](url, data, config)
              .then((res: AxiosResponse) => {
                  if (res.data.errCode) {
                      //todo something
                  } else {
                      //todo something
                  }
            });
         }
    },{} 
)

export default httpMethods

1.3 Exclude & omit

先看看Excludeomit工具的源码:

type Exclude<T, U> = T extends U ? never : T;

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

从代码和注释来看:

  • Exclude可以选出T不存在于U中的类型
  • Omit可以抛弃某对象中不想要的属性

比如:

// 相当于: type A = 'a'
type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'>

interface User {
  id: number;
  age: number;
  name: string;
};
 
// 相当于: type PickUser = { age: number; name: string; }
type OmitUser = Omit<User, "id">

举个例子,现在我们想引入第三方库中的组件,可以这样做:

// 获取参数类型
import { Button } from 'library' // 但是未导出props type
type ButtonProps = React.ComponentProps<typeof Button> // 获取props
type AlertButtonProps = Omit<ButtonProps, 'onClick'> // 去除onClick
const AlertButton: React.FC<AlertButtonProps> = props => (
  <Button onClick={() => alert('hello')} {...props} />
)

二、类型 “string” 没有调用签名 ts(2349)

函数返回元组的时候,在使用的时候,元素可能是元组中的任意一个类型,比如:

在这里插入图片描述

所以,在对返回的元组进行取值操作时,返回值内的类型顺序,可能和函数内的顺序不一致,需要多加一个条件判断:

function test<T>(name: T){
	let myName = name
	const setName = (newName: T): void => {
    if(typeof newName === 'string'){
      console.log(newName.length);
    }
  }
  // console.log(typeof setName);  // function
  return [myName, setName]
}

const [myName, setName] = test<string>("Ryuko")

// 此表达式不可调用。"string | ((newName: string) => void)" 类型的部分要素不可调用。
// 类型 "string" 没有调用签名。ts(2349)
// setName("test")

// 编译器无法判断setName是string还是一个函数,所以需要通过typeof手动判断
if(typeof setName === 'function'){
  setName("test") 
}

console.log(myName);  //Ryuko

export{}

在这个报错案例中,第四行的typeof newName === 'string'判断也是很重要的知识点,面对联合类型传参的情况,我们常常需要通过类型判断来决定最后要执行哪个方法:

type Name = string
type NameResolve = (name: string) => string
type NameOrResolver = Name | NameResolve

function getName(param: NameOrResolver): Name{
  if(typeof param === 'string'){
    return param
  }else{
    return param("Ryuko")
  }
}

console.log(getName("Ryuko"));  // Ryuko
console.log(getName(
  (p: string) => { return p + "si" }
)); // Ryukosi

三、类型 “string” 到类型 “number” 的转换可能是错误的ts(2352)

// 类型 "string" 到类型 "number" 的转换可能是错误的,因为两种类型不能充分重叠。
// 如果这是有意的,请先将表达式转换为 "unknown"
// 在那些将取得任意值,但不知道具体类型的地方使用 unknown,而非 any。
// let a = 'Ryuko' as number

// 更正:先将数据转化为unknown,再将数据转化为子类型的number
let a = ('Ryuko' as unknown) as number

export {}

这样的转换方式还可以用来定义html元素,比如我们想要通过dom操作,来改变某个超链接的url路径地址:

在这里插入图片描述

可是在HTMLElement元素节点中并不存在src这一属性:

在这里插入图片描述

因此,我们可以将这个节点属性断言转化为子属性HTMLImageElement,在子属性身上可以获取到src属性

let elem = document.getElementById('id') as HTMLImageElement

四、类型“string”的参数不能赋给类型“Method”的参数。ts(2345)

type Method = 'get' | 'post' | 'delete'

const requestConfig = {
  url: 'localhost: 3000',
  // config 中的 method 是string类型的菜蔬,而 request 方法中的Method参数
  // method: 'get'
    
  // 解决办法 通过断言进行转换
  method: 'get' as Method
}

function request(url: string, method: Method){
  console.log(method);
}

// 类型“string”的参数不能赋给类型“Method”的参数。ts(2345)
request(requestConfig.url, requestConfig.method)

export {}

4.1 相关案例

这里再介绍一种情况:

注意:这个用法并没有报错

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
  console.log(event);
}
handleEvent(document.getElementById("app")!, "click")
handleEvent(document.getElementById("app")!, "mousemove")

在这个案例中,你可能会认为我传递过去的"click",以及"mousemove"是字符串,既然是字符串,就应该报错:类型“string”的参数不能赋给类型“EventNames”的参数。ts(2345)

事实上,这里的字符串参数会被推导为EventNames类型,而在前面的错误案例中,method:get将会被推导为string类型!这也是为什么在错误案例中,我们需要手动声明类型method: ‘get’ as Method:

五、对象可能为“未定义”。ts(2532)

function add(num1: number, num2?: number): number{
  // 通过可选链提前知道:可能用不上num2这个变量
  // 但是如果真的想要操作 num2 的值便会报错
  return num1 + num2
}
console.log(add(10));
export {}

在这时就可以通过??来设置默认值

function add(num1: number, num2?: number): number{
  return num1 + (num2 ?? 0)
}
console.log(add(10));
export {}

六、“number”索引类型“number”不能分配给“string”索引类型“string”。ts(2413)

在设置索引的时候可能会出现这样的问题:

interface Person {
  [name: string] : string
  // “number”索引类型“number”不能分配给“string”索引类型“string”
  [age: number] : number
}

// 而只要这样写就不会报错了
interface Person {
  [name: string] : string | number
  [age: number] : number
}

分析:

在报错的代码中,定义了一个Person接口,这个接口可以采用字符 & 数字两种类型的索引:既要符合字符,也要符合数字类型

  • number类型索引表示:类型规范的是一个数组
  • string类型索引表示的是:接收一个对象

数组类型的数据一定可以转化为对象,例如:

['a','b','c']
// 等价于
{
	1: 'a',
	2: 'b',
	3: 'c'
}

而对象类型数据不一定可以转化为数组,例如,如果对象的key值是字符串类型,就无法完成转换了

因此:数组类型可以看作是对象类型的一种子集,例如:

interface ok {
  [name: string] : string | number
  [age: number] : number
}

interface ok {
  [name: string] : string | number | boolean
  [age: number] : number
}

interface ok {
  [name: string] : number 
  [age: number] : number
}

interface nope {
  [name: string] : number 
  [age: number] : number | string
}

在这里同样也说明了,为什么可以通过字符串索引来表示json格式的数据:因为json数据的key本质上就是字符串

type Person{
	name: string
	age: number
}

interface IPerson{
	[name: string]: Person
}

let p: IPerson = {
	'Ryuko': {
		name: 'Ryuko',
		age: 1
	}
}

总结:当使用 number 来索引时,JavaScript 会将它转换成 string 然后再去索引对象。也就是说用 1(一个number)去索引等同于使用”1″(一个string)去索引,因此我们可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。

6.1 相关案例

// ok
interface Foo {
  [index: string]: number;
  x: number;
  y: number;
}

// wrong
interface Bar {
  [index: string]: number;
  x: number;
  // 类型“string”的属性“y”不能赋给“string”索引类型“number”。ts(2411)
  y: string; 
}

接口Bar中采用了string类型索引,所以内部属性可以写为x,y,z,xxxx...等字符串,他们的值都应该声明为number类型。

更正方法:

// ok
interface Bar {
  [index: string]: number;
  x: number;
  // 保证和索引数据一致
  y: number; 
}

// ok
interface Bar {
  [index: string]: number | string;
  x: number;
  y: string; 
}

七、对象的类型为 “unknown”。ts(2571)

在一些兑换码场景,经常会需要将兑换码全部转为大写,之后再进行判断:

function isString(s: unknown): boolean {
  return typeof s === 'string'
}

function toUpperCase(x: unknown) {
  if(isString(x)) {
    // 对象的类型为 "unknown"。ts(2571)
    x.toUpperCase() 
  }
}

可是在上一行明明已经通过 isString() 函数确认参数 x 为 string 类型了啊?

原因在于:即使第六行进行了字符串判断,在初次类型检查的时候,编译器看到第七行的x.toUpperCase() ,仍会判定x是unkown类型。

解决办法:采用is关键字。

is 关键字一般用于函数返回值类型中,判断参数是否属于某一类型,并根据结果返回对应的布尔类型。通过 is 关键字将函数参数类型范围缩小为 string 类型

function isString(s: unknown): s is string {
  return typeof s === 'string'
}

function toUpperCase(x: unknown) {
  if(isString(x)) {
    x.toUpperCase() 
  }
}

八、类型“T”上不存在属性“length”。ts(2339)

在遇到泛型的时候,有时候我们需要传递一个字符串给函数,但是对于函数来说,参数a仅仅是一个T类型数据,编译器并不知道参数a身上有length属性。

// 类型“T”上不存在属性“length”。ts(2339)
function test<T>(a: T){
  console.log(a.length);
}

所以在这个时候可以考虑使用类型约束来解决该问题:

interface lengthConfig{
  length: number
}

// 类型“T”上不存在属性“length”。ts(2339)
function test<T extends lengthConfig>(a: T){
  console.log(a.length);
}

九、成员 “T” 隐式具有 “any” 类型,但可以从用法中推断出更好的类型。ts(7045)

目前来看,遇到这种错误的时候只能说多试试…

以这个例子来说,Person接口的函数返回类型声明为T会报错,但ArrayFunc接口不会

interface Person<T,U> {
  name: T,
  age: U,
  // 应为“=>”。ts(1005)
  say: ()=> T
}

interface ArrayFunc<T> {
  (length: number, value: T): T[]
}

// 如果已经声明了函数类型,在定义函数的时候不必声明参数类型
const createArrayFunc: ArrayFunc<string> = (length, value) =>{
  return ['1','2']
}

十、不能将类型“() => string”分配给类型“Func”。ts(2322)

interface Func{
  print(): string
}

// 不能将类型“() => string”分配给类型“Func”。ts(2322)
const helloFuncWrong: Func = function(){
  return "Ryuko"
}

// 如果一定要添加函数名,那么就应该对照着接口中的模式来写
const helloFuncOk: Func = {
  print() {
    return "Ryuko"
  }
}

一般情况下,函数式接口中,(其实type类型也是一样),不能添加具体的函数名:

interface Func{
  (): string
}

const helloFunc: Func = function(){
  return "Ryuko"
}

10.1 相关案例

其实关于2322报错,主要可以理解为:设定了某个类型的数据,但是你在使用的时候却为他赋值为其他类型的数据

let arr: {id: number}[] = []

// ok
arr.push({id: 1})

// wrong
arr.push([{id:2, age: 1}])

以这个来说,定义的arr为包含着id对象的数组,可是第七行却赋值为包含{ id,age }类型的对象数组,现在有两种解决办法:

  1. 改变第一行arr类型定义

  2. 数据可以由大赋值给小的理念来看,我们可以将any类型的数据赋值给arr对象:

    // ok
    arr = [{id:2, age: 1} as any]
    

十一、对象的类型为 “unknown”。ts(2571)

在请求数据的时候,我们常常会有这样的操作:

<script lang='ts' setup>
import { axiosGet } from '@/utils/http'
import { reactive } from 'vue'

let state = reactive({})

async function getImgList() {
  let result = await axiosGet("/api/getlunbo")
  +result.status === 0 ? state.imgList = result.message : ""
}

getImgList()

</script>

如果这段代码没有采用ts类型检测,可以顺利运行,流程为:向接口发起请求,将接口返回的数据赋值给state.imgList。

但是,这里有ts类型检测,请求结果返回的promise.then的结果并没有任何类型声明,所以编译器并不知道result身上存在什么属性,于是发出报错:对象(result)的类型为unknown。

这时候我们就需要手动来为返回值设置类型了,先看看接口格式:

{
    status: 0,
    message: [
        {
            url: "http://www.baidu.com",
            img: "http://img2.imgtn.bdimg.com/it/u=500808421,1575925585&fm=200&gp=0.jpg"
        },
        {
            url: "http://www.qq.com",
            img: "http://p16.qhimg.com/bdr/__85/d/_open360/fengjing34/ABC8cbd.jpg"
        }
   ]
}

根据接口类型,在type.d.ts类型声明文件中定义,然后在代码中为返回值设置类型转换:

interface ResultType {
  status: number,
  message: Array<any>
}

declare namespace HOME {
  interface StateType {
      lunboList: {
          img?: string,
          url?: string
      }[]
  }
}

接下来只需要为数据添加类型就可以了:

  1. 将result返回值数据手动断言为ResultType类型
  2. 为state对象中的数据绑定对象成员类型
<script lang='ts' setup>
import { axiosGet } from '@/utils/http'
import { reactive } from 'vue'

let state = reactive<HOME.StateType>({
  lunboList: []
})

async function getImgList() {
  let result = await axiosGet("/api/getlunbo") as ResultType
  // 需要注意的是,这里的result.message是any类型的数组
  // 可以直接将 any[] 赋值给 HOME.StateType 下的lunboList[]
  // 这是因为 any 类型的数据可以赋值给任意类型,因为**多属性数据可以赋值给少属性数据**
  result.status === 0 ? state.lunboList = result.message : ""
}

getImgList()
</script>

参考文章

TypeScript 高级技巧
TypeScript 联合类型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/408904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅析什么是伪类和伪元素?伪类和伪元素的区别解析

一、理解什么是伪类&#xff1f;什么是伪元素&#xff1f; 1、伪类种类 伪类作用对象是整个元素 a:link{color:#111} a:hover{color:#222}div:first-child{color:#333} div:nth-child&#xff08;3&#xff09;{color:#444} 尽管这些条件不是基于DOM的&#xff0c;但结果每一…

面试必问JavaScript基础面试题(附答案详解)

文章目录前言1、JavaScript的数据类型有哪些&#xff1f;2、null&#xff0c;undefined的区别&#xff1f;3、JS中变量的作用域是什么&#xff1f;4、说说var、let、const之间的区别?区别一&#xff1a;作用域区别二&#xff1a;定义变量区别三&#xff1a;let与const区别5、栈…

微信小程序云开发 | 插件的微信小程序云开发

1、插件开发简介 1●插件简介 插件是对一组JavaScript接口、自定义组件或页面的封装&#xff0c;可嵌入小程序中使用。插件不能独立运行&#xff0c;必须嵌入在其他小程序中才能被用户使用&#xff1b;而第三方小程序在使用插件时&#xff0c;也无法看到插件的代码。因此&…

英雄联盟轮播图手动轮播

感谢大朋友们小朋友们的催更&#xff0c;这个月都在努力复习功课&#xff0c;无异于对待期末考试。 通过前一个个小案例越做越熟悉&#xff0c;代码越来越简洁&#xff0c;整体架构越来越规范 一步一步循序渐进&#xff0c;今天写一个英雄联盟轮播图手动轮播练练手。 清除网页的…

js逆向点点数据:自动扣webpak-webpackJsonp思路

url链接:点点数据-App应用市场数据分析,AppStore排行榜,ASO,ASM优化平台 请求数据是k&#xff0c;网址是个标准的webpak&#xff0c;不过有有很多个js文件&#xff0c;文件加起来十几mb&#xff0c;就很恶心 扣的话还是扣知乎webpak的老办法&#xff0c;导出加载器&#xff0c…

【蓝桥杯Web】第十四届蓝桥杯Web模拟赛 3 期 | 精品题解(上)

&#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; &#x1f5a5;️ 蓝桥杯专栏&#xff1a;蓝桥杯题解/感悟 &#x1f5a5;️ TS知识总结&#xff1a;十万字TS知识点总结 &#x1f449; 你的一键三连是我更新的最大动力❤️&#xff01; &…

Promise.allSettled()方法介绍

前言&#xff1a; 本篇文章介绍 Promise 对象的Promise.allSettled() 方法&#xff0c;另外的关于 Promise 文章 可以看我的 ES6专栏 promise 实现 Ajax 首先通过 promise 对象实现 Ajax &#xff08;如下&#xff09; &#xff0c;后面 在代码中 会使用到 const getJSON f…

uniapp添加极光推送

1.从dcloud插件市场下载极光SDK插件 &#xff08;可以云打包&#xff0c;也可以离线打包&#xff09; 极光JCore官方SDK下载地址 https://ext.dcloud.net.cn/plugin?id4028https://ext.dcloud.net.cn/plugin?id4028 极光JPush官方SDK下载地址 极光JPush官方SDK - DCloud 插…

Request获取请求数据中文乱码问题

目录 一、当Request请求字母时&#xff0c;输出正常 二、当Request请求参数为汉字时 三、使用伪代码了解乱码的形成 URL编码 四、Request请求参数中文乱码-Post请求解决方案 五、Request请求参数中文乱码-Get请求解决方案 前言&#xff1a;Tomcat在7以及更低版本时&#…

【虚幻引擎UE】UE5 实现WEB和UE通讯思路(含工程源码)

UE5实现WEB和UE通讯思路 两个方案,根据需求选择适合自己的: 1.UE打包为像素流页面,嵌入WEB进行通讯。 2.UE和WEB基于WEB UI插件实现通讯,打包为像素流页面。 实现效果如下 ↓ 本文着重说明第二种方案。 示例项目工程文件:https://download.csdn.net/download/qq_35079…

使用nodejs写接口

一、基本步骤 要使用Node.js编写接口&#xff0c;需要遵循以下步骤&#xff1a; 1、安装Node.js&#xff1a;如果尚未在计算机上安装Node.js&#xff0c;可以在Node.js的官方网站上下载安装程序&#xff0c;并按照说明进行安装。 2、初始化项目&#xff1a;在项目文件夹中打…

完美解决 - 前端发版后浏览器缓存问题(发版后及时拉取最新版本代码)

一、简介 开发完发布新版本后&#xff0c;在有些电脑上总需要强刷才能获取到最新版本的内容&#xff0c;太恶心了。 浏览器缓存&#xff08;Browser Caching&#xff09;是为了节约网络的资源加速浏览&#xff0c;浏览器在用户磁盘上对最近请求过的文档进行存储&#xff0c;当…

为什么要将程序部署到云服务器上?华为云Web及移动App上云解决方案体验测评

Web及移动App上云是指将Web应用程序或移动应用程序部署到云计算平台上&#xff0c;以便用户可以通过互联网访问这些应用程序。这种部署方式可以提高应用程序的可靠性、可扩展性和安全性&#xff0c;同时也可以降低应用程序的运营成本。 三大特性决定系统的稳定能力 部署应用服务…

【中秋征文】“海上生明月”中秋节网页特效

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

van-uploader上传图片实现过程、使用原生input实现上传图片

1、使用van-uploader 使用van-uploader组件上传图片&#xff0c;并将其封装成组件&#xff0c;接收传入的参数imglist。图片地址为服务器返回的。 完整代码 <template><div class"image-uploader"><div class"list-img" v-for"(src…

html 导入百度地图 网页中如何导入百度地图

先看案例如图所示 首先我们需要知道我们想要标注地点的经纬度 经纬度查询网址如下 图中以同程大厦为例 经纬度查询定位 拾取坐标系统 经纬度查询地图 好了 准备工作做好 现在开始编码~ 第一步 html css部分 注意点1. #map 命名 不要随意更改 如影响到您的布局 您可以在外面在…

多种方法解决前后端报出的SyntaxError: xxx is not valid JSON的问题,比如“[object Object]“ is not valid JSON

文章目录1. 复现问题2. 分析问题3. 解决问题4. 该错误的其他解决方法5. 文章总结1. 复现问题 今天启动后端服务&#xff0c;访问knife4j文档时&#xff0c;却报出如下错误&#xff1a; 于是&#xff0c;按F12打开调试页面板&#xff0c;找到了具体的错误信息&#xff0c;如下所…

那些你不得不了解的HTML基础

瞧一瞧&#xff0c;看一看&#xff0c;新鲜的HTML出笼了 目录 一、HTML基本语法&#xff08;标签&#xff09; 注释 标题 段落 换行 特殊转义字符 格式化标签 图片 超链接a标签 表格标签 列表标签 表单标签 无语义标签 二、基于上述实现的两个案例 制作一份简历…

vue 之 CSS进行样式穿透的方法(/deep/、::v-deep、>>> 、:deep、额外的全局<style>)

一、简介 在很多vue的组件库 , 如vant&#xff0c;elementUI&#xff0c; iview等都可能自定义一些样式文件&#xff0c;如果我们在项目中引入了样式组件或者通过v-html渲染了数据&#xff0c;然后想要去修改他们内部的某元素的样式, 直接修改样式很可能不起作用&#xff0c;修…

做一个前端网页送给女朋友~轮播图+纪念日

文章目录1. 轮播图框架2. 轮播图大盒子实现1. 盒子及图片的可视化2. 将图片重叠起来并放入轮播图盒子中...相对定位与绝对定位3. 添加左右按钮4. 点击按钮跳转图片5. 鼠标离开图片轮播图按钮隐藏6. 添加小圆点按钮7. 点击小圆点跳转图片并且该小圆点变色8. 自动轮播9. 最后一步…