Hello,everyone !
想以一个轻松愉悦的心情来开始我的每一篇文章。
这是每一次的整理和缩影,希望大家可以发表意见,促进成长。
以下整理是很久之前留存下来的,出处并不记得是在哪里了,尴尬!
面试题很全,请允许我的借鉴哦~ 撒由那拉~
开搞!
块级元素:块级元素
行内元素:行内元素
参考地址:参考地址
HTML解析过程:构建DOM树、构建CSSOM树、根据DOM树和CSSOM树构建render树、有了render树就开始布局Layout、最后绘制paint。
1、 构建DOM树
将HTML构建成一个DOM树,也就是构建节点,把所有的节点都构建出来。
2、构建CSSOM
解析css去构建CSSOM树
3、构建render树
DOM已经构建好了,css也有了,浏览器就会根据这两个来构造render树,浏览器就知道了有哪些节点、各个节点的CSS定义以及他们的从属关系。
4、布局
当render树有了,通过render树,浏览器开始计算各个节点的位置和样式。
5、绘制
遍历render树,在页面上绘制每个节点。
6、重排reflow
当render树绘制完成之后,比如JavaScript改变样式或添加节点,这时候render树就需要重新计算。
7、重绘repaint
要点:
1、如果遇到link和style,那就就会去下载这些外部的css资源,但是css跟DOM的构建是并行的,就是说不会阻塞DOM树的构建。
2、如果遇到script,那么页面就会把控制权交给JavaScript,直到脚本加载完毕或者是执行完毕。
3、页面的渲染是依靠render树,也就是说如果css没有加载完成,页面也不会渲染显示。
4、JavaScript执行过程中有可能需要改变样式,所以css加载也会阻塞JavaScript的加载。
5、JavaScript执行过程中如果操作DOM,但是DOM树又是在JavaScript之后才能构建,就会报错,找不到节点。
总结:css不会阻塞dom树的解析构建,但是会阻塞render树的渲染(只要是阻塞了render构建的资源都是可以优化的方向css和js),因为js可以操作dom(不能一边在改变dom同时又在渲染dom),所以当初设计的时候就是js和render树的渲染是互斥的。
当浏览器的HTML解析器遇到一个script标记时会暂停构建DOM,然后将控制权移交至JavaScript引擎,这时引擎会开始执行JavaScript脚本,直到执行结束后,浏览器才会从之前中断的地方恢复,然后继续构建DOM。每次去执行JavaScript脚本都会严重地阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。显而易见,如果对JavaScript的执行位置运用不当,这将会严重影响渲染的速度。
html渲染参考地址
在标准模式下的盒模型:盒子总宽度/高度=width/height+padding+border+margin
在怪异模式下的盒模型下,盒子的总宽度和高度是包含内边距padding和边框border宽度在内的,盒子
总宽度/高度=width/height + margin = 内容区宽度/高度 + padding + border + margin;
box-sizing有两个值一个是content-box,另一个是border-box。
当设置为box-sizing:content-box时,将采用标准模式解析计算;
当设置为box-sizing:border-box时,将采用怪异模式解析计算。
* 什么是 BFC
BFC(Block Formatting Context)格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。
* 形成 BFC 的条件
* 浮动元素,float 除 none 以外的值
* 定位元素,position(absolute,fixed)
* display 为以下其中之一的值 inline-block,table-cell,table-caption
* overflow 除了 visible 以外的值(hidden,auto,scroll)
* BFC 的特性
* 内部的 Box 会在垂直方向上一个接一个的放置。
* 垂直方向上的距离由 margin 决定
* bfc 的区域不会与 float 的元素区域重叠。
* 计算 bfc 的高度时,浮动元素也参与计算
* bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。
不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
* clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式: {clear:both;height:0;overflow:hidden;}
* 给浮动元素父级设置高度
* 父级同时浮动(需要给父级同级元素添加浮动)
* 父级设置成inline-block,其margin: 0 auto居中方式失效
* 给父级添加overflow:hidden 清除浮动方法
* 万能清除法 after伪类 清浮动(现在主流方法,推荐使用)
.float_div:after{
content:".";
clear:both;
display:block;
height:0;
overflow:hidden;
visibility:hidden;
}
.float_div{
zoom:1
}
static(静态): 没有特别的设定,遵循基本的定位规定,不能通过z-index进行层次分级
relative(相对定位): 对象不可层叠、不脱离文档流,参考自身静态位置通过 top,bottom,left,right 定位,并且可以通过z-index进行层次分级。
absolute(绝对定位):选取其最近一个最有定位设置的父级对象进行绝对定位,如果对象的父级没有设置定位属性,absolute元素将以body坐标原点进行定位,可以通过z-index进行层次分级。
fixed(固定定位):这里所固定的参照对像是可视窗口而并非是body或是父级元素。可通过z-index进行层次分级。
span {
width: 0;
height: 0;
border-top: 40px solid transparent;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
border-bottom: 40px solid #ff0000;
}
6、css3实现0.5px的细线
/* css */
.line {
position: relative;
}
.line:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
background-color: #000000;
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
}
/* html */
flex容器属性:
主轴方向:水平排列(默认) | 水平反向排列 | 垂直排列 | 垂直反向排列
flex-direction: row | row-reverse | column | column-reverse;
换行:不换行(默认) | 换行 | 反向换行(第一行在最后面)
flex-wrap: nowrap | wrap | wrap-reverse;
flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
flex-flow: || ;
主轴对齐方式:起点对齐(默认) | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
justify-content: flex-start | flex-end | center | space-between | space-around;
交叉轴对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 第一行文字的基线对齐
align-items: stretch | flex-start | flex-end | center | baseline;
多根轴线对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
Flex项目属性
顺序:数值越小越靠前,默认为0
order: ;
放大比例:默认为0,如果有剩余空间也不放大,值为1则放大,2是1的双倍大小,以此类推
flex-grow: ;
缩小比例:默认为1,如果空间不足则会缩小,值为0不缩小
flex-shrink: ;
项目自身大小:默认auto,为原来的大小,可设置固定值 50px/50%
flex-basis: | auto;
flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto
两个快捷值:auto (1 1 auto) 和 none (0 0 auto)
flex:none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
项目自身对齐:继承父元素(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 基线对齐 | 拉伸对齐
align-self: auto | flex-start | flex-end | center | baseline | stretch;
1.flex方式
2.定位方式
3.浮动方式
1、div大小已知的绝对定位
2、div大小未知的绝对定位
3、flex
基本数据类型:Undefined、Null、Boolean、Number、String
值类型:数值、布尔值、null、undefined。
引用类型:对象、数组、函数。(object、array、function)
typeof判断除了Object类型的数据
Object.prototype.toString()判断是数据还是对象 Array.isArray()
1. 创建空对象;
var obj = {};
2. 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象;
obj.__proto__ = ClassA.prototype;
3. 使用新对象调用函数,函数中的this被指向新实例对象:
ClassA.call(obj);//{}.构造函数();
4. 如果无返回值或者返回一个非对象值,则将新对象返回;如果返回值是一个新对象的话那么直接直接返回该对象。
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
// 如果构造函数返回的是对象或是函数,且不是null,则返回该对象
return ret;
}
return res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);
每次调用一个函数时,都会创建一个新的执行上下文,在JavaScript的解释器中,执行上下文的调用都有两个阶段:
1、创建阶段【调用函数时,但是在执行里面的代码之前】:
创建作用域链
创建变量,函数和参数
确定this的值
以下是解释器如何评估代码的伪概述:
初始化作用域链
创建变量对象:
创建arguments对象,检查参数的上下文,初始化名称和值并创建引用的副本。 扫描上下文以获取函数声明:
对于找到的每个函数,在变量对象(或活动对象)中创建一个属性,该属性是确切的函数名称,该函数具有指向内存中函数的引用指针。
如果函数名已存在,则将覆盖引用指针值。
扫面上下文以获取变量声明:
对于找到的每个变量声明,在变量对象(或活动对象)中创建一个属性,该属性是变量名称,并将值初始化为undefined。
如果变量名称已存在于变量对象(或活动对象)中,则不执行任何操作并继续扫描(即跳过)。
确定上下文中的this。
2、激活/代码执行阶段
能够读取其他函数内部变量的函数。 或简单理解为定义在一个函数内部的
函数,内部函数持有外部函数内变量的引用。
1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,
f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,
被垃圾回收机制回收。
1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
这里首先需要明白几个概念:同步任务、异步任务、任务队列、microtask、macrotask
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,等待同步任务执行完毕之后,轮询执行异步任务队列中的任务
macrotask队列 等同于我们常说的任务队列,macrotask是由宿主环境分发的异步任务,事件轮询的时候总是一个一个任务队列去查看执行的,"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。
microtask 即微任务,是由js引擎分发的任务,总是添加到当前任务队列末尾执行。另外在处理microtask期间,如果有新添加的microtasks,也会被添加到队列的末尾并执行。注意与setTimeout(fn,0)的区别:setTimeOut(fn(),0)指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
setTimeout
setInterval
setImmediate
requestAnimationFrame
I/O
UI rendering
process.nextTick
Promises
Object.observe
MutationObserver
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
>=node10版本是这个结果: script start -> async1 start -> async2 -> promise1 -> script end -> promise2 -> async1 end -> setTimeout
async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout
应用场景:
防抖(debounce):就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
节流(throttle):就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
鼠标不断点击触发,mousedown(单位时间内只触发一次)
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断 所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait ,type) {
if(type===1){
var previous = 0;
}else if(type===2){
var timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
关系:instance.constructor.prototype = instance.proto
特点:JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本,当我们修改原型时,与之相关的对象也会继承这一改变。 当我们需要一个属性时,JavaScript引擎会先看当前对象中是否有这个属性,如果没有的话,就会查找它的prototype对象是否有这个属性,如此递推下去,一致检索到Object内建对象。
function Func(){}
Func.prototype.name = "汪某";
Func.prototype.getInfo = function() {
return this.name;
}
var person = new Func();
console.log(person.getInfo());//"汪某"
console.log(Func.prototype);//Func { name = "汪某", getInfo = function() }
Function.prototype.call2 = function (context) {
var context = context || window;
// 当context.fn函数执行的时候,函数里面的this就会指向context
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
Function.prototype.apply2 = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fbound = function () {
self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
}
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
return fbound;
}
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log('parent name:', this.name);
}
function Child(name, parentName) {
Parent.call(this, parentName);
this.name = name;
}
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
// 用空对象继承原型,节省内存
Child.prototype = create(Parent.prototype);
Child.prototype.sayName = function() {
console.log('child name:', this.name);
}
// 将原型的构造函数指向重新知道构造函数本身
Child.prototype.constructor = Child;
var parent = new Parent('汪某');
parent.sayName();// parent name: 汪某
var child = new Child('son', '汪某');
function myPromise(constructor) {
let self = this;
self.status = "pending"
//定义状态改变前的初始状态
self.value = undefined;
//定义状态为resolved的时候的状态
self.reason = undefined;
//定义状态为rejected的时候的状态
function resolve(value) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
//两个==="pending",保证了状态的改变是不可逆的
if (self.status === "pending") {
self.reason = reason;
self.status = "rejected";
}
}
//捕获构造异常
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
//同时,需要在 myPromise的原型上定义链式调用的 then方法:
myPromise.prototype.then = function(onFullfilled, onRejected) {
let self = this;
switch (self.status) {
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
//测试一下:
var p = new myPromise(function(resolve, reject) {
resolve(1)
});
p.then(function(x) {
console.log(x)
})
高级版本
浅拷贝 es6的Object.assign和{…obj}的结构赋值都是一层的深拷贝和多层的浅拷贝
JSON.parse(JSON.stringify(obj))对于正则函数等一些对象不能进行深拷贝
手写深拷贝简单版本,会有问题(像是正则、函数和循环引用),详细可以参考jq.extend或是lodash.clone
function deepCopy(obj) {
//判断是否是简单数据类型,
if (typeof obj == "object") {
//复杂数据类型
var result = obj.constructor == Array ? [] : {};
for (let i in obj) {
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
} else {
//简单数据类型 直接 == 赋值
var result = obj;
}
return result;
}
for in
1.一般用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。
2.不建议使用for in 遍历数组,因为输出的顺序是不固定的。
3.如果迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环之前,先检查该对象的值是不是null或者undefined
for of
1.for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
遍历对象
var s = {
a: 1,
b: 2,
c: 3
}
var s1 = Object.create(s);
for (var prop in s1) {
console.log(prop); //a b c
console.log(s1[prop]); //1 2 3
}
for (let prop of s1) {
console.log(prop); //报错如下 Uncaught TypeError: s1 is not iterable
}
for (let prop of Object.keys(s1)) {
console.log(prop); // a b c
console.log(s1[prop]); //1 2 3
}
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
//阻止冒泡行为
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false
//阻止浏览器的默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
//vue实现数据双向绑定的原理就是用Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的。
//Object.property()方法的解释:Object.property(参数1,参数2,参数3) 返回值为该对象obj
//其中参数1为该对象(obj),参数2为要定义或修改的对象的属性名,参数3为属性描述符,属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合使用。而get和set属于存取描述符对象的属性。
//这个方法会直接在一个对象上定义一个新属性或者修改对象上的现有属性,并返回该对象。
为什么要替换Object.defineProperty?
在Vue中,Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。
什么是Proxy
Proxy是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后
beforeCreate 创建前执行(vue实例的挂载元素$el和数据对象data都为undefined,还未初始化)
created 完成创建 (完成了data数据初始化,el还未初始化)
beforeMount 载入前(vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。)
mounted 载入后html已经渲染(vue实例挂载完成,data.message成功渲染。)
beforeUpdate 更新前状态(view层的数据变化前,不是data中的数据改变前)
updated 更新状态后
beforeDestroy 销毁前
destroyed 销毁后 (在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在)
说一下每一个阶段可以做的事情
beforeCreate:可以在这里加一个loading事件,在加载实例时触发。
created:初始化完成时的事件写这里,如果这里结束了loading事件,异步请求也在这里调用。
mounted:挂在元素,获取到DOM节点
updated:对数据进行处理的函数写这里。
beforeDestroy:可以写一个确认停止事件的确认框。。
附上一张中文解析图
解析图
在 router 目录下的 index.js 文件中,对 path 属性加上 /:id。
使用 router 对象的 params.id 获取
vue-router 有哪几种导航钩子?
全局导航钩子(跳转前进行判断拦截)
router.beforeEach(to, from, next),
router.beforeResolve(to, from, next),
router.afterEach(to, from ,next)
组件内钩子
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
单独路由独享组件
beforeEnter
父组件向子组件传值:
子组件在props中创建一个属性,用来接收父组件传过来的值; 在父组件中注册子组件; 在子组件标签中添加子组件props中创建的属性; 把需要传给子组件的值赋给该属性
子组件向父组件传值:
子组件中需要以某种方式(如点击事件)的方法来触发一个自定义的事件; 将需要传的值作为$emit的第二个参数,该值将作为实参传给响应事件的方法; 在父组件中注册子组件并在子组件标签上绑定自定义事件的监听。
是一个能方便vue实例及其组件传输数据的插件 方便传输数据,作为公共存储数据的一个库
state: 状态中心
mutations: 更改状态,同步的
actions: 异步更改状态
getters: 获取状态
modules: 将state分成多个modules,便于管理
应用场景:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车。
公司有个仓库
1.State(公司的仓库)
2.Getter(只能取出物品,包装一下,不能改变物品任何属性)
3.Muitation(仓库管理员,只有他可以直接存储到仓库)
4.Action(公司的物料采购员,负责从外面买东西和接货, 要往仓库存东西,告诉仓库管理员要存什么)
非常要注意的地方:只要刷新或者退出浏览器,仓库清空。
Vue hash 路由和 history 路由的区别
hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
diff算法