web前端面试题
1.src和href的区别 ?
href:
Hypertext Reference的缩写,超文本引用,多数用于a link 标签 看下图 加载他们的时候 不会停止对当前页面的加载 浏览器会向下加载
<a href="http://www.baidu.com"></a>
<link type="text/css" rel="stylesheet" href="common.css">
如果遇到link标签时会识别link是css 并下载当前css文档 不会停止当前页面的后续加载
src:
source的缩写 表示的是引用资源 他指向的内容会嵌套在当前标签里 因此浏览器解析src的时候会停止后续加载的处理 直到当前src资源加载完毕 通常我们把js放在页面底部进行加载 因为放在头部加载页面可能会导致元素渲染 如果放在了头部 可以使用 onload事件 解决
<img src="img/girl.jpg">
<script src="show.js">
总结:
href用于建立当前页面和引用资源的关系(链接) 而src会替换当前标签 遇到href 页面会继续向下加载后续内容 而遇到src不同 浏览器会加载完src 后才会向下执行
2.页面元素隐藏方式 和各自特点?
有以下三种方式实现页面元素隐藏
1.display:none
不占据空间 更改时Dom树不会创建元素 元素显示 display:block
2.visibility:hidden
元素隐藏 占据空间 更改时Dom树存在该元素 不会被销毁 元素显示 visibiliity:visible
3.opcity:0
元素隐藏 占据空间 更改时Dom树存在该元素 不会被销毁 元素显示 opcity:1
3.用过哪些盒模型,以及他们各自的区别?
box-sizing:content-box; 表示w3c标准盒模型 默认值 盒子定义内容宽高 包括内外边距 border 内容部分不包括其他部分
box-sizing:border-box; 表示IE盒模型 盒子定义宽高 等于 内容宽高 + (border) 边框+ (padding) 内边距
区别:设置css宽高时 IE盒模型宽高会包括内边距 而 w3c盒子模型不会
4.谈谈你的移动端适配方案有哪些?
百分比方案
实现原理:使用百分比定义宽度 高度需要用px 固定 根据可视化窗口发生调整 发生改变
优势: 原理简单,不存在兼容问题
缺点:如果屏幕尺寸差距太大 相对于设计稿过大或者过小的手机屏幕 可能不会显示 或者 元素拉伸变形 字体无法随着屏幕大小随之改变
rem方案
实现原理:rem是相对长度单位 rem方案根据 根元素的font-size 的大小计算值的倍数 根据屏幕宽度设置的 font-size 在布局时使用rem单位 来达到自适应的目的 是弹性布局的一种方式
优势:
兼容性好 ios6.1系统以上都支持
android: 2.1系统以上都支持
大部分主流浏览器都支持
相对于静态布局和百分不布局页面不会被拉伸变形 自适应效果更好
不足:不是纯css移动端适配方案 需要引用js 时刻监听可视化窗口的改变 来改变根元素的字体大小
vw/vh 方案
原理
可视化窗口是浏览器中呈现网页的区域 , 移动端的视口指的是布局视口
1vw = 等于视口宽度 1% 1vh = 等于视口高度 1%
优势:纯css 移动端布局方案
不足:android4.4以下不支持
媒体查询标签响应式方案
原理: 通过媒体查询标签设置不同尺寸分辨率所相应的样式
优势:能够在不同设备 , 不同分辨率上显示合理布局,不仅仅是样式变换
不足:要匹配足够多的设备尺寸 一个页面需要多个尺寸方案 ,如果页面不匹配个别尺寸页面会发生显著变化
5. js 数据类型有几种?它们之间的区别是什么
js中分为两种数据类型 分为基本数据类型和引用数据类型
首先我们先了解一下堆栈内存
堆栈内存就是在计算机中内存分配的一快空间,用于执行和储存代码 ,一个是堆内存 ,一个是栈内存
什么是堆栈内存
- 堆内存 储存引用数据类型的值
- 栈内存 储存基本数据类型的值
看以下代码 基本数据类型例子
let a = 12;
let b = a;
b = 13;
console.log(a);
//结果打印为12
可以把栈内存理解为为两个文件夹 为堆内存和栈内存的文件夹
栈内存文件夹中 有两个文件 分别为a文件和b文件 同时b文件复制了a文件里的数据,b文件重新修改数据,a文件里数据还是原本数据
再来看一下 引用数据类型的例子
let n = {
name:'li'
};
let m = n;
m.name = 'ming';
console.log(n.name);
//打印结果为ming
简单理解: 可以比喻n变量有一杯水 m变量借了n的一杯水 喝了一半, 然后n的水只剩下一半;
堆栈内存他们之间的区别是什么
- 基本数据类型:操作的是值,并且值存储在栈内存中
- 因为操作的是值 重新赋值时操作的也是当前变量在内存中的值 每个变量的值都是唯一的
- 引用数据类型:操作的是堆内存的引用地址,并且会把对象中的键值对放在堆内存中
- 发生重新赋值操作时 操作的是堆内存中的地址 所以会找到原变量 发生修改
6.数据类型强制转化和隐式转化的分别怎么使用?
强制类型转换
- 就是指将一个数据类型强制转换为其他数据类型
类型转换主要指,将其他的数据类型。转换为String、Number、Boolean
1.转换为String
- 调用String()函数,并将被装换的数据作为参数传递给函数;
- 该方法不会影响原变量,它会将转换结果返回;
- 使用String()函数做强制类型转换时,null和undefined这两个值可以转换为String;对于Number Boolean 而是直接转换成“null”、“undefined”;
var a = 123
var b = true
var c = null
var d = undefined
String(a) // "123"
String(d) // "true"
String(c) // "null"
String(d) // "undefined"
2.转换为Number
- 如果是纯数字的字符串,直接转换为数字;
- 如果字符串中有非数字的内容或者是undefined,则转换成NaN
- 如果字符串是空串或者空格,则转换成0
- 如果是布尔值;true转换为1,false转换为0;
- 如果是Null,转换为0
var a = "123"
var b = "12as"
var c = " "
var d = undefined
var e = true
var f = Null
Number(a) // 123
Number(d) // NaN
Number(c) // 0
Number(d) // NaN
Number(e) // 1
Number(f) // 0
parseInt() / parseFloat()
parseInt()
parseInt() 强制转换整型
parseInt()转换规则:从左往右依次读取,把有效的整数内容取出来,遇到第一个非数字 内容就停止读取,如果第一个字符就是非数字则转换为NaN;
var a = '123ass'
var b = as123
parseInt(a) // 123
parseInt(b) // NaN
parseFloat()
parseFloat() 把一个字符串转换为一个浮点数,和parseInt()类似,不同的是可以获取有效的一个小数;
var a = '123.123.12'
var b = as123.12
parseFloat(a) // 123.123
parseFloat(b) // NaN
parseInt()或parseFloat(),对非String使用,它会先将其转换为String,然后 再操作
3转换为Boolean
Boolean()
- 数字转布尔值,除了0和NaN都是true
- 字符串转为布尔值,除了空串都是true
- null和undefined转换为布尔值,都是false
- 对象也会转换为true
隐式类型转换
转换为String
var a = 123
a = a + "" // "123"
console.log(typeof a) // "string"
算法运算符(+), 任何值和字符串做 + 时,都会先转换为字符串,然后再和字符串做拼串操作;多个值 + 时 ,从左向右运算,注意数值类型;
可以利用这一特点,来将任意数据类型转换为String,只需(任意字符串 + “”)即可转换为String;这是一种隐式类型转换,由浏览器自动完成,实际上也是调用了String()函数;
转换为Number
var a = "123"
a = a - 0 // 123
a = a * 1
a = a / 1
console.log(typeof a) // "number"
算法运算符(- * / %),任何值做 - * /,都会将其转换为Number,再做运算;可以利用这一特点,来将任意数据类型转换为Number,只需(任意字符串 - 0)(任意字符串 * 1)(任意字符串 / 1)即可转换为Number,这是一种隐式类型转换,由浏览器自动完成,实际上也是调用了Number()函数;
转换为Boolean
逻辑计算符(!非),! 对一个布尔值做取反运算;如果对非布尔值取反,则会将其转换为布尔值,再取反;可以利用其特点,将其他数据类型取两次反,转换为布尔值;原理和Boolean()一样;
var a = "123"
a = !!a // true
console.log(typeof a) // "Boolean"
7.let const 和 var 的区别 ?
var
- 支持全局、函数作用域
- 接受重复声明
- 存在变量提升
let
- 不接受重复声明
- 不存在变量提升
- 支持块作用域(es6新提出的概念)
const
- const 声明变量无法重新赋值
- 存在暂时性死区,不存在变量声明提前,不允许重复定义
- 用来声明常量,一旦声明不能更改
8.箭头函数和普通函数的区别 ?
箭头函数
- 箭头函数时匿名函数 , 不能作为构造函数 ,不能使用new.
- 箭头函数中的this指向不同 this指向他的上级代码快获取当做本身this
- 箭头函数不能Generator函数,不能使用yeild关键字。
- 箭头函数不具有prototype原型对象。
- 箭头函数不具有super。
- 箭头函数不具有new.target。
普通函数
- this 指向的是当前事件对象
9.解释什么叫回调地狱 以及怎么解决回调地狱 ?
我们在了解回调地狱之前我们先了解两个概念
回调函数
当一个函数作为参数传入另一个参数中,并且它不会立即执行, 只有当满足一定条件后该函数才可以执行函数 我们熟悉的定时器 和 ajax中 就有回回调函数,
setTimeout(function(){
console.log("执行了回调函数")
},2000)
这里的回调函数是当定时器执行完成后调用函数
异步任务
与之相对应的概念是“同步任务”,同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。异步任务不进入主线程,而是进入异步队列,前一个任务是否执行完毕不影响下一个任务的执行
回调地狱是什么
setTimeout(function () {
console.log('一');
setTimeout(function () { /
console.log('二');
setTimeout(function () {
console.log('三');
}, 1000)
}, 2000)
}, 3000)
代码中回调函数嵌套回调函数 ,这种情况就叫做回调地狱
如何解决回调地狱
Promise
- Promise是js中的一个原生对象,是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案。
- Promise构造函数接收一个函数作为参数,我们需要处理的异步任务就卸载该函数体内,该函数的两个参数是resolve,reject。异步任务执行成功时调用resolve函数返回结果,反之调用reject。
- Promise对象的then方法用来接收处理成功时响应的数据,catch方法用来接收处理失败时相应的数据。
- Promise的链式编程可以保证代码的执行顺序,前提是每一次在than做完处理后,一定要return一个Promise对象,这样才能在下一次than时接收到数据。
function fn(str){
var p=new Promise(function(resolve,reject){
//处理异步任务
var flag=true;
setTimeout(function(){
if(flag){
resolve(str)
}
else{
reject('操作失败')
}
})
})
return p;
}
fn('1')
.then((data)=>{
console.log(data);
return fn('2');
})
.then((data)=>{
console.log(data);
return fn('3')
})
.then((data)=>{
console.log(data);
})
.catch((data)=>{
console.log(data);
})
async/await
首先我们看async关键字,他作为一个关键字放到声明函数前面,表示该函数为一个异步任务,不会阻塞后面函数的执行:
async function fn(){
return 'aaa';
}
console.log(fn());
打印结果为 Promise{:“aaa”}
可以看到async函数返回数据时自动封装为一个Pormise对象
和Promise对象一样, 处理异步任务时也可以按照成功和失败来返回不同的数据 , 处理成功时用then 方法来接收失败用catch方法来接收
async function fn() {
var flag = true;
if (flag) {
return '不讲武德';
}
else{
throw '处理失败'
}
}
fn()
.then(data=>{
console.log(data);
})
.catch(data=>{
console.log(data);
})
console.log('先执行我,表明async声明的函数是异步的');
async关键字说完了,我们看看awai关键字
- await关键字只能在使用async定义的函数中使用
- await后面可以直接跟一个 Promise实例对象(可以跟任何表达式,更多的是跟一个返回Promise对象的表达式)
- await函数不能单独使用
- await可以直接拿到Promise中resolve中的数据。
//封装一个返回promise的异步任务
function fn(str) {
var p = new Promise(function (resolve, reject) {
var flag = true;
setTimeout(function () {
if (flag) {
resolve(str)
} else {
reject('处理失败')
}
})
})
return p;
}
//封装一个执行上述异步任务的async函数
async function test(){
var res1=await fn('武林要以和为贵'); //await直接拿到fn()返回的promise的数据,并且赋值给res
var res2=await fn('要讲武德');
var res3=await fn('不要搞窝里斗');
console.log(res1,res2,res3);
}
//执行函数
test();
为什么叫await等待呢,因为当代码执行到async函数中的await时,代码就在此处等待不继续往下执行,直到await拿到Promise对象中resolve的数据,才继续往下执行,这样就保证了代码的执行顺序,而且使异步代码看起来更像同步代码。
总结
当我们写代码遇到异步回调时 ,我们想让异步代码按照我们想要的方式执行 , 如果按照传统的嵌套方式 ,就会出现回调地狱,这样的代码不利于维护,我们可以通过promise对象进行解决
10.说明原生ajax的实现步骤?
1.创建ajax对象
var xhr = new XMLHttpRequest();
2.绑定事件
xmlHttp.onreadystatechange(function(){
//获取服务器端返回的数据,更新dom
if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
var data = xmlHttp.responseText; //responseText为服务器返回的数据
//alert(data);
document.getElementById("id").innerText = data;
}
})
3.初始化请求参数
xmlHttp.open(method,url,async);
//参数method为请求方式,取值为post/get
//参数url为请求地址
//参数async设定是否为异步请求,async默认为true
get请求:
xmlhttp.open("GET","demo_get2.asp?fname=Bill&lname=Gates",true);
post请求:
xmlhttp.open("POST","demo_post.asp",true);
4.发送请求
xmlHttp.send(); //发送请求
11.什么情况下会导致跨域?
因为同源策略限制,不同源会造成跨域;
同源策略:所谓同源是指:协议,域名,端口均相同。即便两个不同的域名指向同一个ip地址,也非同源。
12.vue 有几个生命周期 以及各个生命周期的调用时机 ?
beforeCreate()
创造之前,此时数据data和事件方法methods还未绑定到app对象上
created():
创造,数据data和方法methods绑定到应用对象app上
beforeMount():
挂载之前,渲染之前,根据数据生成的DOM对象是获取不到的
mounted():
挂载,渲染之后,可以获取数据生成的DOM对象
beforeUpdate():
当data被修改时,数据更改,但内容未更改之前
updated():
data数据更改时,内容更改后
beforeDestroy():
应用销毁之前
destroyed():
应用销毁之后
图解
13. 使用vue中的v-for时,为什么要绑定 :key? 如果不绑定会有什么效果?
如果不绑定:key,则每删除数组中一个元素,v-for都会先删除所有元素副本,再重新建整个列表——修改效率低。
添加事件时,会造成下标一致,类似于 for循环中添加事件 单击一个元素 其他元素都会发生相应
绑定:key是给每个元素副本添加一个唯一的标识,在删除数组元素时,可根据唯一标识找到对应的一个元素对象,删除即可,其它元素不受影响——修改效率高.
添加事件时,标识了每个元素都是单一的 解决了添加事件时下标一致的作用
14.v-show 和 v-if 的作用和区别, v-bind 和 v-model的作用和区别?
v-show
无论v-show的值为true或者false,元素都会存在于html页面中
v-if
而v-if的值为true时,元素才会存在于html页面中,
区别:
v-if是动态地向DOM树内添加或者删除DOM元素,v-show是通过设置DOM元素的display样式属性控制显隐的
v-bind 单向绑定数据
向视图发送数据改变 数据发生改变时 视图就会发生改变
v-model
而v-model绑定的数据,页面数据的改变,vue对象中的数据也会跟着改变,视图影响数据, 数据影响视图
区别:
v-bind 数据改变影响视图
v- model 数据影响视图 ,视图影响数据
15.vue 组件通信如何实现,至少列举3种方式并说明各自的局限性?
props/$emit 父子组件通讯
使用方法:props通信方式是大家常见的通信类型,也是父子组件通讯的常用方式,用法是直接在子组件标签中绑定属性和方法。用props拿到声明的属性。对于父组件的方法,可以通过this.$emit触发。(事件名,数据)
优点:
props传递数据的优点显而易见、灵活简单,可以对props数据进行数据计算、数据监听等处理,十分灵活方便,但这里单单只是父子一层。
缺点
对于父组件–子组件–子组件–子组件这种跨层级的通信,显然需要我们一层一层的props绑定属性和方法,如果遇到更复杂的情况,实现起来比较困难
vuex(状态管理模式)
使用方法:
state => 基本数据
getters => 从基本数据派生的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
优点
根本解决复杂组件的通信问题
vuex在一定程度上根本解决了vue复杂的组件通信情况,我们不再关心两个毫无干系的两个组件的通信问题。
支持异步组件通信
vuex中actions允许我们做一些异步操作,然后通过commit可以把数据传入对应的mutation,至于actions为什么可以执行异步,是因为里面底层通过Promise.resolve能够获取异步任务完成的状态。
** 缺点**
流程相比稍微复杂
vuex通信方式相比其他方式,比较复杂,而且如果不同的模块,需要建立独立的modules。
16.详细说明vue组件中 data ,computed 和 watch的区别?
首先先说明vue 中 data computed watch都是什么
data
Vue中的data属性专门用来以对象方式存放数据,计算定义的属性会随它的赋值变量的变化而变化
computed
计算属性允许我们对指定的视图,复杂的值计算。这些值将绑定到依赖项值,只在需要时更新。计算属性需要用return 返回 有缓存机制
watch:
侦听属性 不支持缓存 当监听属性改变时会触发区间的代码
data 和 computed 的 区别
先一言以蔽之,data 和 computed 最核心的区别在于 data 中的属性并不会随赋值变量的改动而改动,而computed 会。(赋值变量类似:num: aaa.bbb,直接赋值是 num: 123)。下面有两个例子来佐证。
一个例子
<div id="app">
<h2>num1是data中的变量,其初始值为:{{num1}}</h2>
<h2>点击按钮后,data中的num1变化为:{{num1}}</h2>
<h2>点击按钮后,computed中的c_num1变化为:{{c_num}}</h2>
<button @click="outerNumChange">给num1+10</button>
<hr>
<h1>1.data定义的属性不会因为它的赋值变量的变化而变化</h1>
<h1>2.computed定义的属性会随它的赋值变量的变化而变化</h1>
</div>
<script>
let outer_obj = {num: 30}
let app = new Vue({
el: "#app",
data: {
temp: outer_obj, // 这一句一定要加,必须在 data 对象上存在才能让 Vue 将它转换为响应式的,见下图官方文档
num1: outer_obj.num
},
computed: {
c_num () {
return outer_obj.num
}
},
methods: {
outerNumChange () {
outer_obj.num += 10
}
},
})
</script>
watch 和 compted的区别
watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象,但是我们不能类似这样监控
看一个例子
watch:{
goodsList.price(newVal,oldVal){
//监控商品列表中是商品价格
}
这样会报错。只能监控整个对象或单个变量
watch一般用于监控路由、input输入框的值特殊处理等等,它比较适合的场景是一个数据影响多个数据
compted的理解
computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化,举例:购物车里面的商品列表和总金额之间的关系,只要商品列表里面的商品数量发生变化,或减少或增多或删除商品,总金额都应该发生变化。这里的这个总金额使用computed属性来进行计算是最好的选择
17.keep-alive的作用是什么? 使用它的目的是什么?
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
18.vue-router的作用是什么? 为什么不使用a标签?
vue.router的作用是:
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。
vue-router实现原理
SPA(single page application):单一页面应用程序,只有一个完整的页面;它在加载页面时,不会加载整个页面,而是只更新某个指定的容器中内容。单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面
W3C中是这样解释a标签的:
从一张页面跳转到另一张页面,但从这里来说就违背了多视图的单页Web应用这个概念
通过a标签进行跳转,页面会被重新渲染,即相当于重新打开一个新的网页,体现为视觉上的“闪烁”(如果是本地的项目基本看不出来)
总结:
对比a标签,router-link组件避免了不必要的重渲染,它只更新变化的部分从而减少DOM性能消耗
19.vuex 是什么? 怎么使用?为什么用使用它?
什么是vuex
Vuex是一个专为vue.js应用程序开发的状态管理模式。它解决了组件之间同一状态的共享问题。因为它采用的是集中式存储管理应用的所有组件状态,所以组件就可以和store通讯了。其实Vuex就是用来管理组件之间通信的一个插件
为什么需要vuex
当多个组件依赖于同一个状态时,由于多层嵌套使得传参的方法变得复杂,另外如果使用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝,会使得该模式变得脆弱,从而无法维护代码。从而需要使用Vuex来解决这个问题。
使用方法
首先我们先来看有几个属性
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
name:'',
//state 用来存储数据
//公共状态数据
},
getters:{
},
mutations:{
set(state,value){
state.name = value
},
//用来放同步函数 用来修改state状态值
//state 参数时当前state对象 value 是调用函数传递过来的值
},
actions:{
//用于存放异步函数,
set({
commit
//调用方法的对象 用于修改数据
}) {
//请求ajax异步方法
axios.get(请求地址).then(res => {
commit("setCity", res.data)
})
}
}
})
date
用于存放公共数据
mutation
mutation必须是同步操作数据方式
用于修改state公用数据
Action
Action可以进行一些异步的操作,然后再去触发mutation,所以与后端的一些接口都必须放在action里面
getters
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算
getters:{
//设置函数名
get (state){
return state.list;
//当state下的list 发生改变时return 返回
//在用到state直接获取的地方,用getters的方式获取
//可以使用this.$store.getters.get 直接获取
}
}
moudles
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割,每个状态集最后合成到一个总的store中
constmoduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: {... } }
const moduleB = { state: { ... },mutations: { ... }, actions: { ... } }
const store = new Vuex.Store({ modules: {a: moduleA, b: moduleB } })
20.请谈一下你对 使用原生js开发和 使用vue开发的看法。
控件跟数据自动绑定,可以直接使用data里面的数据值来提交表单,而不需要再使用$("#myid").val()那一套方法来获取控件的值,对控件赋值也方便很多,只需要改变data的值,控件就会自动改变值。将复杂的界面操作,转化为对数据进行操作。
比如下面的一段代码就可以很简单的实现了select控件的里面的列表的动态管理:
html代码:
<el-select v-model="mType" style="flex: 1;">
<el-option v-for="(item,index) in enums" :label="item.label" :value="item.value" :key="index"></el-option>
</el-select>
js代码:
data(){
return{
mType:'',
enums:[{value:0,label:'正常'},{value:1,label:'拉黑'}]
}
}
二、页面参数传递和页面状态管理。
页面传值对于vue来说,可供选择的方法非常多。比如使用子组件实现,通过对props属性传值;也可以使用页面url参数的方法传值;或使用vuex全局状态管理的方法页面传值等等。而原生开发的时候,在页面有多个参数的时候,页面传值和初始化,要复杂很多。而vue直接将参数保存在对象里面,直接给子组件的属性或vuex存储一个对象就行了,比如 , 这样就可以将userinfo传到自定义组件。
三、模块化开发、无刷新保留场景参数更新
比如一个列表页面里面有添加功能,有修改功能,这时候我们可以通过引用子组件的形式,当子组件内容更新的时候,修改主组件的数据,比如修改了一条数据后,我们需要列表页同时刷新,但我们不希望改变原来列表页的页码和搜索条件。假如你用原生开发来实现这个,需要写很多业务逻辑保存上一个页面的搜索条件和页码这些参数,但假如你用vue开发,将变得非常简单。
四、代码的可阅读性
vue天生具有组件化开发的能力,因此不同的功能基本都是写在不同的模块里面,因此代码的可阅读性非常高。当一个新手接手一个旧项目的时候,基本上可以做到一天就能定位到要修改的代码,进行修改,快速接手项目。
基于强大的nodejs,添加新的组件库,基本一句npm命令就能安装,比如当我需要使用axios组件的时候,直接npm install axios安装一下,就可以使用axios这个组件。熟悉maven的同学估计很容易就能理解npm工具。
主路由、子路由、主页面、子组件的方式,可以让我们彻底抛弃iframe。写过前端的同学都知道,因为iframe的滚动条、和子页面跟其他页面的交互性这些原因、用户体验还是远远没有单页面架构友好。而且使用vue非常简单方便的实现系统菜单、导航等固定布局。
各子组件样式不冲突:各个组件之间,可以使用相同的样式名,但有不同的样式属性。比如组件A和组件B的button都绑定了class=“btn”, 但在两个组件里,我们可以实现两个不同的btn样式属性,互不影响。
vue的不足:
当然,vue也有不足,不足的地方如下:
vue是单页面页面,对于搜索引擎不友好,影响seo.因此不适合做公司官网。比如两个vue路由(页面),它的路径是这样的:index.html#aaa 和 index.html#bbb,但对于搜索引擎来说,都是同一个页面,就是index.html。这样搜索引擎就无法收录你的页面。
vue门槛较高,使用vue,需要先学习和摸索vue大概3天左右的时候,建议使用vue的时候,不需要看node.js自动帮你生成的js文件。你只需要编写你自己页面的代码就行了。具体nodejs帮你生成的框架代码,其实是不用看的。
在写一些小项目 和demo时简单时框架里的大部分代码是无用的,相比较原生js会不方便
原生js开发
优点
写一些自己的小案例可以使用原生js,更有针对性,没有多余的代码
缺点
是如果经验不足的话代码的兼容性和扩展能力较差,代码抽象的层次较低,要想做好的话需要经验和大量的时间和精力