本文最后更新于 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