Html5
新标签:
-
<header>定义文档的页眉,头部信息</header>
-
<nav>定义导航连接的部分</nav>
-
<footer>定义文档的页脚,底部信息</footer>
-
<article>内容区域</article>
-
<section>区块</section>
-
<aside>定义其当前所处内容以外的内容,侧边栏</aside>
-
音频标签/(视频标签video)<audio src="" controls autoplay loop></audio> autoplay 自动播放 controls 是否显示播放控件 loop 循环播放 多浏览器支持方法:<audio><source src=“"></source></audio>
新属性 :
-
Placeholder:默认值、autofocus自动获取焦点、autocomplete自动完成、multiple多文件上传、required必填
-
type属性:email、tel、number、url、date、search(搜索框)、range(自由拖动的滑块)
怎么理解语义化标签 ????
-
正确的标签做正确的事情,无CSS样式时也容易阅读,便于阅读维护和理解
-
页面内容结构化
-
便于浏览器、搜索引擎解析。 利于爬虫标记、利于SEO搜索引擎优化
Css
盒子模型 :
-
标准盒模型:box-sizing:content-box;width(content)
-
怪异盒模型:box-sizing:border-box;width(content+padding+border)
flex弹性布局 :
-
flex子项目在主轴的缩放比例 :flex: 2; 约束份数,整数值(使用后宽高失效). 如果用百分数,要加起来是100才可以用. 可实现圣杯布局
-
flex-direction调整主轴方向:row 、row-reverse、 column 、column-reverse
-
flex-wrap控制是否换行: nowrap、wrap、wrap-reverse;
-
flex-flow是flex-direction、flex-wrap的简写形式
-
align-items调整侧轴对齐(垂直对齐)(单行)stretch; 默认值。项目被拉伸以适应容器。center; 项目位于容器的中心。flex-start; 项目位于容器的开头。垂直对齐开始位置 上对齐、 flex-end; 项目位于容器的结尾。垂直对齐结束位置 底对齐
-
align-content堆栈(由flex-wrap产生的独立行)多行垂直对齐方式齐
-
stretch; 默认值。项目被拉伸以适应容器。center; 项目位于容器的中心。flex-start; 项目位于容器的开头。flex-end; 项目位于容器的结尾。 space-between; 项目位于各行之间留有空白的容器内。(中间空白)、space-around 项目位于各行之前、之间、之后都留有空白的容器内。(空白包裹项目)
-
必须设置以下属性才会起作用。对父元素设置自由盒属性display:flex;设置排列方式为横向排列flex-direction:row;设置换行flex-wrap:wrap;
-
-
align-self自己的对齐方式;
-
justify-content调整主轴对齐(水平对齐)
-
order控制子项目的排列顺序:用整数值来定义排列顺序,数值小的排在前面。可以为负值。 默认值是 0
布局方式 :
垂直居中 :
已知盒子宽高: w100px;h100px
-
position:absolute;left: 50%; top : 50%; margin-top: -50px; margin-left: -50px; 定位之后需要退回盒子高宽一半的距离。
-
利用 margin:auto 属性。 position:absolute; margin:auto; top:0; left:0; right:0; bottom:0;
未知盒子宽高:
-
transform:translate(x,y); 将margin换为—》transform: translate(-50%, -50%);
-
flex弹性布局 父元素设置: display: flex; justify-content: center; align-items: center;
左列定宽,右列自适应 :
使用flex实现 :.parent{display:flex;} .left{width:100px;} .right{flex:1;}
利用float+margin实现 :.left{float:left;width:100px;} .right{margin-left:100px;}
使用float+overflow实现 .left{width:100px;float:left;} .right{overflow:hidden;}. overflow:hidden,触发bfc模式,浮动无法影响,隔离其他元素
两侧定宽,中栏自适应 :
利用flex实现 : .parent{display:flex;} .left{width:100px;} .center{flex:1;}
利用float+margin实现 : .left{width:100px;float:left;} .right{width:100px;float:right;} .center{margin-right:200px;margin-left:200px;}
两列定宽,一列自适应 : (基本html结构为父容器为parent,自容器为left,center,right.其中,left,center定宽,right自适应 )
利用flex实现: .parent{display:flex;} .left,.center{width:100px;} .right{flex:1}
利用float+margin实现 : .left,.center{float:left:width:100px;} .right{margin-left:200px;}
利用float+overflow实现 : .left,.center{float:left:width:100px;} .right{overflow:hidden;}
定位 :
静态定位:position:static;静态位置就是各个元素在HTML标准流中默认的位置。
相对定位:relative不脱标、元素相对于它在标准流中的位置进行定位、在标准流中的位置仍然保留。
绝对定位:absolute 脱离标准流,不占空间、找到最近的有定位(非static)的父元素才相对移动、子绝父相
块级元素、行内元素、行内块元素 :
常见的块元素:<h1>~<h6>、<p>、<div>、<ul>、<ol>、<li>等,其中<div>标签是最典型的块元素。
块级元素的特点:
-
独占一行
-
宽度默认是容器的100%
-
高度,行高、外边距以及内边距都可以控制。
-
可以容纳内联元素和其他块元素。(理解为可以容纳所有)
-
注意 : p 里面不能放块级元素,同理还有这些标签h1,h2,h3,h4,h5,h6,dt,他们都是文字类块级标签,里面不能放其他块级元素。
常见的行内元素:<a>、<strong>、<b>、<em>、<i>、<del>、<s>、<ins>、<u>、<span>等,其中<span>标签最典型的行内元素。
行内元素的特点:
-
和相邻行内元素在一行上
-
默认宽度就是它本身内容的宽度。
-
高、宽无效,但水平方向的padding和margin可以设置,垂直方向的无效。
-
行内元素只能容纳文本或则其他行内元素。(a特殊)
-
注意:链接里面不能再放链接。
常见行内块元素: <img />、<input />、<td>
行内块元素的特点:
-
和相邻行内元素(行内块)在一行上,但是之间会有空白缝隙。
-
默认宽度就是它本身内容的宽度。
-
高度,行高、外边距以及内边距都可以控制。
选择器权重 :
!important
内联样式(标签内style形式)
Id选择器
类选择器、属性选择器、伪类选择器
元素、伪元素选择器
通配符选择器 0
继承的权重最低
伪类选择器 :
链接伪类选择器:
-
link /* 未访问的链接 */
-
:visited /* 已访问的链接 */
-
:focus /* 聚焦状态 */
-
:hover /* 鼠标移动到链接上 */
-
:active /* 选定的链接 */
结构(位置)伪类选择器 :
-
:first-child
-
:last-child
-
:nth-child(n)
-
:nth-last-child(n)
目标伪类选择器:
-
:target 和锚点配合使用
px、em、rem的区别 :
-
px(像素 Pixel )相对长度单位。相对于显示器屏幕分辨率而言的。利用 px 设置字体大小及元素宽高等比较稳定和精确。Px 的缺点是其不能适应浏览器缩放时产生的变化,因此一般不用于响应式网站。
-
em 相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(一般为16px)。可以继承父元素尺寸大小。
-
rem : 1rem = html中font-size大小
浮动
-
浮动元素特性:
-
浮动元素元素会具有行内块元素的特性。
-
浮动脱离标准流,不占位置,会影响标准流。浮动只有左右浮动。
-
浮动的元素总是找离它最近的父级元素对齐。但是不会超出内边距的范围。
-
元素的大小完全取决于定义的大小或者默认的内容多少.
-
-
浮动的元素排列位置:
-
浮动的元素顶端对齐,浮动元素不会和行内级元素层叠.
-
上一个元素是(标准流)块级元素:则A元素会在他的下一行.
-
上一个元素是(浮动)块级元素:则A元素会在他的同一行.
-
上一个元素是行内元素或者行内块元素:会先找到父元素对齐,再和行内元素或者行内块元素混在一行显示
-
上一行元素是纯文本:只会在当前行左右浮动,文字环绕
-
下一个元素是纯文字:文字环绕
-
-
清除浮动:清除浮动后造成的影响—》清除浮动主要为了解决父级元素因为子级浮动引起内部高度为0 的问题。
-
额外标签法:在浮动元素末尾添加一个空的标签<div style="clear:both"></div>
-
父级添加overflow属性方法:可以给父级添加:overflow: hidden|auto|scroll; 都可以实现。
-
使用before和after伪元素清除浮动:
-
-
固定定位:相对于浏览器视口。完全脱标,不占有位置,不随着滚动条滚动。
-
.clearfix::after{ content:"."; clear:both; display:block; height:0; visibility:hidden; /* line-height: 0px; */ } .clearfix{ *zoom:1;}/* IE6、7 专有 */ 由于IE6-7不支持:after,使用 zoom:1触发 hasLayout。
bgc-属性:
-
background-color背景颜色red;#ff0000;rgb(255,0,0);rgba(255,0,0,0.3);transparent相当于rgba(0,0,0,0);完全透明; opacity:0-1之间取值
-
background-image: url(路径); 背景图片
-
background-repeat背景是否重复(是否平铺) repeat | no-repeat | repeat-x | repeat-y
-
background-position背景位置 可以是具体px 也可以是方位 -》background-position: 15px top;
-
background-attachment背景是否滚动 scroll | fixed
-
background: 背景颜色 图片地址 是否重复 背景位置 是否滚动 ; 背景的复合属性
-
background-size背景缩放:设置长度单位(px)或百分比 、cover保证图片始终填充满背景区域 、contain保证图片
-
多背景: 以逗号分隔可以设置多背景,设置的多重背景图之间存在着交集(即存在着重叠关系),前面的背景图会覆盖在后面的背景图之上。避免背景色将图像盖住,背景色通常都定义在最后一组上,
-
渐变颜色background:linear-gradient:(角度,颜色 百分比,颜色 百分比);
浅谈javascript特性 :
-
解析执行:轻量级解释型(不需要编译)的,或是 JIT 编译型(即时 实时 编译)的程序设计语言
-
语言特点:动态语言,头等函数 (First-class Function)(又称函数是 JavaScript 中的一等公民)
-
执行环境:在宿主环境(host environment)下运行,浏览器是最常见的 JavaScript 宿主环境,但是在很多非浏览器环境中也使用 JavaScript ,例如 node.js
-
编程范式:基于原型、多范式的动态脚本语言(辅助语言),并且支持面向对象、命令式和声明式(如:函数式编程)编程风格
-
JavaScript 的组成 :
组成部分
说明
Ecmascript
描述了该语言的语法和基本对象
DOM
描述了处理网页内容的方法和接口
BOM
描述了与浏览器进行交互的方法和接口
JavaScript 执行过程 :
预解析
-
全局预解析(所有变量和函数声明都会提前;同名的函数和变量,函数的优先级高)
-
函数内部预解析(所有的变量、函数和形参都会参与预解析)
执行
先预解析全局作用域,然后执行全局作用域中的代码, 在执行全局代码的过程中遇到函数调用就会先进行函数预解析,然后再执行函数内代码。
事件冒泡、捕获、事件委托(代理):
事件捕获:结构上(非视觉上)嵌套关系的元素,会存在事件捕获功能,即同一事件,自父元素捕获至子元素(事件源元素)(自顶向下)
事件冒泡:结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,即同一事件,自子元素冒泡像父元素(自底向上);停止冒泡 :事件对象.stopPropagation();
DOM事件流的三个阶段是先捕获阶段,然后是目标阶段,最后才是冒泡阶段。
事件代理 : 就是利用事件冒泡机制 —》把一系列的内层元素事件 绑定到 外层元素。
可以通过 element.addEventListener() 设置一个元素的事件模型为冒泡事件或者捕获事件。
默认值false,表示事件冒泡;设为true时,表示事件捕获
数据类型 :
基本类型有6种,分别是undefined,null,bool,string,number,symbol(ES6新增)
虽然 typeof null 返回的值是 object,但是null不是对象,而是基本数据类型的一种。
基本数据类型存储在栈内存,存储的是值。
复杂数据类型的值存储在堆内存,地址(指向堆中的值)存储在栈内存。当我们把对象赋值给另外一个变量的时候,复制的是地址,指向同一块内存空间,当其中一个对象改变时,另一个对象也会变化。
判断数据类型方法:
-
简单数据类型: typeof
-
复杂数据类型( array object ):
-
Instance of (不算最直接的判断方法)
-
is.array (es6里面最简单常用的是)
-
原型链上tostring的方法。 通过Object下的toString.call()方法来判断。Object.prototype.toSring().call(arr)
-
根据对象的contructor判断
-
解释 JavaScript 中的 null 和 undefined :
undefined 表示 声明没赋值;有容器没赋值
null表示一个空的对象,什么也没有。没容器
undefined是从null派生出来的
null == undefined //true
null === undefined //false
typeof null // 'object'
typeof undefined // 'undefined'
作用域和作用域链 :
-
作用域 :就是一个独立的空间,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
-
全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
-
函数作用域:函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。
-
块级作用域 :块级作用域可通过es6的let和const声明,所声明的变量在指定块的作用域外无法被访问。
-
-
作用域链:当访问一个变量时,会先从本身作用域中去找这个变量,若找不到则向上一级作用域中去找,依次类推,就形成了一个作用域链。
变量声明提升 :
比如var a = 1; 未声明变量前,去使用变量,并不报错,而是打印undefined,将var a;变量提升了;
call、apply、bind区别:
-
call(对象, 参数1,2,…),换掉了this, 支持传参, 执行了方法, 只有当次调用有效
-
apply(对象, [1,2,3]);换掉了this, 参数以数组的形式传进去, 执了行方法, 只有当次调用有效
-
bind(对象, 参数1,2,..);换掉了this,不执行当前函数,以返回值的形式给出新的函数。 每次调用都有效
es6 :
-
创建变量 :var let const区别
-
var:有变量提升,没有块级作用域。
-
let:没有变量提升,必须先定义再使用。全局变量不会附加到window对象的属性中。不能重复定义。具有块级作用域
-
const :一旦声明立即初始化。没有变量提升,全局变量不会附加到window对象的属性中。具有块级作用域
-
const创建的常量什么能改变,什么不能改变????
-
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
-
-
let暂时性死区:在块级作用域内,没有声明变量前,变量是不可用的。
-
-
解构赋值 :
-
数组 :
-
变量个数等于数组长值
-
变量个数大于数组长度: 有默认值使用默认值,无默认值undefined
-
变量个数小于数组长度 : 忽略
-
用空格跳过不需要的值
-
剩余值 :扩展运算符,最后一个参数前面加三个…,可以获取传进来的多余的参数的数组
-
复杂嵌套场景
-
-
对象 :
-
(...)
-
可以给变量起别名
-
-
-
箭头函数 :
-
写法简单:
-
只有一个参数,可以省略()
-
只有一条命令语句 ,可以省略{}
-
只有一条命令语句 且是return,可以省略{}和 return
-
-
与普通函数区别:
-
没有arguments(伪数组),有扩展运算符得到的是真数组
-
this指向是当前作用域以外的那个作用域
-
不能做构造函数
-
-
-
扩展运算符 : 可以获取传进来的多余的参数的数组,与arguments(伪数组相比),扩展运算符得到的是真数组;
-
字符串模版 : 反引号,${}为界定符号,里面可以使用变量,表达式;可以在里面换行
-
set对象 : let set = new Set() 数组去重 、for循环解决数组去重(两个for循环嵌套,I=0,i<arr.length; j<I+1;j<arr.lenght;arr[I]=arr[j]时;splice(j,1))
Arr数组api : 不改变原数组 slice concat
-
push 在数组最后一个位置添加元素
-
pop 在数组最后一个位置删除一个元素,会修改数组的长度
-
shift 在数组最开始的位置删除一个元素;修改数组的长度
-
unshift 在数组最开始的位置添加一个元素;修改数组的长度
-
sort 排序
-
reserve 反转
-
splice 删除 替换 插入
-
slice 剪切 包左不包右. 不会修改原数组
-
split 替换字符串 返回数组
-
concat() 把两个数组拼接到一块,返回一个新数组 ;(arr.push()打印新的数组是二维数组);不改变原数组
-
arr.toString() 把数组转换为字符串,用逗号分隔
-
arr.indexOf() 找数组中某个数的索引 没找到返回-1
-
arr.join() 替换分隔符
-
Array.isArray() 判断是不是数组
-
Array.from() 把其它非数组的对象转成数组。自定义对象、arguments 伪数组、dom操作拿到的NodeList集合
-
arr.find((item,index,arr)=>{}) arr.find找到数组中第一个满足条件的成员并返回该成员,如果找不到返回 undefined。
-
arr.findIndex((item,index,arr)=>{}) arr.findIndex找到数组中第一个满足条件的成员并返回该成员索引,如果找不到返回 -1。
-
arr.includes(必须->表示查找的内容,可选->表示开始查找的位置,0表示从第一个元素开始找。默认值是0。) 判断数组是否包含某个值
-
forEach()(回调函数,对象(this))
-
map() 返回值 组成数组
-
filter() 返回值的布尔类型是true 的 组成数组
-
some() 返回值有一个是true 就返回true
-
every() 返回值有一个是false 就返回false
-
reduce(参数一,参数二) 求数组的和
-
参数一:函数遍历、function(preValue,n){};第一次遍历结果preValue为0,因为初始值为0 ;n为数组值;第二次遍历结果preValue为return返回值,n为数组值
-
参数二:初始值,一般写0
-
闭包:
-
闭包是(两个)函数嵌套,里面的函数用外面函数的变量,将里面函数暴露出来,(里面的函数重要),再调用
-
闭包的原因:返回的函数并非孤立的函数,而是连同周围的环境(AO)打了一个包,成了一个封闭的环境包,共同返回出来 ---->闭包。我们在返回函数的时候,并不是单纯的返回了一个函数,我们把该函数连同他的AO链一起返回了。
-
优点:缓存数据保数据的安全, 不会污染全局变量,形成块级作用域,变量私有化
-
缺点 :
-
内部执行完,函数弹栈,一旦被清除,无法访问这些数据了。—》 js垃圾回收机制:js 中的变量和函数不再使用后,会被自动js垃圾回收机制回收。
-
占用内存:内部套多层,要等到执行到最里面,才一层层弹栈.
-
-
什么时候使用 :可以用来创建私有变量或函数
for循环里面绑定事件 形成闭包
解决办法1 : 用立即执行函数解决闭包
for(vari=0; i<10; i++){
document.body.addEventListener('click',(()=> {
console.log(i). // 如果不用立即执行函数打印出10个10,用的话打印0123456789
})(i))
}
解决办法2 : ES6 let 块级作用域
var liArr=document.querySelectorAll('li');
for(leti=0; i<liArr.length; i++){
liArr[i].onclick=function(){
console.log(i);
}
}
原型、原型链 :
在每一个实例对象中的_proto_(原型),中同时有一个constructor(构造器)属性,该属性指向创建该实例的构造函数:
每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
原型链思想:先在自己身上找,找到即返回,自己身上找不到,则沿着原型链向上查找,找到即返回,如果一直到原型链的末端Object.prototype.还没有找到,则返回 null。
js预编译
function test(){}
var test=new Function()
test.__proto__== Function.prototype. // 构造函数创建的实例对象的都有__proto__指针指向构造函数的prototype
Function.prototype.__proto__= Object.prototype
// 空对象 Object的原型
new的过程 :
-
创建一个新对象 (开辟堆内存空间)
-
将构造函数的作用域赋给新对象(让内部的this 指向了这个新对象)(接下来所有针对 this 的操作实际上操作的就是 新对象)
-
调用构造函数 (执行构造函数中的代码)
-
返回新对象( 如果构造函数没有显式的返回值,隐式的返回this对象)
Js继承方式 :
借用构造函数继承,原型链继承,组合继承,原型式继承、寄生式继承,寄生组合继承、es6的类继承
借用构造函数继承 :在子类构造函数的内部调用父类构造函数 使用apply()或call 方法,换掉this对象
缺点 :只能继承父类的实例属性和方法,不能继承原型属性/方法
function Parent(name) {
this.colors=["red","blue","green"];
this.name=name;
}
function Sun(name,age) {
// 关键点 继承 Parent 类 并传递了参数
Parent.call(this,name,age)
this.age=age;
}
var s1=new Sun('jack',18);// {colors: Array(3), name: "jack", age: 18}
console.log(s1);
原型链继承 :将别人的实例变为自己的原型。子类可以通过原型链的查找,实现父类的属性公用与子类的实例
缺点: 一些引用数据操作的时候会出问题,两个实例会公用继承实例的引用数据类
function Parent() {
this.property=true;
this.colors=["red","blue","green"];
}
Parent.prototype.getParentValue=function() {
return this.property
}
function Sun() {
this.sunProperty=false;
}
Sun.prototype=newParent(); // 关键 创建Sun的实例,并将该实例赋值给Sub.prototype
Sun.prototype.constructor=Sun;
Sun.prototype.getSunValue=function() {
return this.subProperty
}
var s1=new Parent();
console.log(s1.getParentValue())//true
var s2=new Parent();
s2.colors.push("black");
console.log(s1.colors)// ["red", "blue", "green"]
组合继承:用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承。
缺点 :调用两次超类型, 存在两份相同的属性/方法,实例和原型上各有一份
function Parent(name) {
this.colors=["red","blue","green"];
this.name=name;
}
Parent.prototype.sayName=function() {
console.log(this.name)
}
function Sun(name, age) {
// 关键点 继承 属性
Parent.call(this, name)//第二次调用
this.age=age
}
//继承父类原型方法
Sun.prototype=newParent()//第一次调用
// 重写SubType.prototype的constructor属性,指向自己的构造函数SubType 否自指向超类型
Sun.prototype.constructor=Parent;
Sun.prototype.sayAge=function() {
console.log(this.age)
}
var s1=new Sun('小明',20);
s1.colors.push("black");
console.log(s1.colors)// ["red", "blue", "green", "black"]
s1.sayAge()//20
s1.sayName()// 小明
原型式继承 :利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。
缺点:不能做到函数复用、共享引用类型属性的值、无法传递参数
function object(obj) {// 空对象
function F() { }
F.prototype=obj;// 将某个 空对象 直接 赋值给空对象的构造函数的原型
return new F();
}
var person={
name:'Nicholas',
friends:["Shelby","Coury","Van"]
}
var anotherPerson=object(person)
// 与Object.create 相同 相比之下 Object.create更规范化
// var anotherPerson = Object.create(person)
anotherPerson.name="Greg";
anotherPerson.friends.push("Rob");
console.log(anotherPerson);//__proto__:friends: (4) ["Shelby", "Coury", "Van", "Rob"]
寄生式继承 :在原型式继承的基础上,增强对象,返回构造函数 (原生式 + 工厂模式)
缺点 :(同原型式继承)
function object(obj) {
function F() { }
F.prototype=obj;
return newF();
}
function createAnother(original) {
var clone=object(original);// 或 Object.create(original)
clone.sayHi=function() {// 以某种方式来增强对象
alert("hi");
};
return clone;// 返回这个对象
}
var person={
name:'Nicholas',
friends:["Shelby","Coury","Van"]
}
var anotherPerson=createAnother(person)
anotherPerson.name="Greg";
anotherPerson.friends.push("Rob");
console.log(anotherPerson);// __proto__:friends: (4) ["Shelby", "Coury", "Van", "Rob"]
寄生组合式继承 :
结合借用构造函数传递参数和寄生模式实现继承
通过借用构造函数继承属性,通过原型链的混成形式继承方法
使用寄生式继承来继承父类的原型,然后在将结果指定给子类型的原型
function inheritPrototype(Sun, Parent) {
var prototype=Object.create(Parent.prototype);// 创建对象,创建父类原型的一个副本
prototype.constructor=Sun;// 增强对象,弥补因重写原型而失去的默认的constructor 属性
Sun.prototype=prototype// 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型属性
function Parent(name) {
this.name=name;
this.colors=["red","blue","green"];
}
Parent.prototype.sayName=function() {
alert(this.name);
};
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function Sun(name, age) {
Parent.call(this, name);
this.age=age;
}
// 将父类原型指向子类
inheritPrototype(Sun, Parent);
Sun.prototype.sayAge=function() {
alert(this.age)
}
var instance1=new Sun("rose",22);
var instance2=new Sun("jack",23);
instance1.colors.push("black");// ["red", "blue", "green", "black"]
instance2.colors.push("gray");// ["red", "blue", "green", "gray"]
ES6类继承extends :
extends关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。
super调用父类属性、方法
class Parent{
constructor(name, age) {
this.age=age;
this.mame=name;
}
getAge() {
returnthis.age;
}
}
class Sun extends Parent{
constructor(name, age, sex) {
//调用超类型 必须在使用“this”之前首先调用 super()。
super(name, age)
this.sex=sex
}
}
var instance=new Sun('zxy',18,'女');
console.log(instance.getAge());
vuejs框架
—》从定义入手,官方怎么定义的、我对他的理解是什么??
用于构建用户界面的渐进式javascript框架:易用、灵活、高效
具体怎样—》易用、灵活、高效 ???
vue:可以通过尽可能简单的 API ,列表渲染(v-for)、条件渲染(v-if)、事件渲染、data,components , props , computed , watch , methods , mixin ,filter
vue两大特点:
响应式编程、vue.js会自动对页面中 某些数据的变化做出响应。
组件化。将各种模块拆分到一个一个单独的组件(component)中,
组件化开发的优点:提高开发效率、方便重复使用、提升整个项目的可维护性、便于协同开发。
vue是单页面应用:使页面局部刷新,不用每次跳转页面都要请求所有数据和dom,这样加快了访问速度和提升用户体验。
优点:数据驱动、组件化、轻量、简洁
缺点:
-
第一次加载首页耗时相对长一些;
-
不可以使用浏览器的导航按钮需要自行实现前进、后退。
-
不利于seo
而且他的第三方ui库很多节省开发时间。
生命周期
定义:事物从诞生到消亡的整个过程
生命周期分为三大阶段 :初始化阶段、更新阶段、销毁阶段
初始化阶段的钩子函数:
-
beforeCreate()实例创建前:数据和模版均未获取到
-
created() 实例创建后:最早可以访问到data数据,但是模版未获取到
-
beforeMount() 数据挂载前:模版已经获取到,但是数据未挂载到模版上
-
mounted() 数据挂载后:数据已经挂载到模版中
更新阶段的钩子函数:
-
beforeUpdata() 模版更新前:data改变后更新数据模版前调用
-
updated()模版更新后:将data渲染到数据模版中
销毁阶段的钩子函数:
-
beforeDestroy() 实例销毁前
-
destroyed() 实例销毁后
v-model 双向绑定原理 :
input,绑定input事件,当input发生改变时,获取event.target.value的值,赋值给数据,所以input改变时数据msg也发生改变了,v-bind动态绑定:value=msg;数据改变时,input可以发生改变。
<div id="app"> <input type="text"@input="fn":value="msg"> {{msg}} </div> <script src="node_modules/vue/dist/vue.js"></script> <script> const app=newVue({ el:'#app', data:{ msg:'' }, methods:{ fn(event){ this.msg=event.target.value } } }) </script>
底层原理:
observer监听$options,
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过**Object.defineProperty()**来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
mvvm模型 :
Model:模型, 数据对象(data选项当中的)
View:视图,模板页面(用于渲染数据)
ViewModel:视图模型,其实本质上就是new的 Vue 实例。里面有一个dom监听器,当监听到view试图发生改变时,data中的数据更新
将model层中的数据绑定到view层 。通过**Object.defineProperty()数据劫持,
组件:组件传值:
-
父传子:props
-
父组件动态绑定自定义属性为要传给子组件的数据,子组件props接收传过来的数据,props可以是数组,可以是对象,对象时,可以设置属性,传输类型、必填、默认值。
-
-
子传父:$emit
-
定义一个事件,来触发this.$emit(),将子组件的数据发送给父组件,this.$emit(),参数一自定义事件,参数二发送的数据。父组件绑定自定义事件,相应的回调函数可以使用传过来的数据
-
作用域插槽实现子传父:—》使用子组件中的数据,填充到父组件插槽标签中,子组件插槽中:data=“msg”,父组件插槽中,template模版<template slot-scope=“slot”><template>,可以用slot.data获取子组件数据了
-
(具名插槽 :子组件使用slot标签,属性name给插槽命名,父组件可以通过子组件的name具体更改摸一个插槽。)
-
-
兄弟之间:
-
vuex状态管理模式 : 将数据存到vuex的state里面,全局可以使用
-
插件PubSub :发送数据PubSub.public(事件名称,数据),接收数据PubSub.subscribe(事件名称,(event,data)=>{})
-
子传父父传子
-
-
父组件和子组件的v-model
-
父组件将数据传给子组件,子组件props接收数据
-
子组件中:v-model不能绑定props属性,
-
子组件自己的data 是个函数,返回对象,v-model应绑定子组件中的data,实现副组件数据发生改变,子组件也改变
-
子组件数据改变时,触发事件,利用子传父 $emit 将数据值传给父组件,实现父子组件的双向绑定
$refs 和 $el的用法 :
-
ref 加在普通的元素上,用this.$refs(ref值),获取到的是dom元素。
-
ref 加在子组件上,用 this.$refs 获取到的是组件实例,可以使用组件的所有方法。在使用方法的时候直接this.$refs.XX。
-
vm.$el:获取Vue实例关联的DOM元素
nextTick 是做什么的
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的DOM。
computed、watch、method :
Computed:属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;本质是getter、setter,默认只有get,getter方法,获取数据,也可以使用set方法改变数据;
(比如输入框,双向绑定计算属性,当输入框发生改变时,计算属性不会改变,只有设置了set函数 才发生改变,参数newValue)
Methods:方法表示一个具体的操作,主要书写业务逻辑;
Watch:主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作。当属性数据发生变化时,对应属性的回调函数会自动调用, 在函数内部进行计算。通过watch选项 或者 vm 实例的$watch()来监听指定的属性
Computed好处:在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:
-
使得数据处理结构清晰;
-
依赖于数据,数据更新,处理结果自动更新;
-
在template调用时,直接写计算属性名即可;
-
常用的是getter方法,获取数据,也可以使用set方法改变数据;
-
相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算
-
计算属性内部this指向vm实例
-
自定义指令directive:
directives : {
'指令名' : { // 指令名不要带 v-
bind (el, binding){// 指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。(css样式)
},
inserted (el, binding) {. //. inserted: 当被绑定的元素插入到 DOM 中时(js代码)
// 逻辑代码
// el 代表使用了此指令的那个 DOM 元素
// binding 可获取使用了此指令的绑定值 等 binding.value binding.name
}
}
}
filter过滤器 :
Filters是个对象,过滤器名称,对应回调函数,参数value,返回对value进行的操作。可以用在双花括号{{}}和v-bind表达式
// 局部 过滤器
filters : {
a (value){
if(!value) {
return
}
returnvalue.replace('sb','**')
}
}
事件修饰符:
-
.prevent阻止默认行为
-
.stop阻止事件冒泡
-
.enter监听特殊按键
-
.once事件只调用一次
-
.self: 当事件发生在该元素本身而不是子元素的时候会触发
-
.capture: 事件侦听,事件发生的时候会调用;
组件中的data为什么必须是一个函数?
如果组件内部是data对象,会造成数据污染,组件实例共用一个data数据,一个改变,会影响其他连琐反应,当组件内部data属性是一个函数时,不会造成数据污染,比如一个函数,他的每个实例对象,的对象不同,改掉其中一个,不会引起连锁反应。
vue-router:
hash路由 和history的 :
-
location.hash = “foo"
-
history.pushState(data, title,url) 可以实现不刷新页面改变url,可以利用history.back() 返回上一个路由.
-
data用于存储自定义数据,通常设为null
-
title网页标题,基本上没有被支持,一般设为空
-
url 以当前域为基础增加一条历史记录,不可跨域设置
-
-
histoty.replaceState(data, title, url) 只是替换当前url,不会增加/减少历史记录。
-
onpopstate事件,当前进或后退时则触发
Router-link:
属性:to跳转的路径、tag渲染成什么标签、active-class 更改class属性名
route 和router :
$router 为 VueRouter 实例,想要导航到不同 URL,则使用 $router.push 方法
$route 为当前活跃的路由,$route可以获取 name 、 path 、 query 、 params 等
嵌套路由:
配置路由映射:children:[],path、components,path可以是相对路径,也可以是绝对路径
路由传参:
params:配置路由映射,path: ‘/home/:id’,router-link标签动态绑定to属性,to :’/home/id’,在路由出口可以使用$route.params获取参数
query:配置路由映射,path: ‘/home’,router-link标签动态绑定to属性,to :’{path:’/home’,query:{name:a, age:10}}’,在路由出口可以使用$route.query获取参数
keep-alive:
用于保留组件状态或避免重新渲染。keep-alive标签将router-view标签包裹
路由守卫beforeEach
实现meta的title ——》点击切换不同路由时,title随着对应切换
// 在index.js文件中 配置路由映射中
constrouter=new VueRouter({
routes : [
{
path : '/home',
component : Home,
meta : { // 元数据:描述数据的数据
title: '首页'
}
}
]
})
// 全局导航守卫 !!!!!!1
// 前置钩子。在路由跳转之前实现的回调
router.beforeEach((to, from, next) => {
document.title=to.matched[0].meta.title; // !!!!!!!
console.log(to)
next()
})
vuex :
-
vuex是专门为vue.js提供的一种状态管理模式,它采用的是集中式储存和管理所有组件的状态和数据,方便使用。
-
vue组件—》dispatch调用actions--〉actions context.commit调用mutations--》mutations 改变state里的数据。
-
state 用来存放全局数据
-
mutations 用来修改state中的数据
-
actions 用来调用异步方法
-
modules 当项目很大时,将每个模块抽离出来
-
getters 派生属性: 类似vue的计算属性,主要用来过滤一些数据。
vue数据流?子组件为什么要把事件的一个状态的变更 提交一个事件上去 交由父组件去修改 子组件为什么不能直接改props ?
Vue 在数据操作上支持单向绑定和双向绑定:(单双向绑定:指的是 view层和 model 层之间的映射关系)
-
单向绑定:例如 Mustache 插值语法,v-bind 等;
-
双向绑定:即表单的 v-model。它实际上是一个语法糖,背后包括两步操作:
-
v-bind:value:model 层的更改同步到 view 层
-
v-on:input:view 层的更改同步到 model 层
单向数据流:数据流,指的是组件之间的数据流动;
虽然 v-model 是双向绑定,但 Vue 实际上是单向数据流。 假设想要用子组件的 prop 做一个双向绑定,那么我们的代码可能会这么写:
父组件的数据动态绑定自定义属性,传送到子组件,子组件通过props接收,v-model双向绑定props接受的数据。
我们会发现 model 层的确随着 view 层同步改变了,但是控制台里会报错:
因为 Vue 是单向数据流,数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。防止从子组件意外改变父级组件的状态,从而导致应用的数据流向难以理解
在开发中可能有多个子组件依赖于父组件的某个数据,万一子组件真的可以直接修改父组件数据,那么一个子组件变化将会引发所有依赖这个数据的子组件发生变化,所以 Vue 不推荐子组件修改父组件的数据,直接修改 prop 会抛出警告。
<div id="app"> <cpn v-bind:value2="value"></cpn> </div> <template id="cpn"> <input type="text"v-model="value2"> <h2>{{value2}}</h2> </template> const cpn={ template:"#cpn", props:["value2"] } const app=new Vue({ el:'#app', data:{ value:0 }, components:{ cpn } })
-
但是,很多时候我们又确实要操作这个数据,那么应该怎么办呢? 有两种方法:
定义一个局部变量,并用 prop 的值初始化它:相当于创建了原始 prop 的副本了,之后怎么操作数据都是操作的子组件数据,不会影响到父组件数据;
props: ['initialCounter'],
data:function() {
return{
counter:this.initialCounter
}
}
定义一个计算属性,处理 prop 的值并返回:注意 trim() 会返回一个处理完成后的新字符串,同样不会影响到父组件数据(原字符串)。
props: ['size'],
computed: {
normalizedSize:function() {
return this.size.trim().toLowerCase()
}
}
之后如果父组件确实要用到这个处理后的值,就通过 $emit 的方式传给父组件即可。
拿前面的例子来说,我们想要利用 prop 这个数据实现双向绑定,可以这么写:
<div id="app">
<cpn v-bind:value2="value"></cpn>
</div>
<template id="cpn">
<input type="text"v-model="value3">
<h2>{{value3}}</h2>
</template>
const cpn={
template:"#cpn",
props:["value2"],
data:{
value3:this.value2
}
}
const app=new Vue({
el:'#app',
data:{
value:0
},
components:{
cpn
}
})
注意:在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。 比如下面这段代码:
<div id="app">
<h2>父组件数据:{{parent}}</h2>
<cpn v-bind:obj1="parent"></cpn>
</div>
<template id="cpn">
<div>
<h2>子组件数据:{{son}}</h2>
<input type="text"v-model="son.age">
</div>
</template>
<script>
const cpn={
template:"#cpn",
props:["obj1"],
data() {
return{
son:this.obj1
}
}
}
const app=newVue({
el:'#app',
data:{
parent:{age:20}
},
components:{
cpn
}
}
</script>
这里的 this.obj1 是引用,赋值给了 son,所以 son 实际上还是指向了父组件的数据,对 son.age 的修改依然会影响到父组件,如图:
所以,我们实际上需要的是一个对象副本。因为对象属性都是基本类型,这里只用浅拷贝即可(如果对象属性还是对象,就得用深拷贝):
const cpn={
template:"#cpn",
props:["obj1"],
data() {
return{
// son:this.obj1
son:Object.assign({},this.obj1)
}
}
}
Vue中v-if和v-show的区别?
-
渲染 :
-
v-show : 浏览器首先什么都不管,先把HTML元素先渲染起来,符合条件就显示,不符合条件display就为none,不显示,但是元素还在.
-
v-if : 浏览器先判断符不符合条件,符合了再渲染,否则不渲染DOM,浏览器中找不到这个DOM。
-
-
vue生命周期区别 :
-
v-if由于是重新渲染,所以每次切换一次会重新走一次生命周期
-
v-show由于只是控制显示隐藏,所以除了初始化渲染,其他时候都不会再走相关生命周期了。
-
-
性能区别 :
-
v-if有更高的切换开销,v-show有更高的初始渲染开销。如果需要频繁的切换,使用v-show比较好,如果运行条件很少改变,使用v-if比较好。
-
v-show比v-if性能更高,因为v-show只能动态的改变样式,不需要增删DOM元素。所以当程序不是很大时候,v-if和v-show区别都不大,如果项目很大,推荐多用v-show,较少浏览器后期操作的性能。
-
后续更新react.......