想过的事
# 记录脑海里突然的疑问
# 1.我们在父组件向子组件传递参数时,用prop的时候,有几种情况:
- 传递的是基础数据类型的数据,这时候在子组件进行修改的时候,父组件是不会发生变化的。
- 传递的是对象类型的数据,这时候在子组件对这个对象进行修改的时候,会同时更改了父组件的对象(不提倡)。注:在子组件重新赋值另一个对象的时候,不会更改父组件的数据,父子组件的连接就切断了。
- 传递的是函数类型的数据,一般是为了让子组件向父组件传递数据的时候使用的。子组件在操作时,调用传递的函数时传入形参,函数在执行时,父组件拿到参数。
let a = 3;
b = a;
改变a的时候,b不会发生变化
let a = {
test:'3'
}
b = a;
改变a ,b也会发生变化,但是
b={
test2:'4'
}
b和a指向的对象不同了,互不影响了。
# 2.组件的data一般都是函数,不是对象。主要是为了组件在被引入的时候,避免多次引入的组件指向了同一个对象。
# 3.作用域插槽与匿名插槽,具名插槽相比,不同之处在于显示的数据是由子组件提供的,父组件只提供展示的样式。
1、具名插槽:<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽:
子:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
父:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</base-layout>
注意: v-slot 只能添加在 <template> 上 (只有一种例外情况,独占默认插槽),这一点和已经废弃的 slot attribute 不同。
在父组件上使用v-slot:插槽名称,这个是vue2.6.0以后的写法,在vue2.6.0之前,可以在模板上使用slot="插槽的名称",#footer是v-slot:footer简写
2、匿名插槽:组件中只能有一个,匹配完所有的具名插槽之后,剩余的的匹配匿名插槽(默认插槽)
子:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
父:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
现在 <template> 元素中的所有内容都将会被传入相应的插槽。
任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
然而,如果你希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
3、作用域插槽
子:user是子组件的属性
<span>
<slot v-bind:user="user" name='juming'>
{{ user.lastName }} //默认展示
</slot>
</span>
父:父组件使用子组件的属性
<current-user>
<template v-slot:juming="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>
独占默认插槽:作用域插槽中,当被提供的内容只有 默认插槽 时,组件的标签才可以被当作插槽的模板来使用。
这样我们就可以把 v-slot 直接用在组件上:
<current-user v-slot:default="slotProps"> //默认插槽这么用
{{ slotProps.user.firstName }}
</current-user>
这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot 被假定对应默认插槽:
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
</current-user>
# 4.null和undefined,初始赋值null,let a = null,表示a存储对象在未来,未赋值就是undefined
参考博客
js的基本数据类型:
- 五种简单数据类型(基本数据类型):Undefined、Null、Boolean、Number 和 String
- 复杂数据类型:Object。
undefined:
- 声明了一个变量,但未对其初始化时,这个变量的值就是undefined。
var data;
console.log(data === undefined); //true
console.log(typeof data); //"undefined"
注:如果data变量未提前声明:console.log(data === undefined); //报错
因为对于尚未声明过的变量,我们只能执行一项操作,即使用typeof操作符检测其数据类型,使用其他的操作都会报错。
一个函数如果没有使用return语句指定返回值,就会返回一个undefined值,或者调用函数时没有传参数值,参数同样也会被初始化为undefined值。
null:
- null值表示一个空对象指针,指示变量未指向任何对象
var data = null;
console.log(typeof data); // "object"
注:如果定义的变量在将来用于保存对象,最好将该变量初始化为null,当一个数据不再需要使用时,最好通过将其值设置为null来释放其引用(解除引用)。
console.log(null == undefined); //true ---undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true:
console.log(null === undefined); //false
标准相等符==,会转换其操作数为相同类型后再做比较; 严格相等符===,不会进行类型转换;
# 5.什么是盒子模型 :参考博客
- 盒子模型是CSS技术所使用的一种思维模型。我们可以把css盒子模型当成日常中的一个盒子去理解。
- content就是盒子里装的东西,它有高度(height)和宽度(width),可以是图片,可以是文字或者小盒子嵌套,在现实中,内容不能大于盒子,内容大于盒子就会撑破盒子,但在css中,盒子有弹性的,顶多内容太大就会撑大盒子,但是不会损害盒子。
- padding即是填充,就好像我们为了保证盒子里的东西不损坏,填充了一些东西,比如泡沫或者塑料薄膜,填充物有大有小,有软有硬,反应在网页中就是padding的大小了。
- border就是再外一层的边框,因为边框有大小和颜色的属性,相当于盒子的厚度和它的颜色或者材料。
- margin外边距,就是我们的盒子与其他的盒子或者其他东西的距离。假如有很多盒子,margin就是盒子之间直接的距离,可以通风,也美观同时方便取出。
- css盒子模型有两种,一种是W3C盒模型也就是标准模型,另一种是IE盒模型
# 6.class的定义与继承,原理
跳转至ES6学习记录
# 7.new的时候干了啥
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(链接到原型,绑定this值) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。
//定义一个Person类
class Person {
constructor(name,age){
this.name = name
this.age = age
}
speak(){
console.log(`我的名字是${this.name},年龄是${this.age}`);
}
}
let a = new Person('tom',13);
console.log(a,'this is a');
// 打印结果
Person {name: 'tom', age: 13}
age: 13
name: "tom"
--[[Prototype]]: Object
constructor: class Person
speak: ƒ speak()
[[Prototype]]: Object
//模拟过程
let a = {}; //创建空对象
a.__proto__ = Person.prototype;//会报错,仅模拟
Person.call(a);//绑定this
return a;
# 8.数组reduce
语法:
arr.reduce((preValue, current, index, arr)=>{},initialValue)
arr:当前操作的数组
preValue:第一次执行回调时为给定的初始值initialValue,以后是上一次执行回调时的返回值。
备注:若没有传入initialValue,则第一次的preValue值是数组中第一个元素的值。
current 表示当前正在处理的元素;
index 表示当前正在处理的数组元素的索引,若传入了initialValue值,则为0,否则为1;
array 当前操作的数组(就是arr)
initialValue 表示初始值。一般做数学运算时设置为0,若为筛选最值可以不传。
数组求和
const x = arr.reduce((preValue,current)=>{
console.log(preValue,current);
return preValue+current
})
数组中所有偶数的和---(条件求和)
const x = arr.reduce((preValue,current)=> preValue + (current % 2 === 0 ? current : 0),0)
数组中偶数有几个---(条件统计)
const x = arr.reduce((preValue,current)=> preValue + (current % 2 === 0 ? 1 : 0),0)
数组中所有偶数的乘积---(条件计算)
const x = arr.reduce((preValue,current)=>{
return preValue * (current % 2 === 0 ? current : 1)
},1)
数组中最小值-----(筛选最值)
const x = arr.reduce((preValue,current)=>{
console.log(preValue,current);
return Math.max(preValue,current)
})
# 9.堆和栈的理解
栈内存:
主要用于存放基本类型和对象变量的指针,给人的感觉就像是一个个线性排列的空间,每个小单元大小基本相等,存放的变量一般都是已知大小或者已知上限范围的,算是一种简单存储。
栈内存自动分配相对固定大小的内存空间,并由系统自动释放。
堆内存:
主要用于存放引用类型诸如object这类,存储的对象类型数据对于大小在这方面都是未知的。(所以这大概也是为什么null作为一个object类型的变量却存储在栈内存中的原因)。
堆内存是动态分配内存,内存大小不一,也不会自动释放。
总结:
从一个变量向另外一个变量复制基本类型的数据,会创建这个值的一个副本。从一个变量向另外一个变量复制引用类型的数据,复制的其实是这个值的一个指针,因此两个变量最终指向的都是同一个对象,即复制的是栈中的指针而不是堆中的对象。
# 10.事件委托和事件冒泡,事件捕获:参考博客
事件流:事件发生顺序
<div id="outer">
<div id="inner">Click me!</div>
</div>
如果outer和inner都有click事件,那么点击inner,哪个事件会被触发?
事件冒泡:
事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。
也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
div(inner) -> div(outer) -> body -> html -> document
事件捕获:
与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
上面的例子在事件捕获的概念下发生click事件的顺序应该是
document -> html -> body -> div(outer) -> div(inner)
addEventListener:
element.addEventListener(event, function, useCapture)
- useCapture:
- true - 事件句柄在捕获阶段执行(即在事件捕获阶段调用处理函数)
- false- false- 默认。事件句柄在冒泡阶段执行(即表示在事件冒泡的阶段调用事件处理函数)
阻止事件冒泡:
- 给子级加 event.stopPropagation( ):
$("#div1").mousedown(function(e){
var e=event||window.event;
event.stopPropagation();
});
- 在事件处理函数中返回 false
$("#div1").mousedown(function(event){
var e=e||window.event;
return false;
});
注:但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)。
event.stopPropagation()则只阻止事件往上冒泡,不阻止事件本身。
- 利用event.target==event.currentTarget来进行判断,在成立的时候处理逻辑
事件委托/事件代理:
由于事件会在冒泡阶段向上传播到父节点,可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。
一般尽可能使用事件冒泡,因为相对于事件委托,兼容性更好。
比如给ul标签下的一万个li标签绑定监听处理点击li的逻辑:
可以在ul上绑定监听,每次点击li的时候都会在ul监听到,然后通过判断event.target来判断点击来源,处理逻辑。
# 11.表单组件默认操作,阻止默认事件:参考博客
event.preventDefault
# 12.原型链画图
# 13.接口返回的字节流和文件是怎么下载的
# 14.scollHeight,scollTop等属性的使用
- clientHeight
定义: 只读属性,对于没有定义CSS或者内联布局盒子的元素为0,
否则,它是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距
计算: clientHeight 可以通过 CSS height + CSS padding - 水平滚动条高度 (如果存在)来计算
注意: 返回的是四舍五入的整数值,想要获得小数值使用element.getBoundingClientRect(),但是这个小数值是包含边框的,慎用。
inline元素也是没有的
offsetHeight
定义: 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。
计算: height+padding+滚动条(如果存在)
注意: 如果元素被隐藏(例如元素或者元素的祖先之一的元素的style.display被设置为none),则返回0。 inline元素也是没有的
scrollHeight
定义: 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。
注意: scrollHeight 的值等于该元素在不使用滚动条的情况下为了适应视口中所用内容所需的最小高度。 没有垂直滚动条的情况下,scrollHeight值与元素视图填充所有内容所需要的最小值clientHeight相同。 包括元素的padding,但不包括元素的border和margin。scrollHeight也包括 ::before 和 ::after这样的伪元素。
scrollTop
定义: Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。
注意: 一个元素的 scrollTop 值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。 当一个元素的内容没有产生垂直方向的滚动条,那么它的scrollTop值为0。 在使用显示比例缩放的系统上,scrollTop可能会提供一个小数。
如果一个元素不能被滚动(例如,它没有溢出,或者这个元素有一个"non-scrollable"属性), scrollTop将被设置为0。
设置scrollTop的值小于0,scrollTop 被设为0
如果设置了超出这个容器可滚动的值, scrollTop 会被设为最大值。
offsetParent
定义: 最近的一个非static的定位元素,是disblock:none则为0,父元素没有定位则是body元素
offsetTop
定义: 最近的一个非static的定位元素之间的距离包括父元素的padding+本身的padding,是disblock:none则为0,没有定位父元素,不然就是到body的距离。 总结: 利用这个原理我们可以制作关于滚动条合适下拉到底,那么就可以做下拉加载的功能。 当clientHeight+scrollTop=scrollHeight就是滑动到底的临界条件。
# 15.ajax,axios,fetch
# 16.在react和redux中,尽量少用push和unshift,这样会改变所有元素的位置,底层算法有时会比较堆内存,相同可能不会出发更新。
# 17.if判断有哪些情况会自动计算boolean值
undefined、null、 0、NaN或空字符串("")会被判false
注: 不要将原始布尔值的true和false与Boolean对象的真或假混淆。参考博客
任何一个值,只要它不是 undefined、null、 0、NaN或空字符串(""),那么无论是任何对象,即使是值为假的 Boolean 对象,在条件语句中都为真。
例如:
var b = new Boolean(false);
if (b) //表达式的值为 true
var b = Boolean(false);
if (b) //表达式的值为 false
# 18.网页怎么变黑白
css:
filter: grayscale(1)
# 19.展开运算符
//展开对象,只能在括号中使用,否则会报错,可以理解成浅拷贝
let sex = {look:'man',actual:'women'};
let person = {sex:sex,age:25};
let copyPerson = {...person};
sex.look = 'boy';
console.log(copyPerson,'this is copyPerson')
//展开数组,可以传参时使用,多余的参数自动作废,或者使用arguments接收
let tempArr = [2,4,6,8,9];
let tempArr2 = [5,4,7,8,545];
let endArr = [...tempArr,...tempArr2]
console.log(...tempArr,endArr);
function testzhankai(a,b,c) {
console.log(a,b,c,'test zhankai') //2,4,6
console.log(arguments) //Arguments(5)> 2,4,6,8,9
}
testzhankai(...tempArr);
# 20.DOM
一、DOM全称
文档对象模型(Document Object Model)
二、DOM是什么
DOM就是一个编程接口,就是一套API。
DOM是针对HTML文档、XML等文档的一套API。就类似于JDBC是针对数据库的一套API一样。
三、DOM的用途
DOM 是用来访问或操作HTML文档、XHTML文档、XML文档中的节点元素。
现在基本上所有的浏览器都都执行了W3C发布的DOM规范,所以在浏览器上就可以用DOM的这些API。
四、DOM与其他技术的联系
JavaScript 可以通过 DOM 来访问和操作HTML文档所有的元素。
JavaScript是一种脚本语言,DOM是用来获得和操作HTML文档的节点属性。
JavaScript通常是通过DOM来获得和操作HTML属性的。这就是二者的区别与联系。
五、DOM 与 HTML
HTML文档是树状结构,根为;DOM也是树状结构,根为window或document对象。
所以DOM就可以把HTML以树状的形式呈现出来。
六、DOM的分类
核心 DOM:定义了一套标准的可以针对任何文档的对象。
HTML DOM:针对HTML文档的DOM。
XML DOM:针对XML文档的DOM。
七、DOM的级别Level
DOM0:不是W3C规范。
DOM1:开始是W3C规范。专注于HTML文档和XML文档。
DOM2:对DOM1增加了样式表对象模型
DOM3:对DOM2增加了内容模型 (DTD 、Schemas) 和文档验证。
# 21.或者运算符
let a = 1;
let b = 2;
let c = 3;
let result = a || b || c;
console.log(result); // 1
上面的代码中,当 a 为 truthy 值(即非 null、非 undefined、非 0、非 NaN、非 '' 等)时,
由于或运算符的短路特性,b 和 c 不会再被执行,返回结果为 a 的值。否则,若 a 为 falsy 值,就继续检查下一个值,返回第一个 truthy 值。
# 22.工具类如何全局注册
# 23.nginx服务器的使用
# 24.url传递参数的最大限制
# 25.blob对象的下载
# 26.git rebase和git merge的区别
git merge <source-branch>
比如你在feature分支,需要合并dev的新的其他人的提交(dev就是源分支),就是:
git merge dev
# 27.js的&&
在 JavaScript 中,逻辑运算符 && 具有左结合性(left-associativity),但没有优先级的概念。
这意味着在使用多个 && 运算符时,它们按从左到右的顺序进行求值。
例如:表达式 A && B && C 首先求解 A,如果 A 的结果为 false,则整个表达式的结果为 false,不再求解 B 和 C。
如果 A 的结果为 true,则继续求解 B,并根据 B 的结果继续求解 C。最终,整个表达式的结果将是 C 的结果。
这种求值顺序类似于逻辑门电路中的级联,因此 && 运算符常被称为“逻辑与”运算符,它要求所有操作数都为 true 才会返回 true。
# 28. 为什么0.1+0.2 != 0.3
当将十进制数转换为二进制数时,0.1 和 0.2 都会产生无限循环的二进制表示形式。
这是因为在二进制中,有些小数无法精确表示,就像在十进制中无法精确表示 1/3 一样。
下面是将 0.1 和 0.2 转换为二进制表示的简化步骤:
将 0.1 转换为二进制:
乘以 2,得到 0.2,整数部分为 0。
乘以 2,得到 0.4,整数部分为 0。
乘以 2,得到 0.8,整数部分为 0。
乘以 2,得到 1.6,整数部分为 1。
乘以 2,得到 1.2,整数部分为 1。
乘以 2,得到 0.4,整数部分为 0。
乘以 2,得到 0.8,整数部分为 0。
乘以 2,得到 1.6,整数部分为 1。
乘以 2,得到 1.2,整数部分为 1。
继续该过程下去,得到无限循环的二进制表示形式:0.0001100110011...
将 0.2 转换为二进制:
乘以 2,得到 0.4,整数部分为 0。
乘以 2,得到 0.8,整数部分为 0。
乘以 2,得到 1.6,整数部分为 1。
乘以 2,得到 1.2,整数部分为 1。
继续该过程下去,得到无限循环的二进制表示形式:0.001100110011...
由于这种无限循环,将它们精确表示为二进制是不可能的.
在计算机中,它们的二进制表示会被截断为有限位数,从而引入舍入误差。
因此,在实际计算中,0.1 和 0.2 的精确值不是直接使用它们的二进制表示,而是使用近似值进行计算。
这导致了 0.1 + 0.2 的结果略微偏离于 0.3。
如果在需要高精度计算的情况下,可以考虑以下解决方案:
1、使用专门的高精度计算库:可以使用第三方库或语言内置的高精度计算库,这些库提供了更精确的数值计算功能。
例如,在 JavaScript 中,可以使用 Decimal.js、Big.js 等库来进行高精度计算。
2、手动实现精确计算:如果不想依赖外部库,也可以手动实现高精度计算。
一种常见的方法是使用字符串表示数字,然后编写相应的算法来进行精确计算。通过使用字符串表示,可以绕过浮点数的精度问题。
然而,这样做可能会降低计算速度和增加代码复杂性。
3、调整计算顺序:有时,通过重新排列计算顺序可以减少舍入误差的影响。
例如,如果某个计算顺序导致大数与小数相加,可以尽量将相似大小的数值进行相加,然后再进行舍入。这样可以减小舍入误差的累积效应。
4、使用整数计算:对于需要高精度的货币计算等场景,可以将小数转换为整数,进行整数计算,然后再将结果转换回小数形式。
这可以避免浮点数精度问题,因为整数计算没有舍入误差。
无论选择哪种方法,都需要根据具体情况进行权衡。高精度计算往往会带来性能上的开销,因此在性能和精度之间需要找到平衡点。
# 29.使用axios的时候的坑
在使用 axios.get(url) 发起请求时,如果实际的请求地址前面加了其他的 URL,可能有以下几种原因:
1.相对路径:如果你提供的 url 参数是一个相对路径,而不是一个完整的绝对路径,那么请求将根据当前页面的 URL 进行解析。在这种情况下,浏览器会自动将相对路径解析为绝对路径,将其与当前页面的 URL 进行拼接,形成实际的请求地址。
确保 url 参数包含协议、主机名和路径等必要信息。
2.基础 URL 配置:在使用 Axios 时,你可以配置一个基础 URL(base URL),它将作为所有请求的前缀。这样,当你传递一个相对路径给 axios.get() 时,Axios 将会自动将基础 URL 与相对路径拼接成实际的请求地址。
例如,如果你配置了基础 URL 为 http://api.example.com,并使用 axios.get('/users') 进行请求,实际的请求地址将会是 http://api.example.com/users。
3.拦截器或请求拦截器:如果你在 Axios 中使用了拦截器或请求拦截器,它们可以在请求发出之前修改请求配置。这可能包括修改请求的 URL,添加前缀或其他参数等。
请检查你的拦截器或请求拦截器的代码,确保没有对请求的 URL 进行额外的修改。
检查这些原因,并确认在请求中提供的 URL 参数是否正确,以及是否存在其他代码或配置会影响到实际的请求地址。
30.localstorage
localStorage 中存储的数据在以下情况下会被清除:
手动清除:你可以通过调用 localStorage.clear() 方法清除整个 localStorage 中的数据。
用户清除浏览器数据:当用户在浏览器中清除缓存或删除浏览器数据时,包括清除浏览历史记录、缓存文件、Cookie 等,localStorage 中的数据也会被清除。
存储空间限制:localStorage 的存储空间是有限制的,通常为几兆字节。如果你的数据超过了存储空间限制,新的数据存储会替换掉旧的数据。
域名或协议更改:localStorage 是基于域名的,当你访问不同的域名或子域名时,localStorage 中的数据是隔离的,不会共享。如果你切换到一个不同的域名或子域名,之前存储的数据将不再可访问。
私密浏览模式:在私密浏览模式下,浏览器通常会禁用 localStorage,并在会话结束时自动清除 localStorage 中的数据。
请注意,localStorage 中的数据是持久存储的,它会一直存在,直到满足上述情况之一导致数据被清除。因此,除非你显式地清除或满足以上条件,否则 localStorage 中的数据将一直保留。
31.v-bind='$attrs'
在Vue中,组件上使用v-bind="$attrs"
是一种特殊的用法,它用于将父组件传递给子组件的非声明属性(non-prop attributes)传递给子组件的根元素。
当你在一个组件上使用v-bind="$attrs"
时,Vue会将父组件中传递给该组件的所有非声明属性收集起来,并将它们应用到该组件的根元素上。
举个例子,假设有一个父组件和一个子组件:
<!-- ParentComponent.vue -->
<template>
<div>
<ChildComponent id="child" class="red" data-text="Hello" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
};
</script>
<!-- ChildComponent.vue -->
<template>
<div v-bind="$attrs">
<!-- 子组件的内容 -->
</div>
</template>
<script>
export default {
inheritAttrs: false
};
</script>
在上面的例子中,父组件传递给子组件的非声明属性包括id
、class
和data-text
。子组件中的v-bind="$attrs"
将这些非声明属性应用到子组件的根元素上。
最终生成的HTML将会是:
<div>
<div id="child" class="red" data-text="Hello">
<!-- 子组件的内容 -->
</div>
</div>
通过这种方式,你可以轻松地将父组件的属性传递给子组件的根元素,而无需在子组件中一个个地声明这些属性。这在需要将大量属性传递给子组件时非常方便。
32、websocket协议