前端面试题(准备)

本文深入探讨JavaScript的原型和原型链、闭包、Ajax、作用域、变量声明周期、跨域方法、节流与防抖等核心概念,同时解析Promise、ES6新特性、Set与Map数据结构、async/await异步处理、Vue.js MVVM模式及虚拟DOM原理等关键技术。
摘要由CSDN通过智能技术生成

原型和原型链

原型

js中的对象都包含了一个prototype的内部属性,这个属性所对应的就是该对象的原型(原型是一个对象模板)

原型链

是有一些用来继承和共享属性的对象组成的对象链,并且原型链的长度是有限的(对象之间存在继承关系,在js中是通过prototype对象指向父类对象,直到object对象为止,这样就形成了一个原型指向的链条,我们称之为原型链)

举例:student>person>object 学生>人类>object类

function Animal(name){
	this.name=name
}
Animal.prototype.getName={
	consloe.log(this.name)
}
var animal1=new Animal('Kate');
var animal2=new Animal('Lucy');

animal1和animal2共享方法getName

var A=function(){ }
A.prototype.n=1;
var b=new A();
A.prototype={n:2,m:3};
var c=new A();
console.log(b.n,b.m,c.n,c.m) // 1,undefined,2,3

b继承了A,c继承A的时候添加了n和m
undefined是一个表示“无”的原始值;null用来表示尚未存在的对象;

闭包

是能够读取其他函数内部变量的函数(函数a的内部函数b,被函数a之外的变量引用的时候就创建了闭包)

一般在什么情况下使用:函数封装,定时器;

闭包例子:

function a() {
	var i=0;
	function b(){
		i++;
		alert(i);
	}
	return b;
}
var c= a();
c();
输出结果为1,2,3

闭包的用处:读取函数的局部变量;让这些变量值始终保持在内存中。
闭包的优点:减少全局变量;减少传递函数的参数量;封装。
闭包的缺点:使用闭包会占有内存资源,过多的使用闭包可能会导致内存溢出等;

内存泄漏的解决方案:把那些不需要的变量,但是垃圾回收站又收不走的那些赋值为null,然后让垃圾回收走。

Ajax

Ajax是什么?

是异步JavaScript和XML,是一种创建交互式网页应用的网页开发技术,能够向服务器请求额外的数据而无须加载页面,对网页的某部分进行更新。

XMLHTTPRequest对象是什么?

是Ajax的基础;用于在后台与服务器交换数据。

get和post请求

get:常用于向服务器查询信息;
post:常用于向服务器发送应该被保存的数据;
post请求消耗的资源多,get请求速度是post的两倍

创建一个Ajax

1.创建XMLHttpRequest对象(Ajax对象)
2.使用open方法设置和服务器的交互信息(建立服务器链接)
3.设置发送的数据,开始和服务器交互(发生请求)
4.注册事件(建立Ajax事件)
5.更新界面(http responseText)

Ajax的优缺点

优点:减少服务器的负担,按需取数据,最大程度的减少了冗余请求;
局部刷新页面,减少用户心里和实际的等待时间,带来更好的用户体验;
进一步促进页面和数据的分离;
缺点:编写时需考虑浏览器的兼容性,因为使用了大量js和Ajax的引擎;
对流媒体还有移动设备的支持性不太豪。

js的作用域

js的局部作用域:变量在函数内声明,变量为局部作用域。
局部变量:只能在函数内部访问
局部变量在函数开始执行时创建,函数执行完后,局部变量会自动销毁

myFunction();
    function myFunction(){
        var a=10;
        console.log(a);//10
    }
   console.log(a);//a is not defined

js的全局变量:变量定义在函数外,即为全局变量
全局变量作用域:网页中所有的脚本和函数均可使用
如果变量在函数中内没有声明(没有关键字var),该变量为全局变量

function myFunction(){
        a=19;
        console.log(a);//19
    }
   myFunction();
   console.log(a);//19

js变量声明周期
局部变量在函数执行完毕之后销毁
全局变量子在页面关闭后销毁
HTML中的全局变量是window对象,所有数据变量都属于window对象

typeof:用来检测变量的数据类型
null和undefined的区别
undefined是一个没有设置值的变量
null表示一个空对象

this关键字
js中的this关键字不是固定不变的,它会随着环境的改变而改变。

在方法中,this表示该方法所属的对象;
如果单独使用,this表示全局对象;
在函数中,this指向函数的所属者;
在函数中,在严格模式下,this是未定义的undefined
在事件中,this指向触发这个事件的对象,特殊的是,IE中AttachEvent中的this总是指向全局对象window
类似call()和apply()方法可以将this引用到任何对象。
this总是指向函数的直接调用者
如果有new关键字,this指向new出来的那个对象

js跨域方法和原理
js跨域是指在js在不同域直接进行数据传输或通信。
产生跨域的原因:协议不同;端口号不同;主机名称不同。

jsonp跨域
在js中,我们直接用XMLHttpRequest请求不同域上的数据时是不可以的,在页面上引入不同域上的js脚本却是可以的。
jsonp利用了这个特性来实现跨域
原理:通过src+callback回调函数来请求。

cros跨域
一般在后台配置cros跨域请求
PHP后台配置
JAVA后台配置
.NET后台配置

js节流和防抖

函数节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
节流原理:规定时间内只执行一次,它与防抖的最大区别是即使再高频的动作在规定时间内都会执行一次。

函数防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频函数再次触发,则重新计算时间。
防抖实现方式:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法。
缺点:如果事件在规定的时间间隔内被不断触发,则调用方法会被不断延迟。

两者都是为了限制函数的执行频次,以优化函数触发频率过高会导致响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。

节流应用场景:DOM元素的拖拽功能实现,搜索联想。
防抖应用场景:每次resize/scroll触发统计事件,文本输入验证。

浏览器缓存
浏览器缓存:cookie,localstorage,sessionstorage。
共同点:它们都是保存在浏览器端并且同源的。
区别:

  1. cookie数据始终在同源的http请求中携带,即cookie在浏览器和服务器间来回传递;localstorage和sessionstorage不会自动把数据发送给服务器,仅在本地保存。
  2. 数据有效期不同:sessionstorage仅在浏览器关闭之前有效;localstorage始终有效,即使浏览器关闭也有效;cookie只在设置cookie过期时间之前有效,即使窗口关闭或者浏览器关闭;
  3. 存储大小不同:cookie数据不超过4K;localstorage和sessionstorage比cookie大的多,可达5M
  4. 作用域不同:sessionstorage在不同的浏览器窗口不共享,即使一个页面;localstorage在所有同源窗口是共享的;cookie也是。

jQuery
jQuery是什么?

jQuery是一个款苏简洁的Javascript框架,是继prototype之后又一个优秀的Javascript代码库。
(是一个快速、轻量级、可扩展的js库。写的少做的多)

Bootstrap
Bootstrap是一个用于快速开发web应用程序和网站的前端框架。(基于HTML、CSS、Javascript;移动设备优先,浏览器支持,容易上手,响应式设计)

call()和apply()的区别
call():调用一个对象的一个方法以另一个对象替换当前对象。
apply:应用某个对象的一个方法,用另一个对象替换当前对象(继承性)。

Json

json是用于存储和传输数据的格式。
json通常用于服务端向网页传递数据
json是一种轻量级的数据集交换格式,是独立的语言,易于理解

函数的调用

4种调用方式,每种方式的不同在于this的初始化:

  1. 作为一个函数调用
  2. 函数作为方法调用
  3. 使用构造函数调用函数
  4. 作为函数方法调用函数
//函数作为方法调用
var myObjext={
        firstName:"Mike",
        lastName:"Dod",
        fullName:function(){
            return this.firstName+" "+this.lastName;
        }
    }
   console.log(myObjext.fullName());
   //使用构造函数调用函数
    function myFunction(a,b){
        this.one=a;
        this.two=b;
    }
    var x=new myFunction("one","two");
   console.log(x.one);
   //作为函数方法调用函数
    function myFunction1(a,b){
        return a+b;
    }
    myObjext=myFunction1.call(myObjext,2,5);
   console.log(myObjext);

Javascript的函数

 /*普通函数*/
    function myFunction(){
        alert("hello world");
    }
    /*带参函数*/
    function myFunction(a,b){
        alert(a+b);
    }
    /*带返回值的函数*/
    function myFunction1(){
        console.log(1);
        var x=5;
        return x;
    }
    document.getElementById("one").innerHTML=myFunction1();
    /*带参函数 形参和实参*/
    function showname(name,sex,age){
        return name+sex;
    }
    var name=showname("张三","男",18)
    console.log(name);
    /*如果函数没有参数列表 传递参数怎么接收参数*/
    function showData(){
//      arguments 参数列表对象
//        arguments 取值按照集合来取值 key:value 索引
        console.log(arguments[0], arguments[1],arguments.length);
    }
    showData("小花",19);
    /*匿名函数  不带函数名称的函数 用变量去接收
    * 匿名函数不提前声明
    * */
    var list=function(){
        console.log(arguments);
        return arguments[0];
    }
    console.log(list(1, 2, 3));
    /*自执行函数  自执行的函数体*/
    //有实参形参 返回值
    var mm=(function (x,y) {
        console.log(x, y);
        console.log(arguments);
        return x+y;
    })(1,2);
    console.log(mm);

ES6

es5和es6的区别,说一下你所知道的es6:

ECMAScript5,即ES5,是ECMAScript的第五次修订,于2009年完成标准化
ECMAScript6,即ES6,是ECMAScript的第六次修订,于2015年完成,也称ES2015
ES6是继ES5之后的一次改进,相对于ES5更加简洁,提高了开发效率

ES6新增的一些特效:

  1. let声明变量和const声明常量
  2. 箭头函数ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义
  3. 模板字符串模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串
  4. 解构赋值ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值
  5. class 类的继承ES6中不再像ES5一样使用原型链实现继承,而是引入Class这个概念

var、let和const之间的区别

var声明变量可以重复声明,而let不可以重复声明;
var是不受限于块级作用域,而let是受限于块级作用域;
var会与window相映射,而let不与window相映射;
var存在变量提升(变量可以在声明之前使用),而let不存在,如果在变量上面访问会报错;
const声明之后必须赋值,否则会报错;
const定义了不可变量,改变了就会报错;
const和let一样不会与window相映射、支持块级作用域、在声明上面访问变量会报错

使用箭头函数应该注意什么?

  1. 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  2. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  3. 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
  4. 不可以使用yield命令,因此箭头函数不能用作Generator函数。

为什么需要块级作用域?

ES5只有全局作用域和函数作用域,没有跨级作用域,带来的问题:内层变量可能会覆盖外层变量,用来计数的循环变量泄漏出为全局变量。

Set和Map数据结构
应用场景Set用于数据重组,Map用于数据储存

Set: 成员不能重复; 只有键值没有键名,类似数组;可以遍历,方法有add, delete,has
Map:本质上是健值对的集合,类似集合;可以遍历,可以跟各种数据格式转换

Set

set类似于数组,但是成员的值都是唯一的,没有重复的值。
set本身是一个构造函数,用来生成set数据结构。
Set实例的属性和方法
Set结构的实例有以下属性。

  • Set.prototype.constructor:构造函数,默认就是Set函数。
  • Set.prototype.size:返回Set实例的成员总数。

Set实例的方法分为两大类:
操作方法(用于操作数据)和遍历方法(用于遍历成员)。

下面先介绍四个操作方法。

  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。

Set结构的实例有四个遍历方法,可以用于遍历成员。

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
  • 需要特别指出的是,Set的遍历顺序就是插入顺序。

Map

Map结构的目的和基本用法。
JavaScript的对象(Object),本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
Map结构的实例有以下属性和操作方法。

  • size属属性性: size属性返回Map结构的成员总数。
  • set(key, value):set方法设置key所对应的键值,然后返回整个Map结构。
    如果key已经有值,则键值会被更新,否则就新生成该键。
  • get(key):get方法读取key对应的键值,如果找不到key,返回undefined。
  • has(key):has方法返回一个布尔值,表示某个键是否在Map数据结构中。
  • delete(key):delete方法删除某个键,返回true。如果删除失败,返回false。
  • clear() clear方法清除所有成员,没有返回值。

Map原生提供三个遍历器生成函数和一个遍历方法。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历Map的所有成员。
  • Map与其他数据结构的互相转换
    *Map转为数组:Map转为数组最方便的方法,就是使用扩展运算符(…)
  • 数组转为Map:将数组转入Map构造函数,就可以转为Map。
  • Map转为对象 如果所有Map的键都是字符串,它可以转为对象。
    Map转为JSON Map转为JSON要区分两种情况。
  1. 一种情况是,Map的键名都是字符串,这时可以选择转为对象JSON。
  2. 另一种情况是,Map的键名有非字符串,这时可以选择为数组JSON。

ECMAScript 6 怎么写 class ,为何会出现 class?

ES6的class可以看作是一个语法糖,它的绝大部分功能ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法

//定义类
class Point { 
  constructor(x,y) { 
      //构造方法
       this.x = x; //this关键字代表实例对象
       this.y = y; 
  } toString() {
       return '(' + this.x + ',' + this.y + ')'; 
  }
}

类的实例对象:生成类的实例对象的写法,与ES5完全一样,也是使用new命令,如果忘记加上new,像函数那样调用class,将会报错。
class不存在变量的提升。
class表达式:与函数一样,类也可以使用表达式的形式来定义。
class继承:通过关键字extends来实现。
extends关键字后面可以跟多种类型的值。
class的取值函数getter和存值函数setter

Promise构造函数
promise构造函数是同步执行的,then方法是异步执行的

  • promise构造函数接受一个函数作为参数,该函数两个参数分别是resolve和reject。
    resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果, 作为参数传递出去;
    reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected), 在异步操作失败时调用,并将 异步操作报出的错误,作为参数传递出去。

//Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
{
    promise.then(function(value){
        //sucess
    },function(error){
        //failure
    })
}

promise有几种状态,什么时候会进入catch?

三个状态:pending、fulfilled、reject
两个过程:padding -> fulfilled、padding -> rejected
当pending为rejectd时,会进入catch

ES6诞生之前,异步编程的方法有:回调函数,事件的监听,发布/订阅,Promise对象。
异步:简单来说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好准备,再回过头执行第二段。

下面的输出结果是多少

const promise = new Promise((resolve, reject) => {
    console.log(2);
    resolve();
    console.log(333);
})
promise.then(() => {
    console.log(666);
})
console.log(888);

Promise 新建后立即执行,所以会先输出 2,333,而Promise.then()内部的代码在 当次 事件循环的 结尾 立刻执行 ,所以会继续输出888,最后输出666
使用结构赋值,实现两个变量的值的交换

let a = 1;let b = 2;
[a,b] = [b,a];

下面Set结构,打印出的size值是多少

let s = newSet();
s.add([1]);s.add([1]);
console.log(s.size);//2

两个数组[1]并不是同一个值,它们分别定义的数组,在内存中分别对应着不同的存储地址,因此并不是相同的值都能存储到Set结构中,所以size为2

Promise 中 reject 和 catch 处理上有什么区别

reject 是用来抛出异常,catch 是用来处理异常
reject 是 Promise 的方法,而 catch 是 Promise 实例的方法
reject后的东西,一定会进入then中的第二个回调,如果then中没有写第二个回调,则进入catch网络异常(比如断网),会直接进入catch而不会进入then的第二个回调

使用 class 手写一个 promise

  //创建一个Promise的类
  class Promise{
    constructor(executer){//构造函数constructor里面是个执行器
      this.status = 'pending';//默认的状态 pending
      this.value = undefined//成功的值默认undefined
      this.reason = undefined//失败的值默认undefined
      //状态只有在pending时候才能改变
      let resolveFn = value =>{
        //判断只有等待时才能resolve成功
        if(this.status == pending){
          this.status = 'resolve';
          this.value = value;
        }
      }
      //判断只有等待时才能reject失败
      let rejectFn = reason =>{
        if(this.status == pending){
          this.status = 'reject';
          this.reason = reason;
        }
      }    
      try{
        //把resolve和reject两个函数传给执行器executer
        executer(resolve,reject);
      }catch(e){
        reject(e);//失败的话进catch
      }
    }
    then(onFufilled,onReject){
      //如果状态成功调用onFufilled
      if(this.status = 'resolve'){
        onFufilled(this.value);
      }
      //如果状态失败调用onReject
      if(this.status = 'reject'){
        onReject(this.reason);
      }
    }
  }

如何使用 Set去重

let arr = [12,43,23,43,68,12];
let item = [...new Set(arr)];
console.log(item);//[12, 43, 23, 68]

下面for循环改成for of形式

let arr = [11,22,33,44,55];
let sum = 0;
for(let i=0;i<arr.length;i++){
    sum += arr[i];
}
答案:
let arr = [11,22,33,44,55];
let sum = 0;
for(value of arr){
    sum += value;
}

理解 async/await 以及对 Generator 的优势

async await 是用来解决异步的,async函数是Generator函数的语法糖
使用关键字async来表示,在函数内部使用 await 来表示异步
async函数返回一个 Promise 对象,可以使用then方法添加回调函数
当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句
async较Generator的优势:

  1. 内置执行器。Generator 函数的执行必须依靠执行器,而 Aysnc 函数自带执行器,调用方式跟普通函数的调用一样
  2. 更好的语义。async 和 await 相较于 * 和 yield 更加语义化
  3. 更广的适用性。yield命令后面只能是 Thunk 函数或 Promise对象,async函数的await后面可以是Promise也可以是原始类型的值
  4. 返回值是 Promise。async 函数返回的是 Promise 对象,比Generator函数返回的Iterator对象方便,可以直接使用 then() 方法进行调用

forEach、for in、for of三者区别

forEach更多的用来遍历数组
for in 一般常用来遍历对象或json
for of数组对象都可以遍历,遍历对象需要通过和Object.keys()
for in循环出的是key,for of循环出的是value

es6的导入导出模块:导入通过import关键字;导出通过export关键字

// 只导入一个
import {sum} from "./example.js"
// 导入多个
import {sum,multiply,time} from "./exportExample.js"
// 导入一整个模块
import * as example from "./exportExample.js"
//可以将export放在任何变量,函数或类声明的前面
export var firstName = 'Chen';
export var lastName = 'Sunny';
export var year = 1998;
//也可以使用大括号指定所要输出的一组变量
var firstName = 'Chen';
var lastName = 'Sunny';
var year = 1998;
export {firstName, lastName, year};
//使用export default时,对应的import语句不需要使用大括号
let bosh = function crs(){}
export default bosh;
import crc from 'crc';
//不使用export default时,对应的import语句需要使用大括号
let bosh = function crs(){}
export bosh;
import {crc} from 'crc';

讲述vue的MVVM模式的理解

MVVM 是Model-View-ViewModel的缩写,即将数据模型与数据表现层通过数据驱动进行分离,从而只需要关系数据模型的开发,而不需要考虑页面的表现,具体说来如下:

    1. Model代表数据模型:主要用于定义数据和操作的业务逻辑。
    2. View代表页面展示组件(即dom展现形式):负责将数据模型转化成UI 展现出来。
    3. ViewModel为model和view之间的桥梁:监听模型数据的改变和控制视图行为、处理用户交互。通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel
之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。

vue.js的两个核心是:数据驱动和组件化

vue双向数据绑定原理

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

具体步骤:

第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 ->视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

vue常用指令
指令

解释:指令 (Directives) 是带有 v- 前缀的特殊属性 作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

vue常用指令
数据绑定 绑定属性
循环渲染数据 数据渲染 显示隐藏
绑定数据表达式{{}}

<p>{{msg}}</p>

v-model 绑定表单元素值的 数据双向绑定

	  <p>
         <input type="text" v-model="msginfo">
      </p>
      <p>{{msginfo}}</p>

v-bind 绑定属性的 单向绑定

<p v-bind:title="title"></p>

v-bind绑定类名称, 如何一次绑定多个类

<p v-bind:class="{'red':true,'p1':true}">{{msg}}</p>

v-bind 绑定样式 style

<p v-bind:style="{'color':fontcolor}">
          我是灰太狼啊
        </p>
        <p v-bind:style="pstyle">
          我是灰太狼啊
        </p>

v-bind 简写 :title=""
v-html v-text 绑定元素的文本值
v-html 可以自动解析字符串标签
v-text 直接以文本显示

		<p v-html="phtml">
        </p>
        <p v-text="phtml">
        </p>
        <script>
	export default {
  		name: 'app',
  			data () {
    			return {
    			phtml:"<span>我是绑定的值</span>"
    			}
    			}
    			}

v-once 一次性数据绑定
v-for 数据的循环渲染

<!-- 
    循环渲染数据
    渲染谁给谁写
    key 不能重复
    集合的索引
  -->
  <ul>
    <li v-for="(item,index) in array1" :key="index">
      {{item+"/"+index}}
    </li>
  </ul>
  <ul>
    <li v-for="(item,index) in obj" :key="index">
      姓名:{{item.name}}性别:{{item.sex}}
      <span v-for="(a,b) in item.hobby" :key="b">
        {{a}}
      </span>
    </li>
  </ul>
  export default {
  		name: 'app',
  			data () {
    			return {
    			array1:[1,2,3,4,5,6,7],
      obj:[
        {
          name:"小灰灰",
          sex:"男",
          hobby:["玩游戏","捉迷藏"]
        },
        {
          name:"美羊羊",
          sex:"女",
          hobby:["化妆","学习","捉迷藏"]
        },
        {
          name:"喜羊羊",
          sex:"男",
          hobby:["跑步"]
        }
      ]
    			}
    			}
    			}

v-show v-hide 显示/隐藏

<p v-show="num==0?true:false">我是显示的</p>
   <p v-show="false">我是隐藏的</p>

条件渲染指令
v-if v-else v-else-if

 <p v-if="btn">
     我在看你
   </p>
   <p v-else-if="btn">
     我看你
   </p>
   <p v-else>
     我不看你
   </p>
   <!-- 
     条件渲染语句可以直接写给模板

    -->
    <template v-if="btn">
      <p>马上吃饭了</p>
    </template>

v-if 和 v-show
条件渲染
v-if:根据表达式的值的真假条件,销毁或重建元素
v-show:根据表达式之真假值,切换元素的 display CSS 属性

不同点:

 1 . v-if 当值为 true时,显示div ,
    当值为false时,改元素消失,代码也会消失,
    相当于将代码删除了,当在为true时,页面会重新渲染div; 
    支持加在<template>标签上
    而v-show 控制的隐藏出现,
	只是将css属性设为了display:none 或block;
   不支持加在<template>标签上
2.v-if 后还有 v-else 和 v-else-if 条件渲染,
这里需要注意的是v-else 必须紧跟 v-if 或v-else-if 
3.v-if是真真正正的条件渲染;然而他是惰性的,在初始值是false的时候,他就什么都不做,在为真的时候才会开始局部变异 相比之下v-show则是更简单一下,仅仅是css上的切换 所以,v-if有更高的切换消耗,而v-show有更高的初始渲染消耗;因此,如果是频繁切换,就用v-show;在条件很难改变,比如某个模块在用户a出显示,就用v-if

vue 事件 以及获取dom元素(虚拟)
v-on

v-on:事件类型 @事件类型
v-on:click=“事件的执行方法” changeStatus执行的方法可以不带括号
简写 @click
执行的方法如果有参数
事件的修饰符
.stop 阻止事件传播
.prevent 组件重载页面
.slef 阻止事件不从内部触发
.once 事件触发一次
冒泡:里向外 捕捉:外向里

<button v-on:click="changeStatus">显示隐藏</button>
    <div v-show="changeS" class="d1">
    </div>
    <ul class="menu">
    <li v-for="(item,index) in obj" :key="index" @click="getStuInfo(index)">
      姓名:{{item.name}}+性别:{{item.sex}}
      <span v-for="(a,b) in item.hobby" :key="b">
        {{a}}
      </span>
    </li>
  </ul>
  <div class="d1" @click.stop="stopEvent(1)">
    <div class="d3" @click.stop="stopEvent(2)">
    </div>
  </div>
  <!-- 事件.self 相当于事件的委托,当前的触发元素是自身的时候,才能执行当前事件的函数
 .capture 类似原型的js里面的事件的捕获,事件从外向里执行 -->
  <ul @click.self="ulEvent">
    <li>灰太狼抓喜洋洋</li>
  </ul>

事件的执行参数e event

<button @click="getEvent">获取Event</button> 
<input type="text" @keydown="getEvent" >

vue里面获取dom元素 refs获取虚拟dom e.target/e.srcElement

<p ref="xx">我在吃饭饭</p>
<button @click="getDom">获取dom元素</button>

vue 过滤器 类似过滤内容
(自定义过滤器)局部过滤和全局过滤

<!-- 
     过滤器的常规写法
    
    -->
    <p>{{array1 | mysort}}</p>
    <input type="text" v-model="textsex" >
    <p>{{sex | changeSex(textsex)}}</p>
    <!-- 
      v-for 换个方式写过滤器
     -->
    <p>
      <span v-for="(item,index) in forSort()" :key="index">
        {{item}}
      </span>
    </p>

上面代码的js和css:

<script>
export default {
  name: 'app',
  data () {
    return {
      msg:"第一次使用vue.js",
      msginfo:"你好,这里是毛豆新车网",
      title:"标题",
      classname:"red p1",
      fontcolor:"#ffee25",
      pstyle:{
        "color":"#ff00ff",
        "font-size":"20px"
      },
      phtml:"<span>我是绑定的值</span>",
      array1:[1,2,3,4,5,6,7],
      obj:[
        {
          name:"小灰灰",
          sex:"男",
          hobby:["玩游戏","捉迷藏"]
        },
        {
          name:"美羊羊",
          sex:"女",
          hobby:["化妆","学习","捉迷藏"]
        },
        {
          name:"喜羊羊",
          sex:"男",
          hobby:["跑步"]
        }
      ],
      num:0,
      num1:0,
      btn:true ,
      changeS:true,
      sex:["男","女","男","男","女","男","女","女"],
      textsex:"男"
    
    }
  },
  filters:{
    //这里是写过滤器
    //有很多钩子函数 对于不同的状态
    mysort(val){
      //过滤器里面的返回值
      //在返回之前对值进行过滤
      //val代表管道符前面的值

     // console.log(val);
     let [...array3]=[...val];
      array3.sort((a,b)=>{
        return b-a;
      })
      //console.log(array2);
      
      return array3
    },
    changeSex(val,args1){
      //过滤
      let arr=[];
      for( let key of val ){
        //console.log(key);
        if(key===args1){
          arr.push(key);
        }
      }
      return arr;
    }
  },
  mounted(){
  
  },
  methods:{
    //methods 区域 写当前组件的所有方法
    changeStatus(){
      //console.log(1);
      //写简单效果执行代码
      //修改当前组件data方法里面的变量值
      //console.log(this);
      this.changeS=!this.changeS;
      //console.log(this);//注意this指针的问题
    },
    getStuInfo(index){
      this.obj[index].sex="男";
      //console.log(this.obj[index]);
    },
    stopEvent(num){
      //console.log(num);
      
    },
    ulEvent(){
      //console.log("ul"); 
    },
    getEvent(e){
      //e和原生event一致
      //键盘事件的相关参数 e.target e.srcElement e.keyCode e.which e.key e.code
      //鼠标事件的相关参数 e.timeStamp 触发的事件间隔 e.clientX/e.clientY e.pageX/e.pageY e.target/e.srcElement
      //console.log(e);
      
    },
    getDom(e){
      //获取dom
      //console.log(this.$refs.xx);
      //获取执行事件的目标元素
      //console.log(e.target);
      //console.log(e.srcElement);

      //调用计算属性
      this.changeValue;
    },
    forSort(){
      //在方法里面变相去写过滤器
      //写的是对整个数据处理
      //array1console.log(array1);
      
      let array=[...this.array1];
      array.sort((a,b)=>(b-a));
      console.log(array);
      return array;
    }
  },
  computed:{
    changeValue(){
      this.obj.push({
          name:"暖羊羊",
          sex:"女",
          hobby:["化妆","学习","吃饭"]
        });
      //console.log(this.obj);
      this.num++;
      this.array1.push(10);
    }
  },
  //监听属性
  //监听谁? 监听值 对象
  watch: {
    //对象
     obj:{
      handler(newval,oldval){
        //console.log(newval,oldval);
        //检测值是一样的 监听里面只能知道变化的时间
      }

      
      
    },
    //监听的是值
    //newval新+oldval旧
    num(a,b){
      //console.log(a,b);
      
    },
    array1:{
      //数组也可以使用简单监听
      handler(newval,oldval){
       // console.log(newval,oldval);
        
      }
      
    }
  },
}
</script>

<style>
.red{
  color: red;
}
.p1{
  text-shadow:0 0 5px orange;
}
.d1{
  width: 200px;
  height: 200px;
  background:pink;
}
.menu>li:hover{
  color: orange;
}
.d3{
  width: 100px;
  height: 100px;
  background: blue;
}
</style>

main.js:

import Vue from 'vue'
import App from './App.vue'
//vue 的实例化对象
//el:关联的元素
//render 渲染
new Vue({
  el: '#app',
  render: h => h(App)
})
//全局过滤器
Vue.filter("",()=>{

})
//main文件是主入口文件

虚拟dom是什么?
Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。
简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。不同的框架对这三个属性的命名会有点差别。
对于虚拟DOM,咱们来看一个简单的实例,就是下图所示的这个,详细的阐述了模板 → 渲染函数 → 虚拟DOM树 → 真实DOM的一个过程
虚拟DOM在Vue.js主要做了两件事:

  1. 提供与真实DOM节点所对应的虚拟节点vnode
  2. 将虚拟节点vnode和旧虚拟节点oldVnode进行对比,然后更新视图

虚拟dom的好处:

具备跨平台的优势
操作 DOM 慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。
提升渲染性能:Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值