基础知识点
本文最后更新于 2024-03-24,文章内容可能已经过时。
h5+c3
什么是HTML?
HTML并不是真正的的程序语言他是一种 标 记 语 言 用来结构化和含义化你想要放
在web 网站上的那些内容。它由一系列的元素(elements)所组成,这些元素可以用来
封装你的内容中担任不同工作的各部分和各个角色。
行内元素和块级元素的具体区别是什么?行内元素的padding和margin可设置吗?
块级元素(block)特性:
总是独占一行,表现为另起一行开始,而且其后的元素也必须另起一行显示;
宽度(width)、高度(height)、内边距(padding)和外边距(margin)都可控制;
行内元素特性
和相邻的内联元素在同一行;
宽度(width)、高度(height)、内边距的top/bottom(padding-top/padding-bottom)和外边距的top/bottom(margin-top/margin-bottom)都不可改变(也就是padding和margin的left和right是可以设置的),就是里面文字或图片的大小。
介绍一下你对浏览器内核的理解?都有哪些常见的浏览器内核?
“渲染引擎”,不过我们
一般习惯将之称为“浏览器内核”负责对网页语法的解释(如标准通用标记语言下的一个
应用 HTML、JavaScript)并渲染(显示)网页。 所以,通常所谓的浏览器内核也就是浏
览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。
常见浏览器内核:
Trident 内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称 MSHTML]
Gecko内核:Netscape6 及以上版本,FF,MozillaSuite/SeaMonkey 等。
Presto 内核:Opera7及以上。 [Opera内核原为:Presto,现为、Blink;]
Webkit 内核:Safari,Chrome 等。 [ Chrome 的:Blink(WebKit 的分支)]
EdgeHTML内核:Microsoft Edge。 [此内核其实是从 MSHTML fork 而来,删掉了几
乎所有的 IE私有特性
h5有哪些些新特性
header 网页或section的头部
asider 网页的侧边栏内容
nav 定义页面的主要导航部分
article 独立完整的内容模块,通常用在博客、论坛、新闻、评论等,区别于section这种分段的标签
section 网页文档中的段、节,通常子元素包括标题:h1-h6
footer 网页或section底部的内容,可能包括:作者或者版权信息等;
details 用于描述文档或文档某个部分的细节,summary是details元素的标题
canvas canvas绘图,该标签为图形容器
video 定义电影片段或者其他视频流,支持三种类型的视频
audio 浏览器默认将第一个能识别的格式进行播放 使用source实际是解决个大厂的兼容性问题
datalist 与input配合使用可制作输入值的下拉列表,与select不同的是datalist即可下拉选择,也可以输入值,还有模糊匹配的功能。
progress 进度条,运行中、加载中的进度。
time 定义日期或者时间
兼容性
收集地址
Meta基础知识:
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
// width 设置viewport宽度,为一个正整数,或字符串‘device-width’
// height 设置viewport高度,一般设置了宽度,会自动解析出高度,可以不用设置
// initial-scale 默认缩放比例,为一个数字,可以带小数
// minimum-scale 允许用户最小缩放比例,为一个数字,可以带小数
// maximum-scale 允许用户最大缩放比例,为一个数字,可以带小数
// user-scalable 是否允许手动缩放
<!-- 设置缩放 -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />
<!-- 可隐藏地址栏,仅针对IOS的Safari(注:IOS7.0版本以后,safari上已看不到效果) -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- 仅针对IOS的Safari顶端状态条的样式(可选default/black/black-translucent ) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<!-- IOS中禁用将数字识别为电话号码/忽略Android平台中对邮箱地址的识别 -->
<meta name="format-detection"content="telephone=no, email=no" />
H5页面窗口自动调整到设备宽度,并禁止用户缩放页面
<!-- 启用360浏览器的极速模式(webkit) -->
<meta name="renderer" content="webkit">
<!-- 避免IE使用兼容模式 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->
<meta name="HandheldFriendly" content="true">
<!-- 微软的老式浏览器 -->
<meta name="MobileOptimized" content="320">
<!-- uc强制竖屏 -->
<meta name="screen-orientation" content="portrait">
<!-- QQ强制竖屏 -->
<meta name="x5-orientation" content="portrait">
<!-- UC强制全屏 -->
<meta name="full-screen" content="yes">
<!-- QQ强制全屏 -->
<meta name="x5-fullscreen" content="true">
<!-- UC应用模式 -->
<meta name="browsermode" content="application">
<!-- QQ应用模式 -->
<meta name="x5-page-mode" content="app">
<!-- windows phone 点击无高光 -->
<meta name="msapplication-tap-highlight" content="no">
var phoneWidth = parseInt(window.screen.width);
var phoneScale = phoneWidth/640;
var ua = navigator.userAgent;
if (/Android (\d+\.\d+)/.test(ua)){
var version = parseFloat(RegExp.$1);
if(version>2.3){
document.write('<meta name="viewport" content="width=640, minimum-scale = '+phoneScale+', maximum-scale = '+phoneScale+', target-densitydpi=device-dpi">');
}else{
document.write('<meta name="viewport" content="width=640, target-densitydpi=device-dpi">');
}
} else {
document.write('<meta name="viewport" content="width=640, user-scalable=no, target-densitydpi=device-dpi">');
}
H5页面rem兼容适配
$(document).ready(function(){
//rem兼容
var winW = $(window).width();
var constant = winW/6.4;(10.8/7.5)
$("html,body").css("font-size",constant);
$(window).resize(function(){
var winW = $(window).width();
var constant = winW/10.8;
$("html,body").css("font-size",constant);
})
})
//使用时有可能造成div等容器过大。
//div中放入img时,让div的宽高自适应,此时会造成容器的宽高可能会大于img的宽高.
//解决:容器添加 font-size:0 ,然后div中的内容使用rem
div {
font-size:0;
}
div img {
width:1rem;
}
div p {
font-size:0.5rem;
}
css
//去掉webkit的滚动条——display: none;
//其他参数
::-webkit-scrollba //滚动条整体部分
::-webkit-scrollbar-thumb //滚动条内的小方块
::-webkit-scrollbar-track //滚动条轨道
::-webkit-scrollbar-button //滚动条轨道两端按钮
::-webkit-scrollbar-track-piece //滚动条中间部分,内置轨道
::-webkit-scrollbar-corner //边角,两个滚动条交汇处
::-webkit-resizer //两个滚动条的交汇处上用于通过拖动调整元素大小的小控件
// 禁止长按链接与图片弹出菜单
a,img { -webkit-touch-callout: none }
// 禁止ios和android用户选中文字
html,body {-webkit-user-select:none; user-select: none; }
// 改变输入框placeholder的颜色值
::-webkit-input-placeholder { /* WebKit browsers */
color: #999; }
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
color: #999; }
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #999; }
:-ms-input-placeholder { /* Internet Explorer 10+ */
color: #999; }
input:focus::-webkit-input-placeholder{ color:#999; }
// android上去掉语音输入按钮
input::-webkit-input-speech-button {display: none}
// 阻止windows Phone的默认触摸事件
/*说明:winphone下默认触摸事件事件使用e.preventDefault是无效的,可通过样式来禁用,如:*/
html { -ms-touch-action:none; } //禁止winphone默认触摸事件
audio元素和video元素在ios和andriod中无法自动播放
//音频,写法一
<audio src="music/bg.mp3" autoplay loop controls>你的浏览器还不支持哦</audio>
//音频,写法二
<audio controls="controls">
<source src="music/bg.ogg" type="audio/ogg"></source>
<source src="music/bg.mp3" type="audio/mpeg"></source>
优先播放音乐bg.ogg,不支持在播放bg.mp3
</audio>
//JS绑定自动播放(操作window时,播放音乐)
$(window).one('touchstart', function(){
music.play();
})
//微信下兼容处理
document.addEventListener("WeixinJSBridgeReady", function () {
music.play();
}, false);
//小结
//1.audio元素的autoplay属性在IOS及Android上无法使用,在PC端正常
//2.audio元素没有设置controls时,在IOS及Android会占据空间大小,而在PC端Chrome是不会占据任何空间
css3新特性
原文出处
CSS3的选择器
E:last-child 匹配父元素的最后一个子元素E。
E:nth-child(n)匹配父元素的第n个子元素E。
E:nth-last-child(n) CSS3 匹配父元素的倒数第n个子元素E。
@Font-face 特性
@font-face { /*可以用来加载字体样式*/
圆角
border-radius: 15px;
阴影
text-shadow:5px 2px 6px rgba(64, 64, 64, 0.5);
渐变
background-image:-webkit-gradient(linear,0% 0%,100% 0%,from(#2A8BBE),to(#FE280E));
过渡
transition: all .5s;
2d转换和3d转换
transform:适用于2D或3D转换的元素
transform-origin:转换元素的位置(围绕那个点进行转换)。默认(x,y,z):(50%,50%,0)
边框图片
border-image:
背景
background-clip 制定背景绘制
background-size 是相对位置
background-origin 就是制定背景的大小
反射
-webkit-box-reflect:方向[ above-上 | below-下 | right-右 | left-左 ],偏移量,遮罩图片
文字超出省略号
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
文字阴影
text-shadow:
颜色--rgba
background: rgba(00,00,00,.5);
渐变
-webkit-radial-gradient([<position> || <angle>,]?[<shape> || <size>,]?<color-stop>,<color-stop>[,<color-stop>]*);
滤镜
<p>原图</p>
<img src="test.jpg" />
<p>黑白色filter: grayscale(100%)</p>
<img src="test.jpg" style="filter: grayscale(100%);"/>
<p>褐色filter:sepia(1)</p>
<img src="test.jpg" style="filter:sepia(1);"/>
<p>饱和度saturate(2)</p>
<img src="test.jpg" style="filter:saturate(2);"/>
<p>色相旋转hue-rotate(90deg)</p>
<img src="test.jpg" style="filter:hue-rotate(90deg);"/>
<p>反色filter:invert(1)</p>
<img src="test.jpg" style="filter:invert(1);"/>
<p>透明度opacity(.5)</p>
<img src="test.jpg" style="filter:opacity(.5);"/>
<p>亮度brightness(.5)</p>
<img src="test.jpg" style="filter:brightness(.5);"/>
<p>对比度contrast(2)</p>
<img src="test.jpg" style="filter:contrast(2);"/>
<p>模糊blur(3px)</p>
<img src="test.jpg" style="filter:blur(3px);"/>
<p>阴影drop-shadow(5px 5px 5px #000)</p>
<img src="test.jpg" style="filter:drop-shadow(5px 5px 5px #000);"/>
css渐进增强优雅增强
清除浮动
/*父级div定义height (高度等差法)*/
给div定义高度,重点是放在网站的国定点上(父元素)动态数据欠佳
/*父级div定义伪类:after和zoom*/
.clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0}
.clearfloat{zoom:1}
/*双伪类*/
.clearfix:before,clearfix:after{
content:"";display:block; clear:both;
}
.clearfix{
zoom:1
}
/* 空div定义伪类:after和zoom */
.clearfloat{clear:both}
/*父级div定义overflow:hidden*/
.div1{overflow:hidden}
/*父级div定义overflow:auto*/
.div1{overflow:auto}
水平垂直居中
/*1父容器上定义固定宽度,margin值设成auto*/
nav {margin: 0 auto; text-align: center}
/*2display:flex */
.parent {isplay:flex;flex-direction:column;}
.Children{flex-direction:center}
水平垂直居中
/*flex方式(适用于居中元素元素宽高未知)--- 必须设置html和body的高度为100%*/
body {
display: flex;
align-items: center; /*垂直居中*/
justify-content: center; /*水平居中*/
}
/*绝对定位和负边距(适用于居中元素的宽高是固定的)--*/
img {
position: absolute;
top: 50%;
left: 50%;
margin-left: -80px; /*图片宽度的一半*/
margin-top: -80px; /*图片高度的一半*/
}
/*CSS3的transform属性(适用于居中元素元素宽高未知)-- 即使img元素再加一些padding和border,依然可以垂直水平居中 */
img{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
padding:100;
}
/*等边法 margin:auto */
img{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
不指定宽高的元素
/*常用在div模拟模态框*/
.demo{
position:absolute;
left:50%; top:50%;
transform:translate(-50%,-50%);
}
.demo{
position:absolute;
left:50%; bottom:0;
transform:translate(-50%,-50%);
}
.demo{
position:fixed;left:50%;
top:50%;
transform:translate(-50%.-50%);
}
指定宽高的元素
/*常用在div模拟模态框*/
/*绝对定位*/
.demo{
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
margin:auto;
}
/*负边距*/
.demo{
width:1200px;
height: 600px;
position: absolute;
left: 50%;
top: 50%;
margin:-300px 0 0 -600px;
}
/*表格法*/
.demo{
display: table-cell;
vertical-align: middle;
text-align: center;
}
/*弹性盒子*/
.demo{
display: flex;
justify-content:center;
align-items:Center;
}
实现三栏布局,两边宽度固定,中间自适应
圣杯布局 双飞翼布局
双飞翼布局
布局
静态布局
流式布局
自适应布局 媒体查询
响应式开发(栅格化布局)
弹性布局rem布局
HTML`CSS_网站页面不同浏览器兼容性问题解决
不同浏览器的标签默认的外边距和内边距不同
*{margin:0;padding:0;}
双边距塌陷问题
1 使用display
2 1px
IE浮动边缘产生的双倍距离
#box {
float:left;
width:100px;
margin:0 0 0 100px; //这种情况之下IE会产生200px的距离
display:inline; //使浮动忽略
}
background显示问题---背景透明问题
全部注意补齐width,height属性
IE:filter:progid:DXImageTransform.Microsoft.Alpha(style = 0,opacity = 60);
IE:filter:alpha(opacity = 10);
FF:不透明度:0.6;
FF:-moz-opacity:0.10;
最好两个都写,并将透明度属性放在下面
javascript
对象
JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。
在 JavaScript 中,对象是拥有属性和方法的数据。
类型
数据封装对象 : Object Array Boolean Number String
其他类型 : Function Argument Math Date Error RegExp
对象的定义
布尔是对象(如果用 new 关键词定义)
数字是对象(如果用 new 关键词定义)
字符串是对象(如果用 new 关键词定义)
日期永远都是对象
算术永远都是对象
正则表达式永远都是对象
数组永远都是对象
函数永远都是对象
对象永远都是对象
JavaScript 原始值
string
number
boolean
null
undefined
对象是包含变量的变量
var person = "Bill Gates";
创建 JavaScript 对象
JavaScript 中的几乎所有事务都是对象:字符串、数字、数组、日期、函数,等等。
定义和创建单个对象,使用对象文字。
定义和创建单个对象,通过关键词 new。
定义对象构造器,然后创建构造类型的对象。
person=new Object();
person.firstname="Bill";
person.lastname="Gates";
person.age=56;
person.eyecolor="blue";
对象字面量
对象文字指的是花括号 {} 中的名称:
var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};
对象属性
属性通常可以被修改、添加和删除,但是某些属性是只读的 ( 属性指的是与 JavaScript 对象相关的值。 )
访问 JavaScript 属性
objectName.property // person.age
objectName["property"] // person["age"]
objectName[expression] // x = "age"; person[x]
添加对象 person.nationality = "English";
删除对象 delete person.age;
访问对象
objectName.propertyName
this指向问题
this 关键词
被称为 this 的事物,指的是拥有该 JavaScript 代码的对象。this 的值,在函数中使用时,是“拥有”该函数的对象。请注意 this 并非变量。它是关键词。您无法改变 this 的值。
this理解
作为一个纯粹的函数的话 this的指向是全局对象
作为一个方法调用的话 this的指向是调用对象
作为一个构造函数调用的话 this的指向是一个新对象 (new 会改变一个this的方向 )
apply 调用this指向apply方向的第一个参数
在es6中箭头函数内部的this指向外部作用域中的this (箭头函数没有自己的this )
事件处理程序中的this 指向事件源 【 定时器中的this 指向window 】
JavaScript 对象原型
所有 JavaScript 对象都从原型继承属性和方法。
案例
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
// 添加 nationality 属性
Person.nationality = "English";
var myFather = new Person("Bill", "Gates", 62, "blue");
var myFather = new Person("Bill", "Gates", 62, "blue");
document.getElementById("demo").innerHTML ="My friend is " + myFriend.age + myFather.nationality;
// 会发现nationality 属性会添加不了 ,返回值为undefined
// 如果添加的话,我们需要更新数据
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
// 将nationality 属性添加到 构函数中
this.nationality = "English";
}
原型继承
prototype
所有 JavaScript 对象都从原型继承属性和方法。日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。Person 对象继承自 Person.prototype。Object.prototype 位于原型继承链的顶端:日期对象、数组对象和 Person 对象都继承自 Object.prototype。
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}
// 我们会添加到到原型链中
Person.prototype.nationality = "English";
函数
JavaScript 函数是被设计为执行特定任务的代码块。
JavaScript 函数会在某代码调用它时被执行。
函数定义
JavaScript 函数是通过 function 关键词定义的。您可以使用函数声明或函数表达式。
// 函数声明
function myFunction(p1, p2) {
return p1 * p2; // 该函数返回 p1 和 p2 的乘积
}
// 函数表达式
var x = function (a, b) {
return a * b
};
var z = x(4, 3);
console.log( z )
// Function() 构造器
var myFunction = function (a, b) {
return a * b
};
var x = myFunction(4, 3);
console.log(x)
函数调用
当事件发生时(当用户点击按钮时)
当 JavaScript 代码调用时
自动的(自调用)
(function () {
var x = "Hello!!"; //我会调用我自己
})();
// 匿名的自调用函数(没有名称的函数)。
函数是对象
JavaScript 中的 typeof 运算符会为函数返回 "function"。但是最好是把 JavaScript 函数描述为对象。JavaScript 函数都有属性和方法。
<span style="color:red">arguments.length 会返回函数被调用时收到的参数数目:</span>
function myFunction(a, b) {
return arguments.length;
}
console.log(myFunction(4, 3)) //2
<span style="color:red">toString() 方法以字符串返回函数::</span>
function myFunction(a, b) {
return a * b;
}
var txt = myFunction.toString();
箭头函数
// ES5
var x = function(x, y) {
return x * y;
}
// ES6
const x = (x, y) => x * y;
// 保留 return
const x = (x, y) => { return x * y };
箭头函数没有自己的 this。它们不适合定义对象方法。箭头函数未被提升。它们必须在使用前进行定义。使用 const 比使用 var 更安全,因为函数表达式始终是常量值。如果函数是单个语句,则只能省略 return 关键字和大括号。因此,保留它们可能是一个好习惯:
函数返回值
当 JavaScript 到达 return 语句,函数将停止执行。
如果函数被某条语句调用,JavaScript 将在调用语句之后“返回”执行代码。
函数参数
函数不会对参数值进行任何检查
functionName(parameter1, parameter2, parameter3) {
要执行的代码
}
// 函数参数(parameter)指的是在函数定义中列出的名称。
// 函数参数(argument)指的是传递到函数或由函数接收到的真实值。
参数默认
如果调用参数时省略了参数(少于被声明的数量),则丢失的值被设置为:undefined。
function MyFunction (x, y ) {
if ( y === undefined) {
y =0
}
return x*y
}
console.log(MyFunction (3)) //返回 0
如果函数调用的参数太多(超过声明),则可以使用 arguments 对象来达到这些参数。
arguments 对象
内置对象
JavaScript 函数有一个名为 arguments 对象的内置对象。arguments 对象包含函数调用时使用的参数数组。
arguments 对象
arguments[] 函数的数组
arguments.length 传递函数的参数
Array 数组
length 属性 动态获取数组长度
join () 将一个数组转化为字符串。返回一个字符串
reveres 将数组中的数字颠倒顺序
shift () 删除数组中的第一个值
pop() 删除数组中的最后一个值
splice 插入、删除或者替换元素
toString 将数组转化为字符串
Boolean 对象
Boolean.toString () 将布尔型转化为字符串
Boolean.valueOf() Boolean对象的布尔值
Date 对象
Error 对象
Math 对象
Object 基础对想
RegExp 正则表达式对象
String 字符串对象
函数调用
在函数被定义时,函数内部的代码不会执行。在函数被调用时,函数内部的代码会被执行。调用函数通常也可以说“启动函数”或“执行函数”。在本教程中,我们使用“调用”
//以函数的方式调用函数
function myFunction (a,b){
return a*b;
}
myFunction(10 , 2) // 返回值为 20
javascript 函数 call
使用 call() 方法,您可以编写能够在不同对象上使用的方法。 call() 方法是预定义的 JavaScript 方法。它可以用来调用所有者对象作为参数的方法。通过 call(),您能够使用属于另一个对象的方法。本例调用 person 的 fullName 方法,并用于 person1
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1);
document.getElementById("demo").innerHTML = x;
01函数的基础使用
// 基础函数
function sayHello() {
console.log('Hello!');
}
sayHello()
// 函数传参
function outer (hello){
console.log(hello)
}
outer('hello');
//函数返回值
function sun (numer1,numer2){
return numer1+ numer2
}
sun(10,15)
02面向对象编程
JavaScript里的对象就是普通名值对的集合
方式1:
var obj = new Object();
方式2:
var obj = {};
可以补充创建一个完整的对象
var obj = {
name:{
surname:'Zhang',
names : 'XiaoLun',
},
age: 15;
}
对象是类的实例。一个类定义对象的特征,我们可以创造多个类来表示数据结构
// 定义一个对象,并未对象添加对应的类
function Book (title,conter,about){
this.title = title,
this.conter = conter,
this.about = about,
}
// 实例化这个对象
var Book = new Book('title','png','isnotop')
// 对对象进行操作 、
console.log(Book.title); // title
Book.title = 'newTitle';
console.log(BooK.title); // newTitle
3数组
创建一个数组
数组长度 lenght
var arry = [];
var arry = ['数据1','数据2','数据3','数据4','数据5']
console.log(arry.lenght)
数组的添加
var arr = [1,2,3,4]
// 在末尾添加一个新的元素,
arr[arr.lenght] = 5
// 或者 push
arr.push(6,7)
// 在首位添加一个新元素
arr.unshift(-1)
数组的删除
arr.pop();
//删除数组中的第一值
arr.shift();
// 根据下标进行删除
arr.splice(5,3)
//索引为5后的三个元素删除
arr.splice(5,0 ,2,3,4)
从索引5插入元素,2,3,4。0代表插入,splice(数组的角标,删除长度,.... 添加的元素 )
4二维数组
很可惜的的是,JS并不支持矩形,但我们可以用嵌套的循环来表示
function TowDArry(arry){
for(var i = 0; i < arry.lenght ;i++)
for (var j = 0;j < arry[i].lenght; j++)
console.log(arry[i][j])
}
5其他的数组方法
concat
every
slice
map
indexof
lastndexof
join
toString
6数组合并
var arryData1 = [1,2,3,4]
var arryData2 = [5,6,7,8]
var data = arryData1.concat(arryData2)
7数组的迭代
var number = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
var isEver = function (x){
// 如果值为2的倍数就返回true
console.log(x)
//否则就返回false
return (x % 2 == 0)
}
//every方法会迭代数组中的每个元素,直到返回false
// number.every(isEver)
// some 方法会将数组中的每一个元素都进行一次迭代。直到函数返回true:
// number.some(isEver);
如果是要进行将所有项进行输出,我们需要循环,或者forEach
numbers.forEach(function(x){
console.log((x % 2 == 0));
});
//方法一
var myMap = numbers.map(isEven);
// 方法二
var evenNumbers = numbers.filter(isEven);
map方法会将数组中的没有一个元素都给定一个新的元素数组,
filter 对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
8排序
var arry = [1,2,3,4,5,6,7,8,9]
// 反序输出数组
arry.reverse()
sort() 方法用于对数组的元素进行排序
var arry= [1,2,3,4,5,6,7,11,15]
console.log(arry.sort()) //[1, 11, 15, 2, 3, 4, 5, 6, 7]
sort() 是按照字符编码的顺序进行排序。首先应把数组的元素都转换成字符串,以便进行比较。
// 我们将创建一个数组,并按字母顺序进行排序:
var arryName = [
'ZhangSan',
'LiSi',
'WangErXiao',
'LiErGou',
GouDan'
];
console.log(arryName.sort())
// ["GouDan", "LiErGou", "LiSi", "WangErXiao", "ZhangSan"]
若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
var arry= [1,22,3,4,51,96,7,11,15]
function compare(a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
// a必须等于
return 0;
}
arry.sort(compare); //[1, 3, 4, 7, 11, 15, 22, 51, 96]
// 应用,例如我们一个数组里面有张三,李四,王二狗三人的个人信息,现在要按照年龄排序
var arry = [
{ name: "ZhangSan", age: 18 },
{ name: "LiSi", age: 35 },
{ name: "WangErXiao", age: 30 },
];
function compare(a, b) {
if (a.age < b.age) {
return -1;
}
if (a.age > b.age) {
return 1;
}
// a必须等于
return 0;
}
console.log(arry.sort(compare));
// 0: {name: "ZhangSan", age: 18} 1: {name: "WangErXiao", age: 30} 2: {name: "LiSi", age: 35}
9搜索 indexOf
var arry = [1,2,3,4,5,6,7,8,9,10];
var index = arry.indexOf(10);
console.log(index,'返回下角标')
跨域问题
跨域是什么?
为什么要跨域?
怎样跨域?
跨域的概念 即在一个域下的文档或者脚本,去请求另一个域下的资源(广义跨域):例如当我们在做项目的时候,我们的项目前后端是分离的,前端放在静态域下,而我们的后端会放在指定服务端域下,那么我们要两则间,数据请求的来往,就无法避免的会遇到跨域问题。
1只要我们说到跨域就会谈到同源策略:
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略,它是由Netscape提出的一个著名的安全策略。
现在所有支持JavaScript 的浏览器都会使用这个策略。
所谓同源是指,域名,协议,端口相同。
当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面
当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,
即检查是否同源,只有和百度同源的脚本才会被执行。 [1]
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
2如果说我们缺少了同源策略会发生什么?
跨站脚本攻击XSS
跨站脚本攻击(也称为XSS)指利用网站漏洞从用户那里恶意盗取信息。
跨站请求伪造CSRF(Cross-site request forgery)
是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
3那同源策略又有哪些限制那?
Cookie、LocalStorage 和 IndexDB 无法读取
DOM 和 Js对象无法获得
AJAX 请求不能发送
4跨域场景?
URL 说明 是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不同文件或路径 允许
http://www.domain.com/lab/c.js
http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不同端口 不允许
http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不同协议 不允许
http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名对应相同ip 不允许
http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不同 不允许
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js 不同域名 不允许
5解决跨域?
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域 (saokeita)
jsonp: 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。
6通过jsonp跨域
(1) 原生的方法
//创建一个script
var script = document.createElement('script');
//指定style为javascript
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.baidu.com:8080/login?user=admin&callback=handleCallback';
//追加
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
服务端返回如下(返回时即执行全局函数):
leCallbackhand({"status": true, "user": "admin"})
(2) jquery ajax:
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
(3) vue.js:
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
(4)后端node.js代码示例:
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var params = qs.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回设置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
7跨域资源共享
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。如果想实现当前页cookie的写入,可参考下文:七、nginx反向代理中设置proxy_cookie_domain 和 八、NodeJs中间件代理中cookieDomainRewrite参数的设置。
目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
1、 前端设置:
1.)原生ajax
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
2.)jQuery ajax
$.ajax({
...
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
...
});
3.)Nodejs后台示例:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
/*
* 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
*/
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly的作用是让js无法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
8跨域资源共享(CORS)WebSocket协议跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
1.)前端代码:
<div>user input:<input type="text"></div>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');
// 连接成功处理
socket.on('connect', function() {
// 监听服务端消息
socket.on('message', function(msg) {
console.log('data from server: ---> ' + msg);
});
// 监听服务端关闭
socket.on('disconnect', function() {
console.log('Server socket has closed.');
});
});
document.getElementsByTagName('input')[0].onblur = function() {
socket.send(this.value);
};
</script>
2.)Nodejs socket后台:
var http = require('http');
var socket = require('socket.io');
// 启http服务
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
// 监听socket连接
socket.listen(server).on('connection', function(client) {
// 接收信息
client.on('message', function(msg) {
client.send('hello:' + msg);
console.log('data from client: ---> ' + msg);
});
// 断开处理
client.on('disconnect', function() {
console.log('Client socket has closed.');
});
});
闭包
1JavaScript 变量:JavaScript 变量是存储数据值的容器
声明(创建) JavaScript 变量:通过 -var- 关键词来声明 JavaScript 变量:
2JS作用域大致分为三:全局作用域和局部作用域,以及ES6的块级作用域
全局作用域:最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的:
<script>
var outerVar = "outer";
function fn(){
console.log(outerVar);
}
fn();//result:outer
</script>
局部作用域:和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部
<script>
function fn(){
var innerVar = "inner";
}
fn();
console.log(innerVar);//报错,是没有定义
</script>
值得一提的是如果你在函数内部没有用var定义函数,那你其实声明了一个全局的变量
<script>
function fn(){
innerVar = "inner";
}
fn();
console.log(innerVar);// result:inner
</script>
同样原理我们看如下代码:
<script>
var scope = "global";
function fn(){
console.log(scope);//result:undefined
var scope = "local";
console.log(scope);//result:local;
}
fn();
</script>
不要怀疑,对就如你眼中看到一样,js和别的语言有区别,函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提前声明”:
作用域链
我对作用域链的理解是:
在内部函数可以访问外部函数变量的这种机制,用所梯度链式查找的方式,决定哪些数据能被内部函数访问的过程。 那我就想问,为啥内部可以访问外部?
js执行环境
所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据 ,决定了它们各自的行为。js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中.
①比如:
<script>
var name = "小美";
function got1(){
return name;
}
function got2(){
return name;
}
got1();
got2();
</script>
②图鉴过程
全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。 js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。
当某个函数第一次被调用时,就会创建一个执行环境(execution context)以及相应的作用域链,并把作用域链赋值给一个特殊的内部属性([scope])。然后使用this,arguments(arguments在全局环境中不存在)和其他命名参数的值来初始化函数的活动对象(activation object)。当前执行环境的变量对象始终在作用域链的第0位。
因此我们可以看过程图:当got1()第一调用的时候,会创建一个由got1函数对象创建的执行环境,可以看到got1里并没有scope变量,于是沿着作用域链(scope chain)向后寻找,结果在全局变量对象里找到了scope,所以就返回全局变量对象里的scope值。执行过后,栈会将got1()对象“销毁”,然后执行同样步骤的got2()
那这些又和闭包有什么关系那?
<script>
function out(){
var scope = "outer";
function into(){
return scope;
}
return innto;
}
var fn = out();
fn();
</script>
以上其实就是一个闭包,而闭包的原理也就是图鉴的原理!我们分析代码:
outer()内部返回了一个into函数,①当调用out时,into函数的作用域链就已经被初始化了,(也就是说已经执行了图示的过程,在本作用域内没有,然后到父级类找)②一般来说,当某个环境中的所有代码执行完毕后,该环境被销毁(弹出环境栈),保存在其中的所有变量和函数也随之销毁(全局执行环境变量直到应用程序退出,如网页关闭才会被销毁) 但是像上面那种有内部函数的又有所不同,③当out()函数执行结束,执行环境被销毁,但是其关联的活动对象并没有随之销毁,而是一直存在于内存中,因为该活动对象被其内部函数的作用域链所引用
1什么是闭包:闭包(Closure)是JavaScript语言中一个非常重要的特性
MDN:闭包是函数和声明该函数的词法环境的组合。
在Javascript语言中,只有函数中的子函数才能引用函数中的变量,简单来说,闭包就是定义在函数中的函数,是函数内外部连接的桥梁
闭包的意义是:当前作用域总是能够访问外部作用域中的变量;函数是唯一拥有自身作用域的结构,所以闭包的创建依赖于函数
百度百科:闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
2闭包的作用:
读取自身函数外部的变量(沿着作用域链寻找)
让这些外部变量始终保存在内存中
延长局部变量的生命周期
维护私有变量-局部变量的安全
3如何检测一个程序中是否有闭包?
1. 外层函数 和 子函数
2. 外层函数必须有局部变量
3. 子函数要操作外层函数的局部变量
4. 让子函数和外部产生关联。 // 关联不一定是返回函数
写个闭包:就用this,今天碰到的
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//result:The Window
原型链
原型: Person.prototype
构造函数:被 new 使用的函数
构造函数使用 new 运算符生成实例
构造函数通过 prototype 属性初始化一个对象,即原型对象
原型对象如何区分被哪个构造函数所引用,通过原型对象的构造器 constructor 来指向生成的函数
原型链:从一个实例往上找构造这个实例相关联的对象,这个关联的对象再往上找,它又有创造它的上一级的原型对象,以此类推,直到objrct.prototype 原型终止。主要通过 prototype 和 proto 实例
当调取一个对象的属性时,会先在本身查找,若无,就根据 proto 找到构造原型,若无,继续往上找。最后会到达顶层Object prototype,它的 proto 指向null,均无结果则返回undefined,结束。由 proto 串起的路径就是『原型链』。
继承方式
1借助构造函数实现继承
function parent1() {
this.name = 'parent1';
}
function child1() {
parent1.call(this);
this.type = 'child1';
}
console.log(new child1);
通过call()函数修改 this 指向,从而实现将父类属性挂载到子类实例中。
借助原型链实现继承(最通用的方式)
function parent2() {
this.name = 'parent2';
this.play = [1, 2, 3];
}
parent2.prototype.say = function() {
console.log('hello');
};
function child2() {
this.type = 'child2';
}
child2.prototype = new parent2();
console.log(new child2);
var p1 = new child2();
var p2 = new child2();
console.log(p1.say());
console.log(p1.play, p2.play);
p1.play.push(4);
console.log(p1, p2);
console.log(p1.play, p2.play);
优点:父类的方法(getName)得到了复用。
缺点:重写子类的原型 等于 父类的一个实例,(父类的实例属性变成子类的原型属性)如果父类包含引用类型的属性,那么子类所有实例都会共享该属性 (包含引用类型的原型属性会被实例共享)。
组合方式
function parent3() {
this.name = 'parent3';
this.play = [1, 2, 3];
}
function child3() {
parent3.call(this);
this.type = 'child3';
}
child3.prototype = new parent3();
var p3 = new child3();
var p4 = new child3();
console.log(p3.play, p4.play);
p3.play.push(4);
console.log(p3,p4);
console.log(p3.play, p4.play);
ajax请求步骤
创建
XMLHttpRequest
对象,也就是创建一个异步调用对象.创建一个新的
HTTP
请求,并指定该HTTP
请求的方法、URL
及验证信息.open 的参数要牢记,很多面试官爱问这样的细节
method:请求的类型;GET 或 POST
url:文件在服务器上的位置,相对位置或绝对位置
async:true(异步)或 false(同步)
设置响应
HTTP
请求状态变化的函数.发送
HTTP
请求.获取异步调用返回的数据.
使用JavaScript和DOM实现局部刷新.
xmlhttp.status:响应状态码。这个也是面试比较爱问的,这个必须知道4个以上
1消息 2成功 3重定向 4 请求错误 5服务器错误
200: "OK" 304:该资源在上次请求之后没有任何修改(这通常用于浏览器的缓存机制,使用GET请求时尤其需要注意)。 403 (禁止) 服务器拒绝请求。 404 (未找到) 服务器找不到请求的网页。 408 (请求超时) 服务器等候请求时发生超时。 500 (服务器内部错误) 服务器遇到错误,无法完成请求
0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪
call() 和 apply() 和 bind() 区别:
三者的相似之处
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。
typeof运算符
typeof underfind //underfind
typeof 'abc' //string
typeof 123 //number
typeof true //boolean
typeof {} //object
typeof [] //object
typeof null //object
typeof console.log //function
何时用 === 何时用 ==
if(obj.a == null){
//这里相当于obj.a === null || obj.a=== underfind,简写形式
//这是jq源码中推荐的写法
//除了这个的判断,其余都建议使用===
}
js内置函数
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
知道这个的用处就是为了今后学习构造函数使用
vue
MVVM模式理解
MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定
为什么会出现 MVVM 呢?
MVC 即 Model-View-Controller 的缩写,就是 模型—视图—控制器,也就是说一个标准的Web 应用程式是由这三部分组成的:
Model(模型)表示应用程序核心(比如数据库记录列表)。
View(视图)显示数据(数据库记录)。
Controller(控制器)处理输入(写入数据库记录)。
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对 象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据 创建的。
Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责 从视图读取数据,控制用户输入,并向模型发送数据。
起因
在HTML5 还未火起来的那些年 ,前端所需要的数据在后端基本上都可以处理好,View 层主要是做一下展示,那时候提倡的是 Controller 来处理复杂的业务逻辑,所以View 层相对来说比较轻量,就是所谓的瘦客户端思想。
HTML5 它为移动设备提供了一些非常有用的功能,使得 HTML5 具备了开发App的能力, HTML5开发App 最大的好处就是跨平台、快速迭代和上线,节省人力成本和提高效率,因此很多企业开始对传统的App进行改造因此,前端也需要工程化,也需要一个类似于MVC 的框架来管理这些复杂的逻辑,
经过
==前端开发就暴露出了三个痛点==
开发者在代码中大量调用相同的 DOM API,处理繁琐 ,操作冗余,使得代码难以维护。
大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
当 Model 频繁发生变化,开发者需要主动更新到View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到Model 中
虽然JQ的出现解决了大量调用相同的 DOM API,但后两个问题,也没有很好的解决
结果
==MVVM 的出现,完美解决了以上三个问题。==
MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
Vue.js 的细节
Vue.js 是采用 Object.defineProperty 的 getter 和 setter,并结合观察者模式来实现数据绑定的。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化
Vue的生命周期
什么是vue生命周期?
Vue实例从创建到销毁的过程,就是生命周期。
从开始创建、初始化数据、变编译模板、挂载DOM->渲染、更新->渲染、销毁等一系列过程,称之为Vue的生命周期
页面一上来触发了beforeCreate、created、beforeMount、mounted四个方法
vue生命周期过程
beforeCreate: <span style="color:red">(创建前)</span>--- 在数据观测和初始化事件还未开始
created: <span style="color:red">(创建后)</span>--- 获取data里面数据,没有DOM
beforeMount: <span style="color:red">(创建载入前)</span>--- 相关的render首次被调用,把data里面的数据和模板生成HTML,但并没有挂在到页面上
mounted: <span style="color:red">(载入后)</span>--- 用上面编译好的html内容替换掉el所指向的DOM对象,此过程中进行ajax操作
beforeUpdate: <span style="color:red">(更新前)</span>--- 在数据更新之前调用,发生虚拟DOM渲染之前
uodated: <span style="color:red">(更新后)</span>--- 组件DOM已经更新,可以执行依赖于DOM的操作
beforeDestroy: <span style="color:red">(销毁前)</span>--- 在实例销毁之前调用
destroyed: <span style="color:red">(销毁后)</span>--- 所有的事件监听都会被移出
组件传值
1.封装js插件成vue组件
全局组件 CustToast.vue
<template>
<div class="CustToast" :class="type" v-if="showToast">
<span class="icon">
<img :src="iconSrc" />
</span>
{{ message }}
</div>
</template>
<script>
export default {
name: "CustToast",
data() {
return {
showToast: true,
type: "normal",
message: "消息提示",
duration: 3000,
};
},
computed: {
iconSrc() {
// window.console.log("当前类型", this.type);
let tipType = ["normal", "success", "warning", "fail"];
if (tipType.includes(this.type)) {
return require(`@/assets/close.png`);
} else {
throw "Toast type数据只允许为 normal, success, warning, fail 四种其中的一种,默认为normal";
}
},
},
};
</script>
<style scoped>
.CustToast {
position: fixed;
left: 50%;
top: 50%;
background: rgb(233, 233, 235);
padding: 10px;
border-radius: 5px;
transform: translate(-50%, -50%);
animation: show-toast 0.2s;
color: #909399;
overflow: hidden;
display: flex;
align-items: center;
}
@keyframes show-toast {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.success {
color: #67c23a;
background: rgb(225, 243, 216);
}
.warning {
color: #e6a23c;
background: rgb(250, 236, 216);
}
.fail {
color: #f56c6c;
background: rgb(253, 226, 226);
}
.icon img {
width: 20px;
height: 20px;
margin-top: 3px;
margin-right: 4px;
}
</style>
全局组件配置 index.js
import vue from "vue";
// 导入自定义到Toast组件
import CustToast from "./CustToast.vue";
// 生成一个扩展实例构造器
const ToastConstructor = vue.extend(CustToast);
// 定义弹出组件的函数 接收三个参数 消息 toast类型 显示时间
function showToast(message, type = "normal", duration = 2000) {
// 实例化一个 CustToast.vue
const _toast = new ToastConstructor({
data() {
return {
showToast: true,
type: type,
message: message,
duration: duration
};
}
});
// 把实例化的 CustToast.vue 添加到 body 里
let element = _toast.$mount().$el;
document.body.appendChild(element);
// duration时间到了后隐藏
setTimeout(() => {
_toast.showToast = false;
}, duration);
}
// 需要在main.js 里面使用 Vue.use(showToast);
showToast.install = Vue => {
// 将组件注册到 vue 的 原型链里去,
// 这样就可以在所有 vue 的实例里面使用 this.$toast()
Vue.prototype.$toast = showToast;
};
// 导出
export default showToast;
2.父组件向子组件传值
父组件 index.vue
<template>
<div id="Home">
<Test :testData='testData'></Test>
</div>
</template>
<script>
// 导入的其他文件 例如:import moduleName from 'modulePath';
import Test from './comments/Test'
export default {
// import所引入的组件注册
name: "Home",
components: {
Test
},
data() {
return {
testData:['输出1','输出2','输出3']
};
},
// 监听属性
computed: {},
// 监控data中的数据变化
watch: {},
// 方法集合
methods: {},
};
</script>
<style lang='less' scoped>
//@import url(); 引入公共css类
</style>
子组件 Test.vue
<template>
<div id="Test">
<div class="Test">
<ul>
<li v-for="(item,index) in testData" :key="index">
{{item}}
</li>
</ul>
</div>
</div>
</template>
<script>
// 导入的其他文件 例如:import moduleName from 'modulePath';
export default {
//import所引入的组件注册
name: "Test",
components: {},
props: {
testData: {
type:Array,
required:true
},
},
//监听属性
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {},
};
</script>
<style lang="less" >
li {
font-size: 20px;
}
</style>
<style lang='less' scoped>
//@import url(); 引入公共css类
</style>
3子组件向父组件传值(通过事件形式)
子组件 Title.vue
<template>
<header>
<h1 @click="changeTitle">{{ title }}</h1>
</header>
</template>
<script>
export default {
name: "Title",
data() {
return {
title: "Vue.js Demo",
};
},
methods: {
changeTitle() {
this.$emit("titleChanged", "子向父组件传值"); //自定义事件 传递值“子向父组件传值”
},
},
};
</script>
父组件 index.vue
<template>
<div id="Home">
<app-header v-on:titleChanged="updateTitle"></app-header>
<h2>{{ title }}</h2>
</div>
</template>
<script>
// 导入的其他文件 例如:import moduleName from 'modulePath';
import Title from "./comments/Title";
export default {
// import所引入的组件注册
name: "Home",
components: {
"app-header": Title,
},
data() {
return {
title:"传递的是一个值",
};
},
// 监听属性
computed: {},
// 监控data中的数据变化
watch: {},
// 方法集合
methods: {
updateTitle(e) {
//声明这个函数
this.title = e;
},
},
};
</script>
<style lang='less' scoped>
//@import url(); 引入公共css类
</style>
4 sync 的语法糖解决 v-mdoel只能出现一次
### 子组件 ###
<template>
<div>
<select
:value="phoneInfo.areaCode"
placeholder="区号"
@change="handleAreaCodeChange"
>
<option value="+86">+86</option>
<option value="+60">+60</option>
</select>
<input
:value="phoneInfo.phone"
type="number"
placeholder="手机号"
@input="handlePhoneChange"
/>
<input
:value="zipCode"
type="number"
placeholder="邮编"
@input="handleZipCodeChange"
/>
</div>
</template>
<script>
export default {
name: "PersonalInfo",
// v-model 定义使用的
model: {
prop: "phoneInfo", // 默认 value
event: "change", // 默认 input
},
props: {
phoneInfo: Object,
zipCode: String,
},
methods: {
handleAreaCodeChange(e) {
this.$emit("change", {
...this.phoneInfo,
areaCode: e.target.value,
});
},
handlePhoneChange(e) {
this.$emit("change", {
...this.phoneInfo,
phone: e.target.value,
});
},
handleZipCodeChange(e) {
this.$emit("update:zipCode", e.target.value);
},
},
};
</script>
### 父组件 ###
<div>
<PersonalInfo v-model="phoneInfo" :zip-code.sync="zipCode" />
<PersonalInfo
:phone-info="phoneInfo"
:zip-code="zipCode"
@change="(val) => (phoneInfo = val)"
@update:zipCode="(val) => (zipCode = val)"
/>
phoneInfo: {{ phoneInfo }}
<br />
zipCode: {{ zipCode }}
</div>
data(){
phoneInfo: {
areaCode: "+86",
phone: "",
},
zipCode: "",
}
5组件种类
简单的说vue项目中的组件分为三种'视图组件','基础组件','业务组件'
视图组件:由 vue-router 产生的每个页面主要承载当前页面的 HTML 结构,会包含数据获取、数据整理、数据可视化等常规业务。整个文
件相对较大,但一般不会有 props 选项和 自定义事件,因为它作为路由的渲
染,不会被复用,因此也不会对外提供接口。这类组件主要是根据还原设计
稿,完成需求
基础组件:不包含业务,独立、如日期选择器、模态框等。这类组件作为项
目的基础控件,会被大量使用,因此组件的 API 进行过高强度的抽象,可以
通过不同配置实现不同的功能,开发难度要高于第一类组件,因为它的侧重点
是 API 的设计、兼容性、性能、以及复杂的功能。这类组件对 JavaScript
的编程能力有一定要求
业务组件:在业务中被多个页面复用的,它与独立组件的区别是,业务组件
只在当前项目中会用到,不具有通用性,而且会包含一些业务,比如数据请
求;而独立组件不含业务,在任何项目中都可以使用,功能单一,比如一个
具有数据校验功能的输入框。也可以对现阶段的一些流行js库进行二次封装
成vue组件
6了解组件
6-1prop
// Prop 类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
6-2button组件
<template>
<button id="6666" :disabled="disabled" :class="'i-button-size' + size" value="445" >ss</button>
</template>
<script>
// props size 自定义的验证规则判断
function oneOf (value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
}
export default {
//inheritAttrs: false,
props: {
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default: 'default'
},
disabled: {
type: Boolean,
default: false
},
}
}
</script>
使用
<template>
<div>
<my-button id="btn1" class="btn-submit" value="41"></my-button>
</div>
</template>
<script>
import myButton from '_c/my-button'
export default {
name: "testlison",
components:{
myButton
}
}
</script>
7 provide / inject 组件通信
'provide:Object | () => Object'
'inject:Array<string> | { [key: string]: string | Symbol | Object }'
使用'provide' 对象的形式,注意如果使用对象的形式,是无法获得当前
,组件的'this'指向因此也无法获取其中的data
父
<template>
<div class="home">
<input v-model="dataName.name">
<Acomponents></Acomponents>
</div>
</template>
<script>
// @ is an alias to /src
import Acomponents from '@/components/a-components'
import Vue from "vue";
export default {
name: 'home',
provide(){
this.dataName = Vue.observable({
name: "blue"
});
return{
dataName:this.dataName
}
},
components: {
Acomponents,
}
}
</script>
子
<template>
<div>
<input v-model="dataName.name">
我接受爷爷组件的传值{{dataName.name}}
</div>
</template>
<script>
export default {
inject: ['dataName'],
}
</script>
<style scoped>
</style>
1.Vue Router 是 Vue.js 官方的路由管理器,可以通过路由和组件的关联配置,形成
前端路由跳转。
2.官方文档的一句话:'用 Vue.js + Vue Router 创建单页应用,是非常简单的。使用
Vue.js ,我们已经可以通过组合组件来组成应用程序,当你要把 Vue Router 添加
进来,我们需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue
Router 在哪里渲染它们。'
router
npm install vue-router
使用Vue.use 注册路由组件
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
02 使用
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: () => import("@/views/home")
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
在页面中直接使用就可以了
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
router-link 默认渲染为一个a 标,使用tag 可以规定标签,
<router-link to="/login" tag="span">登录</router-link>
如果tag 规定是li 想让li中在包裹个a可以下面这么写:
<router-link tag="li" to="/foo">
<a>/foo</a>
</router-link>
03 动态路由
const routes = [
{
path: '/',
name: 'Home',
component: () => import("@/views/home")
},
{
path: '/about/:id',
name: 'About',
component: () => import('../views/About.vue')
}
]
页面跳转
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about/1">About</router-link>
<router-link to="/about/2">About</router-link>
<router-link to="/about/3">About</router-link>
</div>
About.vue
<div class="abouts"> aboutID {{$route.params.id }} </div>
04 命名路由
{
path: '/',
name: 'Home',
component: () => import("@/views/home")
},
<router-link :to="{ name: 'home' }">home</router-link>
05 $router -- 路由函数使用
05-01push
this.$router.push('参数是路由地址')-- 跳转指定页
注意push 是在 history 栈添加一个新的记录,因此当使用后退功能的时候
可以后退到上一个网址
当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击
<router-link :to="..."> 等同于调用 router.push(...)。
// 字符串
,/home
router.push('home')
// 对象
,/home
router.push({ path: 'home' })
// 命名的路由(动态路由使用这种方式)-> /user/123
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
05-02 replace
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而
是跟它的方法名一样替换掉当前的 history 记录。简单的说就是历史记
录后退不是上一个而是前一个,因为他把上一个给替换成自己了
05-03 go
this.$router.go(1)
07路由嵌套
const routes = [
{
name: "login",
path: "/",
component: () => import("@/views/login")
},
{
name: "Layout",
path: "/Layout",
component: () => import("@/views/Layout"),
meta: {
title: "首页",
icon: "home",
noCache: true
},
children: [
{
name: "home",
path: "/home",
component: () => import("@/views/home"),
meta: {
title: "首页",
icon: "home",
noCache: true
}
},
{
name: "user",
path: "/user",
component: () => import("@/views/user"),
meta: {
title: "用户管理",
icon: "user",
noCache: true
}
},
]
}
];
08 导航守卫
//全局路由钩子
beforeEach(to,from, next)
beforeResolve(to,from, next)
afterEach(to,from) //没有next
//独享路由钩子
beforeEnter(to,from, next)
//组件内路由钩子
beforeRouteEnter(to,from, next)
beforeRouteUpdate(to,from, next)
beforeRouteLeave(to,from, next)
08-01导航守卫的三个参数
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
08-02全局前置守卫
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
08-03全局后置守卫
router.afterEach((to, from) => {
// ...
})
09 路由独享的守卫
var routes = [
{ path: "/", name: "parent", component: Parent },
{
path: '/comp1', name: 'comp1', component: Comp1,
beforeEnter: (to, from, next) => {
console.log(to)
console.log(from)
next()
}
},
{
path: '/comp2', name: 'comp2', component: Comp2,
},
{ path: "*", component: { template: "<h2>404---404</h2>" } }
]
Vuex 的使用
01 安装和引入
npm install vuex --save
1.第一步导入vuex
2.第二步创建引入Vuex
3.第三步创建一个new Vuex.Store 实例
import Vue from 'vue'
import Vuex from 'vuex' // 第一步
Vue.use(Vuex) //第二步
export default new Vuex.Store({ //第三步
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
在main.js 文件中挂载到根vue实例中
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app');
02 参数
1.'Store' -- vuex 的仓库储存这我们需要使用的参数内容在创建的时候使用: new Vuex.Store({})
2.'state' -- 可以理解成Vue中的data,我们的一些公共数据放在这里
3.'mutations' -- 可以理解成Vue中的methods。也可以理解成java的set。简单的说
所有对'state' 中的数据更改都是通过'mutations' 中的方法操控,Vuex 不提倡直接
更改'state' 中的数据
4.'getters' -- 可以理解成Vue的computed 计算属性,或者java中的get,当我们要
获取'state' 中的方法的时候从getter中取值
5.'Action' -- 异步获取请求参数赋值,他会操控'mutations',再让'mutations'给
'state' 赋值
02-1理解state
// state.js
export default new Vuex.Store({ //第三步
state: {
administratorName:'admin',
},
mutations: {
},
actions: {
},
modules: {
}
}
在我们的页面中使用STATE,
<template>
<div>
<p>{{administratorName}}</p>
</div>
</template>
<script>
export default {
name: "store",
data(){
return{}
},
methods:{},
computed:{
//将vuex中的administratorName数据取出来,直接展示在页面上
administratorName(){
return this.$store.state.administratorName;
}
}
}
</script>
<style scoped>
</style>
相当于我们展示页面中的data,但是并不是data数据,
02-2理解getters
当我们在state中的有个数组list,现在需求是所有页面的只需要大于5的文章id,我们就可以在getters中实现数据值的过滤
export default new Vuex.Store({
state: {
list: [1, 3, 5, 7, 9, 20, 30]
},
getters: {
filteredList: (state) => {
return state.list.filter(item => item > 5)
}
},
mutations: {},
actions: {},
modules: {}
});
页面中使用
computed: {
list() {
return this.$store.getters.filteredList;
}
},
02-3理解mutations
1.当我们想改变'state' 中的值的时候可以使用'mutations ',它相当于vue的method,也就是是可以理解我们来触发Vuex 中的'mutations '方法来改变getters值
2.每个'mutations ' 中定义的参数两个值,第一个值是Vuex中的'state' 对象,第二
个是,传递过来的参数,也是一个对象
3.如何使用,在Vuex 的'mutations ' 定义好之后,在对应的组件中的methods 方
法去触发,有点类似子传父,使用方法:
this.$store.commit('mutations 中的方法名','参数对象')
mutations传递参数赋值
<!-- 点击按钮传递不同的值 -->
<template>
<div id="Projects">
<p>{{number}}</p>
<button @click="addCount(5)">+5</button>
<button @click="addCount(10)">+10</button>
</div>
</template>
触发点击事件,将点击按钮的参数注册在vuex中
computed: {
number(){
return this.$store.state.counter
}
},
methods: {
addCount(count) {
this.$store.commit("incrementCount", count);
}
}
接收传值。将状态赋值给store
state: {
counter: 25
},
mutations: {
incrementCount(state, count) {
state.counter = count
console.log(count)
}
mutations提交风格
this.$store.commit("incrementCount", count);
// 如果打印count,得到的是count
this.$store.commit({ type: "incrementCount",count });
// 如果打印count,得到的是一个对象
mutations响应
// 向原有对象增加值
Vue.set(state.info, "address", '地球');
// 删除原有对象中的值
Vue.delete(state.info, "age")
mutations常量类型
官方推荐,将mutations中的方法名都定义为常量,不容易出错,也便于管理维护
在store文件下创建mutations-type.js文件,存放常量
export const INCREMENT = "increment"
export const DECREMENT = "decrement"
在store文件下的index.js文件中导入并使用
import {
INCREMENT,
DECREMENT
} from "../store/mutations-type"
mutations: {
[INCREMENT](state) {
state.counter++;
},
[DECREMENT](state) {
state.counter--;
},
}
在App.vue文件中导入并使用
import { INCREMENT, DECREMENT } from "../src/store/mutations-type";
methods: {
add() {
this.$store.commit(INCREMENT);
},
sub() {
this.$store.commit(DECREMENT);
},
}
03 Vuex -- state扩展
mapState
1.官方的第一种写法,就是我们案中的一种缩写形式
2.第二种是官方第一种的缩写形式
3.第三种为了方便获取this 进行组合形式的数据返回
4.第四种是一二种的缩写用,'使用数组'中直接包含'state' 中要使用的值
// 页面中使用辅助函数
state: {
count: 25
},
computed: {
...mapState({
// 箭头函数可使代码更简练
count: state => state.count,
})
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
countPlusLocalState (state) {
return state.count + this.localCount
}
//'使用数组'中直接包含'state' 中要使用的值
'count'
},
...mapState(['对应vuexstate中值名字'])
...mapState({'要在页面中使用的名称': 对应取Vuex中的state方法})
04 getters 扩展
mapGetters 辅助函数
// 01 引入
import { mapGetters } from 'vuex'
// 02 处理数据
getters: {
filteredList: state => {
return state.list.filter(item => item > 5);
},
incrementCount:state => {
return state.counter
}
},
// 03 页面中使用
...mapGetters([
'filteredList',
'incrementCount',
])
// 04 使用对象形式:
...mapGetters({
doneCount: 'filteredList',
})
05 mutations-- 扩展
mapMutations 辅助函数
import { mapMutations } from 'vuex'
store.js
mutations: {
mopote(state,mopote) {
state.appNameWithVersion = mopote
},
tiemdatafer(state,tiem){
state.tiem = tiem
},
}
页面中
<template>
<div class="about">
<div class="abouts">aboutID :{{ $route.params.id }}</div>
<p>{{ appNameWithVersion }}</p>
<p>{{ timee }}</p>
<button @click="handleChangeAppVersion">点击</button>
<button @click="handleChangetime('2019-02-09')">时间</button>
</div>
</template>
页面中
//监听属性
computed: {
...mapState({
timee: state => state.tiem,
appNameWithVersion: "appNameWithVersion"
})
// timee() {
// return this.$store.state.tiem;
// },
// appNameWithVersion() {
// return this.$store.state.appNameWithVersion;
// }
},
methods: {
// handleChangeAppVersion() {
// this.$store.commit("mopote", this.Version);
// },
...mapMutations(["mopote"]),
handleChangeAppVersion() {
this.mopote(this.Version);
},
// handleChangetime(tiem) {
// this.$store.commit("tiemdatafer", tiem);
// },
...mapMutations({ handleChangetime: "tiemdatafer" })
}
06 项目中使用
index.js 数据值
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
state:{//设置属性 用来存储数据
message:{}
},
getters:{//对应方法 用来获取属性的状态
getMessage:state => state.message
},
mutations:{//更改属性的状态
setMessage(state, data){//定义的修改 属性的方法
state.message = data
}
},
actions:{//应用 mutation
}
})
在.vue中绑定 赋值的使用 😂😂
/// setMessage 为 store index.js 中的 mutations 属性中的定义的方法
this.$store.commit('setMessage',data.message)
在.vue中绑定 获取属性的使用 😎😎
/// message为 store index.js 中的 state属性中的定义的方法
this.$store.state.message
😃😃
computed:{
get(){
return this.$store.state.menuItems
},
set(data){
this.$store.commit('setMessage',data)
}
}
从 getters 中获取 message
let data = this.$store.getters.getMessage
- 感谢你赐予我前进的力量