发表于: 2019-11-19 07:33:33
0 932
js基础 - 续1
构造函数和操作符 "new"
构造函数
构造函数在技术上是常规函数。不过有两个约定:
- 他们首先用大写字母命名。
- 它们只能用
"new"
操作符来执行。
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
当一个函数作为 new User(...)
执行时,它执行以下步骤:
- 一个新的空对象被创建并分配给
this
。 - 函数体执行。通常它会修改
this
,为其添加新的属性。 - 返回
this
的值。
换句话说,new User(...)
做类似的事情:
function User(name) {
// this = {};(隐式创建)
// 添加属性到 this
this.name = name;
this.isAdmin = false;
// return this;(隐式返回)
}
这是构造函数的主要目的 — 实现可重用的对象创建代码
从技术上讲,任何函数都可以用作构造函数。即:任何函数都可以运行 new
,它会执行上面的算法。 “首字母大写”是一个共同的约定,以明确表示一个函数将被使用 new
运行。
如果一个函数返回一个对象,那么 new
返回那个对象而不是 this
。
如果我们有许多关于创建单个复杂对象的代码行,我们可以将它们封装在构造函数中,如下所示:
let user = new function() {
this.name = "John";
this.isAdmin = false;
// ...用户创建的其他代码
// 也许是复杂的逻辑和陈述
// 局部变量等
};
构造函数不能被再次调用,因为它不保存在任何地方,只是被创建和调用。所以这个技巧的目的是封装构建单个对象的代码,而不是将来重用。
构造函数中的方法
使用构造函数来创建对象会带来很大的灵活性。通过构造函数的参数传递定义构造对象。
当然,我们不仅可以将属性添加到 this 中,而且还可以添加方法。
总结
- 构造函数或简言之,就是常规函数,但构造函数有个共同的约定,命名它们首字母要大写。
- 构造函数只能使用
new
来调用。这样的调用意味着在开始时创建空的this
,并在最后返回填充的对象。
我们可以使用构造函数来创建多个类似的对象。
JavaScript 为许多内置的对象提供了构造函数:比如日期 Date,设置集合 Set 以及其他。
数据类型
数组方法
添加/移除数组元素
从开头或结尾添加删除元素的方法:
arr.push(...items)
— 从结尾添加元素,arr.pop()
— 从结尾提取元素,arr.shift()
— 从开头提取元素,arr.unshift(...items)
— 从开头添加元素,
如何从数组中删除元素?
数组是对象,所以我们可以尝试使用 delete
:
let arr = ["I", "go", "home"];
delete arr[1]; // remove "go"
alert( arr[1] ); // undefined
// now arr = ["I", , "home"];
alert( arr.length ); // 3
元素被删除,但数组仍然有 3 个元素,我们可以看到 arr.length == 3
。
这很正常,因为 delete obj.key
是通过 key
来移除对应的值。但是对于数组,我们通常希望剩下的元素移除并释放占用的位置,得到一个更短的数组。
所以应该使用特殊的方法。
arr.splice(str) 方法可以说是数组界的瑞士军刀。它可以做所有事情:添加,删除和插入元素。
语法是:arr.splice(index, deleteCount, elem1, ..., elemN)
index 必需。从第几个元素开始,负值从数组结尾处规定位置。(-1为倒数第二位)
deleteCount 必需。要删除的项目数量。如果设置为 0,则不会删除项目。(可实现指定处添加元素)
elem1, ..., elemN 可选
从 index
开始:删除 deleteCount
个元素并在当前位置插入 elem1, ..., elemN
。最后返回已删除元素的数组。
我们也可以看到 splice
返回已删除元素的数组:
let arr = ["I", "study", "JavaScript", "right", "now"];
// remove 2 first elements
let removed = arr.splice(0, 2);
alert( removed ); // "I", "study" <-- 被删除元素的数组
slice
arr.slice 方法比 arr.splice
简单得多。
语法是:arr.slice(start, end)
它从所有元素的开始索引 "start"
复制到 "end"
(不包括 "end"
) 返回一个新的数组。start
和 end
都可以是负数,在这种情况下,从末尾计算索引。
它和字符串的 str.slice
有点像,就是把子字符串替换成子数组。
let str = "test";
let arr = ["t", "e", "s", "t"];
alert( str.slice(1, 3) ); // es
alert( arr.slice(1, 3) ); // e,s
alert( str.slice(-2) ); // st
alert( arr.slice(-2) ); // s,t
concat
arr.concat 将数组与其他数组和/或元素结合在一起。
语法:arr.concat(arg1, arg2...)
它接受任意数量的参数 — 数组或值。
结果是一个包含arr
,arg1
,arg2
等元素的新数组。
如果参数是一个数组或具有 Symbol.isConcatSpreadable
属性,则其所有元素都将被复制。否则,复制参数本身。
通常,它只复制数组中的元素(“扩展”它们)。其他对象,即使它们看起来像数组一样,仍然作为一个整体添加:
let arr = [1, 2];
let arrayLike = {
0: "something",
length: 1
};
alert( arr.concat(arrayLike) ); // 1,2,[object Object]
//[1, 2, arrayLike]
…但是,如果类似数组的对象具有 Symbol.isConcatSpreadable
属性,将替换其元素:
let arr = [1, 2];
let arrayLike = {
0: "something",
1: "else",
[Symbol.isConcatSpreadable]: true,
length: 2
};
alert( arr.concat(arrayLike) ); // 1,2,something,else
查询数组
这些是在数组中查询某些内容的方法。
indexOf/lastIndexOf 和 includes
arr.indexOf、arr.lastIndexOf 和 arr.includes 方法与字符串操作具有相同的语法,只不过这里是对数组元素而不是字符进行操作:
arr.indexOf(item, from)
从索引from
查询item
,如果找到返回索引,否则返回-1
。arr.lastIndexOf(item, from)
— 和上面相同,只是从尾部开始查询。arr.includes(item, from)
— 从索引from
查询item
,如果找到则返回true
。
find 和 findIndex
想象一下,我们有一个对象数组。我们如何找到具有特定条件的对象?
这时可以用 arr.find 方法。
语法:
let result = arr.find(function(item, index, array) {
// 如果查询到返回 true
});
该函数对数组中的每个元素重复调用:
item
是元素。index
是它的索引。array
是数组本身。
如果它返回true
,则查询停止,返回 item
。如果没有查询到,则返回 undefined
。
例如,我们有一组用户,每个用户都有 id
和 name
字段。让我们找到一个 id == 1
:
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // John
注意在这个例子中我们传给了 find
一个单参数函数 item => item.id == 1
。其他参数 find
很少使用。
与 arr.findIndex 方法本质上是相同的,但它返回找到元素的索引而不是元素本身。
filter
find
方法查询的是使函数返回 true
的第一个元素。
如果需要匹配的有很多,我们可以使用 arr.filter(fn)。
语法与 find
大致相同,但是它返回的是所有匹配元素组成的数组:
let results = arr.filter(function(item, index, array) {
// 在元素通过过滤器时返回 true
});
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
// 返回前两个用户的数组
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
转换数组
本节介绍转换或重新排序数组的方法。
map
arr.map 方法是最有用和经常使用的方法之一。
语法:
let result = arr.map(function(item, index, array) {
// 返回新值而不是当前元素
})
它对数组中每个元素调用函数并返回符合结果的数组。
例如,在这里我们将每个元素转换为它的字符串长度:
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length)
alert(lengths); // 5,7,6
sort(fn)
arr.sort 方法对数组进行排序
语法:
let arr = [ 1, 2, 15 ];
// 该方法重新排列 arr 的内容(并返回它)
arr.sort();
alert( arr ); // 1, 15, 2
顺序变成了 1, 15, 2
。不对,但为什么呢?
这些元素默认情况下按字符串排序。
从字面上看,所有元素都被转换为字符串,然后进行比较。因此,按照词典顺序排序,实际上应该是"2" > "15"
。
要使用我们自己的排序顺序,我们需要提供带两个参数的函数作为 arr.sort()
的参数。
arr
可以是由任何东西组成的数组。它可能包含数字或字符串或 html 元素或其他。我们对一组数据进行排序时,需要一个排序函数来确认如何比较这些元素。默认是按字符串排序的。
arr.sort(fn)
方法内置实现排序算法。我们不需要关心它是如何工作的(大多数情况下是优化过的快速排序算法)。它将自动遍历数组,使用提供的函数比较它的元素并对它们重新排序,我们所需要的只是提供用于比较的函数 fn
。
实际上,比较函数只需要返回一个正数表示更大,而负数表示更少。
let arr = [ 1, 2, 15 ];
arr.sort(function(a, b) { return a - b; }); //箭头函数可以使这句更简洁 arr.sort( (a, b) => a - b );
alert(arr); // 1, 2, 15
reverse
arr.reverse 方法颠倒 arr
中元素的顺序。
let arr = [1, 2, 3, 4, 5];
arr.reverse();
alert( arr ); // 5,4,3,2,1
它也在返回后返回数组 arr
。
split 和 join
举一个现实生活的场景的例子,我们正在编写一个消息应用程序,并且该人员输入以逗号分隔的接收者列表:John,Pete,Mary
。但对我们来说,数组比单个字符串更舒适。怎么做才能获得这个数组呢?
str.split(delim) 方法可以做到。它通过给定的分隔符 delim
将字符串分割成一个数组。
在下面的例子中,我们用逗号分隔:
let names = 'Bilbo, Gandalf, Nazgul';
let arr = names.split(', ');
for (let name of arr) {
alert( `A message to ${name}.` ); // A message to Bilbo ...
}
split
方法有一个可选的第二个数字参数 — 对数组长度的限制。如果提供了,那么额外的元素将被忽略。但实际上它很少使用:
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2);
alert(arr); // Bilbo, Gandalf
拆分为字母
调用空的参数
split(s)
会将字符串分成一个字母数组:
arr.join(str) 与 split
相反。它会在它们之间创建一串由 str
粘合的 arr
项。
例如:
let arr = ['Bilbo', 'Gandalf', 'Nazgul'];
let str = arr.join(';');
alert( str ); // Bilbo;Gandalf;Nazgul
reduce/reduceRight
当我们需要遍历一个数组时 — 我们可以使用 forEach
。
当我们需要迭代并返回每个元素的数据时 — 我们可以使用 map
。
arr.reduce 和 arr.reduceRight 和上面差不多,但有点复杂。它们用于根据数组计算单个值。
语法是:
let value = arr.reduce(function(previousValue, item, index, arr) {
// ...
}, initial);
该函数应用于元素。从第二个参数开始你可能就会觉得很眼熟了:
item
— 当前的数组元素。index
— 当前索引。arr
— 数组本身。
目前为止,这很像 forEach/map
。但还有一个参数不同就是:
previousValue
— 是前一个函数调用的结果,第一次调用是初始化。
我们写个例子试试。
这里我们得到一行数组的总和:
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
在这里,我们使用了 reduce
的最常见类型,它只使用 2 个参数。
让我们看看发生了什么的细节。
- 在第一次运行时,
sum
是初始值(reduce
的最后一个参数),等于 0,current
是第一个数组元素,等于 1。所以结果是1
。 - 在第二次运行时,
sum = 1
,我们添加第二个数组元素(2
)并返回。 - 在第三次运行中,
sum = 3
,我们再添加一个元素,等等……
正如我们所看到的,先前调用的结果成为下一个调用的第一个参数。
我们也可以省略初始值:
let arr = [1, 2, 3, 4, 5];
// 删除初始值
let result = arr.reduce((sum, current) => sum + current);
alert( result ); // 15
结果是一样的。这是因为如果没有初始值,那么 reduce
将数组的第一个元素作为初始值,并从第二个元素开始迭代。
计算表与上面相同,减去第一行
但是这种使用需要非常小心。如果数组为空,那么在没有初始值的情况下调用 reduce
会导致错误。
let arr = [];
// Error: Reduce of empty array with no initial value
// 如果初始值存在,reduce 将返回空 arr。
arr.reduce((sum, current) => sum + current);
arr.reduceRight 也一样,但是遍历是从右到左。
迭代:forEach
arr.forEach 方法允许为数组的每个元素运行一个函数。
语法:
arr.forEach(function(item, index, array) {
// ... do something with item
});
例如:
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => {
alert(`${item} is at index ${index} in ${array}`);
});
大多数方法支持 “thisArg”
几乎所有调用函数的数组方法 – 比如 find
,filter
,map
,与带有 sort
的不同,他们接受一个可选的附加参数 thisArg
。
该参数在上面的部分没有解释,因为它很少使用。但为了完整性,我们还需要解释下。
以下是这些方法的完整语法:
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg 是可选的最后一个参数
thisArg
参数的值在 func
中变为 this
。
例如,在这里我们使用一个对象方法作为过滤器,thisArg
派上用场:
let user = {
age: 18,
younger(otherUser) {
return otherUser.age < this.age;
}
};
let users = [
{age: 12},
{age: 16},
{age: 32}
];
// 找到比 user 小的所有 users
let youngerUsers = users.filter(user.younger, user);
alert(youngerUsers.length); // 2
在上面我们使用 user.younger
作为过滤器,并提供 user
作为它的上下文。如果我们没有提供上下文,users.filter(user.younger)
会调用user.younger
作为一个独立的函数,这时 this=undefined
。
总结
数组方法备忘录:
添加/删除元素:
push(...items)
— 从结尾添加元素,pop()
— 从结尾提取元素,shift()
— 从开头提取元素,unshift(...items)
— 从开头添加元素,splice(pos, deleteCount, ...items)
— 从index
开始:删除deleteCount
元素并在当前位置插入元素。slice(start, end)
— 它从所有元素的开始索引"start"
复制到"end"
(不包括"end"
) 返回一个新的数组。concat(...items)
— 返回一个新数组:复制当前数组的所有成员并向其中添加items
。如果有任何items
是一个数组,那么就取其元素。
查询元素:
indexOf/lastIndexOf(item, pos)
— 从pos
找到item
,则返回索引否则返回-1
。includes(value)
— 如果数组有value
,则返回true
,否则返回false
。find/filter(func)
— 通过函数过滤元素,返回true
条件的符合 find 函数的第一个值或符合 filter 函数的全部值。findIndex
和find
类似,但返回索引而不是值。
转换数组:
map(func)
— 从每个元素调用func
的结果创建一个新数组。sort(func)
— 将数组倒序排列,然后返回。reverse()
— 在原地颠倒数组,然后返回它。split/join
— 将字符串转换为数组并返回。reduce(func, initial)
— 通过为每个元素调用func
计算数组上的单个值并在调用之间传递中间结果。
迭代元素:
forEach(func)
— 为每个元素调用func
,不返回任何东西。
其他: –
Array.isArray(arr)
检查arr
是否是一个数组。
请注意,sort
,reverse
和 splice
方法修改数组本身。
这些方法是最常用的方法,它们覆盖 99% 的用例。但是还有其他几个:
arr.some(fn)/arr.every(fn) 检查数组。
在类似于
map
的数组的每个元素上调用函数fn
。如果任何/所有结果为true
,则返回true
,否则返回false
。arr.fill(value, start, end) — 从
start
到end
用value
重复填充数组。arr.copyWithin(target, start, end) — copies its elements from position
start
till positionend
into itself, at positiontarget
(overwrites existing).将其元素从start
到end
在target
位置复制到 本身(覆盖现有)。
解构赋值
解构赋值是一种特殊的语法,它让我们可以将数组或对象进行“拆包”,存放到一系列的变量中,因为有时候使用变量更加方便。解构操作在那些具有很多参数和默认参数值的函数中也很奏效,
数组解构
以下是将数组解构到变量中的一个例子:
// 有一个存放了名字和姓氏的数组
let arr = ["Ilya", "Kantor"]
// 解构赋值
let [firstName, surname] = arr;
alert(firstName); // Ilya
alert(surname); // Kantor
现在我们就可以针对这些变量进行操作,而不是针对原来的数组元素。
当与 split
函数(或其他返回值是数组的函数)结合使用时,看起来就更优雅了:
let [firstName, surname] = "Ilya Kantor".split(' ');
这种语法叫做“解构赋值”,因为它通过将结构中的各元素复制到变量中来达到“解构”的目的。但数组本身是没有被修改的。
也就是以下语句的更精简写法而已
// let [firstName, surname] = arr;
let firstName = arr[0];
let surname = arr[1];
数组中不想要的元素也可以通过添加额外的逗号来把它丢弃:
// 不需要第一个和第二个元素
let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert( title ); // Consul
在以上的代码中,数组的第一个和第二个元素被跳过,第三个元素被赋值给了 title
变量,剩下的元素也被跳过了。
我们可以使用 .entries() 方法和解构语法来遍历一个对象的键-值对:
let user = {
name: "John",
age: 30
};
// 循环遍历键-值对
for (let [key, value] of Object.entries(user)) {
alert(`${key}:${value}`); // name:John, then age:30
}
对于 map 对象也类似:
let user = new Map();
user.set("name", "John");
user.set("age", "30");
for (let [key, value] of user.entries()) {
alert(`${key}:${value}`); // name:John, then age:30
}
剩余的 ‘…’
如果我们不仅要获得第一个值,还要将后续的所有元素也收集起来——我们可以使用三个点 "..."
加一个参数来接收“剩余的”元素:
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert(name1); // Julius
alert(name2); // Caesar
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
rest
变量的值就是数组中剩下的元素组成的数组。不一定要使用变量名 rest
,我们也可以使用其他的变量名,只要确保它前面有三个点,并且在解构赋值的最后一个参数位置上就行了。
默认值
如果赋值语句中变量的数量多于数组中实际元素的数量,赋值不会报错。未赋值的变量被当作 undifined
:
let [firstName, surname] = [];
alert(firstName); // undefined
所以如果我们想要提供一个“默认值”给未赋值的变量,我们可以使用 =
来提供:
// 默认值
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
alert(name); // Julius (来自数组的值)
alert(surname); // Anonymous (默认值被使用了)
默认值可以是更加复杂的表达式甚至可以是函数调用,这些表达式或函数只会在这个变量未被赋值的时候才会被计算。
对象解构
解构赋值同样适用于对象。
基本的语法是:let {var1, var2} = {var1:…, var2…}
在等号右侧有一个已经存在的对象,我们想把它拆开到变量中。等号左侧包含了对象相应属性的一个“模式”。
就像数组或函数参数一样,默认值可以是表达式甚至是函数调用。只会在这个变量未被赋值的时候才会被计算/调用。
以下的代码提示输入宽度 width,但不会提示输入标题 title。
let options = {
title: "Menu"
};
let {width = prompt("width?"), title = prompt("title?")} = options;
alert(title); // Menu
alert(width); // 你输入的宽度值
如果我们想把一个属性赋值给不同名字的变量,比如把 options.width 属性赋值给变量 w,那可以使用冒号来指定:
let options = {
title: "Menu"
};
let {width: w = 100, height: h = 200, title} = options;
alert(title); // Menu
alert(w); // 100
alert(h); // 200
剩余操作符
如果对象拥有的属性数量比我们提供的变量数量还多怎么办?我们可以只取其中的某一些属性然后把“剩余的”赋值到其他地方吗?
关于剩余操作符(即三个点)的文档几乎已经要被列为标准了,但大部分的浏览器还尚未支持。
let options = {
title: "Menu",
height: 200,
width: 100
};
let {title, ...rest} = options;
// now title="Menu", rest={height: 200, width: 100}
alert(rest.height); // 200
alert(rest.width); // 100
注:
let title, width, height;
{title, width, height} = {title: "Menu", width: 200, height: 100}; // 这一行发生错误
问题在于 JavaScript 把主代码流(即不在其他表达式中)的 {...}
当做一个代码块,这样的代码块可以被用来组织语句,如下:
{
// 一个代码块
let message = "Hello";
// ...
alert( message );
}
为了告诉 JavaScript 这不是一个代码块,我们可以把整个赋值表达式用括号 (...)
包起来:
let title, width, height;
// 现在就正确了
({title, width, height} = {title: "Menu", width: 200, height: 100});
alert( title ); // Menu
嵌套解构
如果一个对象或数组包含了其他的对象和数组,我们可以在等号左侧使用更复杂的模式来抽取深层的数据。
在以下代码中 options
的属性 size
是另一个对象,属性 items
是另一个数组。赋值语句中等号左侧的模式拥有相同的结构:
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true // 一些不会被解构的额外属性
};
// 为了清晰起见,解构赋值语句被写成多行
let {
size: { // 把 size 赋值到这里
width,
height
},
items: [item1, item2], // 把 items 赋值到这里
title = "Menu" // 在对象中不存在的属性(会使用默认值)
} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
alert(item1); // Cake
alert(item2); // Donut
最终,我们得到了 width
、height
、item1
、item2
和具有默认值的 title
变量。
有一个拥有很多属性的复杂对象,我们只想要抽取我们所需要的其中某些属性。这在解构赋值语句中是很常见的。
甚至还可能是这样的情况:
// 将 size 作为一个整体取出赋值给一个变量,忽略剩下的所有
let { size } = options;
智能函数参数
有时候一个函数可能有很多参数,大部分的参数是可选的
现实情况下的问题就是你怎么记得住这么多参数的顺序,通常集成开发环境工具(IDE)会尽力帮助我们,特别是当代码有良好的文档注释的时候,但… 另一个问题就是当大部分的参数采用默认值就好的情况下,怎么调用这个函数。
难道像这样?
showMenu("My Menu", undefined, undefined, ["Item1", "Item2"])
这太难看了。而且当我们处理更多参数的时候可读性还会变得更差。
解构赋值语法前来支援!
我们可以把所有参数当作一个对象来传递,然后函数马上把这个对象解构成多个变量:
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
// ...然后函数马上把对象展开成变量
function showMenu({
title = "Untitled",
width: w = 100, // width 赋值给 w
height: h = 200, // height 赋值给 h
items: [item1, item2] // items 第一个元素赋值给 item1, 第二个元素赋值给 item2
}) {
alert( `${title} ${w} ${h}` ); // My Menu 100 200
alert( item1 ); // Item1
alert( item2 ); // Item2
}
showMenu(options);
请注意,这种解构假定了调用 showMenu()
函数时传递了一个参数,如果我们想让所有的参数都使用默认值,那我们应该传递一个空的对象:
showMenu({});
showMenu(); // 这样会导致错误
我们可以通过指定空对象 {}
为整个函数参数的默认值:
// 清晰起见,精简了部分参数
function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
alert( `${title} ${width} ${height}` );
}
showMenu(); // Menu 100 200
在以上的代码中,整个参数对象默认就是 {}
,因此总会有对象可以用来解构。
总结
解构赋值允许将对象或数组立即映射到多个变量上。
解构对象的语法:
- let {prop : varName = default, ...} = object
这表示属性
prop
会被赋值给变量varName
,如果没有这个属性的话,就会使用default
的值。解构数组的语法:
- let [item1 = default, item2, ...rest] = array
数组的第一个元素赋值给
item1
,第二个元素赋值给item2
,剩下的所有组成另一个数组rest
。更多复杂的案例情况下,等号左侧必须和等号右侧有相同的结构。
完成了登录页
用Element UI完成了后台管理系统头部,侧边栏组件及子路由跳转框架
设置登录时,出了点问题,发现不像我想象中那么简单
一、跨域
Step1:配置BaseUrl
首先在main.js中,配置下我们访问的Url前缀:
import Axios from "axios"
Vue.prototype.$axios = Axios
Axios.defaults.baseURL = "http://dev.admin.carrots.ptteng.com" //配置默认发送请求到http://url,可改或者加端口号,这样每次发送请求都会带一个http//url
的前缀。
2.接着配置config/index.js,找到proxyTable,内部添加如下代码
proxyTable: {
'/carrots-admin-ajax': {
target: 'http://dev.admin.carrots.ptteng.com',//设置调用的接口域名和端口号(默认端口号80)
changeOrigin: true, //允许跨域
pathRewrite: {'^/carrots-admin-ajax': '' }
//这里理解成用‘/carrots-admin-ajax’代替target里面的地址,
}
},
因为我们给url加上了前缀 /carrots-admin-ajax,我们访问 http://localhost:80/a/login 就当于访问了:http://localhost:80/carrots-admin-ajax/a/login。(假设本地访问端口号为80)
又因为在 index.js 中的 proxyTable 中拦截了 /carrots-admin-ajax ,并把 /carrots-admin-ajax 及其前面的所有替换成了 target 中的内容,因此实际访问 Url 是http://dev.admin.carrots.ptteng.com/a/login。
完成配置后,发送请求,后台提示
Access to XMLHttpRequest at 'http://dev.admin.carrots.ptteng.com/a/login' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
即已拦截跨源请求:同源策略禁止读取位于XXX的远程资源。(原因:CORS 头缺少 ' Access-Control-Allow-Origin ')
然后才了解到
这叫跨域资源共享CORS,这么做需要后台添加请求头,才可以进行跨域访问,但一般不建议这样进行跨域,很容易遭XSS(虽然不懂是什么) 。
回到反向代理服务器
评论