1. 用过canvas吗,描述一下;和svg的区别
-
canvas基础知识
<canvas id="mycanvas" width="150" height="150"></canvas> // canvas标签只有width和height两个属性,不设置的话默认300*150
给canvas设置宽高要用width、height属性,而不是css,否则图形会变形,(css中设置宽高,不是讲修改画布宽高,而是将300*150的画布拉伸了)
// index.js let painting = () => { let drawing = document.getElementById('canvas'); if(drawing.getContext) { let pen= drawing.getContext('2d'); // 声明画笔 pen.moveTo(10, 10); // 起点 pen.lineTo(200, 100); // 终点 pen.lineWidth = 2; // 笔触宽度 pen.strokeStyle = '#098766'; // 绘制 pen.stroke(); } } painting();
-
canvas应用–绘制图片
// 平铺图片 let pattenImg = () => { let patcanvas = document.getElementById('imgcan'); let img = document.createElement('img') img.src = './img/pattenimg.jpeg' // 获取到图片 if(patcanvas.getContext) { let patctx = patcanvas.getContext('2d'); let pat = patctx.createPattern(img, 'repeat') // 创建图片pattern patctx.rect(0,0,1000,500); // 画一个矩形 patctx.fillStyle=pat; // 用图片pattern来设置填充样式 patctx.fill(); // 填充 // patctx.drawImage(img, 200, 200); // 这个是单纯的画一张图片 } } pattenImg();
-
canvas和svg的区别
svg生成的每一个图形都是独立的元素,是矢量图可以放大缩小不失真
canvas生成的是一个整体的画布,是位图,会失真
2. 图片上传到服务器、文件上传到服务器
ajax formdata上传
https://blog.csdn.net/lijia_1983370657/article/details/80489979
- 转成base64后再上传:
H5新特性 readAsDataURL 可以将文件转base64格式
3. http跨域
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
解决:
- PHP端修改header(XHR2方式)
在php接口脚本中加入以下两句即可:
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式 - 代理:例如www.xxx.com/index.html需要调用www.xxx.com/server.php,可以写一个接口www.xxx.com/server.php,由这个接口在后端去调用www.xxx.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题
4. promise和async、await的区别
都是异步编程的解决办法,都是非阻塞式的
async是基于promise实现的,用async声明的函数返回一个隐式promise,但是async解决了Promise的then链式回调繁琐问题,使代码更简洁易懂,减少中间变量。
5. 深浅拷贝
https://www.cnblogs.com/secretAngel/p/10188716.html
- js的数据类型分为
基本数据类型:Number, String, Boolean, Null, Undefined
引用数据类型(对象数据)深拷贝和浅拷贝只是针对于引用数据类型(Object, Array)
基本数据类型直接存放在stack中,而引用数据类型是存放在堆内存heap中,变量是保存在栈内存中一个指向堆内存中对象内容的指针(引用地址)
浅拷贝:
在定义一个对象或数组时,变量存放的只是一个地址。当我们使用对象拷贝时,传递的只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。
深拷贝:
不希望父子对象之间产生关联,既然属性值类型是数组和或象时只会传址,那么我们就用递归来解决这个问题,把父对象中所有属于对象的属性类型都遍历赋给子对象即可。
深拷贝的方法:
-
递归
let deepCopy = (origin) => { let result = Array.isArray(origin) ? [] : {} for(item in origin) { if(typeof(origin[item]) == 'object') { result[item] = deepCopy(origin[item]) }else{ result[item] = origin[item] console.log(origin[item]) } } return result }
-
[…arr]和Array.from() 第一层是深拷贝,但如果arr中有子数组,那么就只是浅拷贝。
-
Object.assign(目标对象,被拷贝对象)对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
-
JSON.stringify() + JSON.parse() 深拷贝
6. addeventlistener和onclick的区别
- onclick只能指向一个function,多次指向只会执行最后一个,前面的均被覆盖掉。
- addeventlistener可以多次绑定事件,而不会覆盖之前绑定的处理程序并且按照顺序执行。另外,支持控制listener的触发阶段(捕获/冒泡),两个阶段都是通过addEventListener最后一个参数设置为false(默认值,表示事件冒泡)或者true(表示事件捕获)来切换
7. js中获取元素的几种方式
- document.getElementById(‘id’); // 返回一个元素/null
- document.getElementsByClassName(‘classname’); // 返回HTMLCollection/HTMLCollection [ ]
- documnet.getElementsByTagName(‘tagname’); // 同classname
HTML Collection动态对象是类数组对象,可以用数字下标取元素,但不可以用数组的方法(foreach)。
- document.getElementsByName(‘name’); // 同classname
- document.querySelector(’.classname’); // 选择器,返回第一个符合的元素/null
- document.querySelectorAll(’.classname’); // 选择器,返回NodeList []
- document.documentElement; // 返回HTML标签
- document.body; // 返回body标签
8. 日历组件的实现
9. vuex
storage、mutation(唯一可以改变状态的方法)
- vuex存的是状态,存在内存中,用于组件间传值,刷新存储值丢失
- 本地存储(localstorage、sessionstorage)存的本地文件,存在本地缓存中,主要用于页面间传值,刷新存储值不丢失
10. css的滤镜功能
filter 对图片的处理效果,例如灰度(greyscale),模糊(blur),饱和,老照片
https://www.cnblogs.com/mmzuo-798/p/6237010.html
11. es6
const\let
() => {}
for … in 遍历对象的属性
class
12. 权限管理
通过导航守卫做权限管理(全局 beforeEach,组件内 beforeRouteEnter)
methods: {
onSubmit() {
this.$axois.post('/api/users', {
name: this.name,
pwd: this.pwd
}).then(res => {
if(res.data.state === 0) {
console.log('success');
let token = res.data.token
localStorage.setItem('token',JSON.stringify(token))
localStorage.setItem('role',JSON.stringify('xxadmin'))
this.$router.posh('/home');
}else{...}
})
}
},
beforeRouteEnter (to, from, next) {
// 不能用this,需要单独重新引入axois
axois.get('/api/users').then(
res => {
if(res.data.status === 0) { // loged
next(
vm => {
vm.$store.commit('自定义mutation', {
name: res.data.data.name
})
}
)
}
}
)
}
13. 上传文件
<template>
<div>
<input type="text" v-model="loginForm.username" placeholder="用户名"/>
<input type="text" v-model="loginForm.password" placeholder="密码"/>
<button @click="login">登录</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
data () {
return {
loginForm: {
username: '',
password: ''
}
};
},
methods: {
...mapMutations(['changeLogin']),
login () {
let _this = this;
if (this.loginForm.username === '' || this.loginForm.password === '') {
alert('账号或密码不能为空');
} else {
this.axios({
method: 'post',
url: '/user/login',
data: _this.loginForm
}).then(res => {
console.log(res.data);
_this.userToken = 'Bearer ' + res.data.data.body.token;
// 将用户token保存到vuex中
_this.changeLogin({ Authorization: _this.userToken });
_this.$router.push('/home');
alert('登陆成功');
}).catch(error => {
alert('账号或密码错误');
console.log(error);
});
}
}
}
};
</script>
算法:
-
数组去重
// 方法一 let eee = [ 2, 3, 'ss', 4, 2, 'ss'] let unique = (originalArr) => { let temp = [] originalArr.forEach((item,index) => { if(temp.indexOf(item) === -1) { temp.push(item) } }) return temp } console.log(unique(eee)) // 方法二 let uniqueArr = [...new Set(originalArr)]; console.log(uniqueArr);
-
快速创建1-100的数组:
console.log(Array.from(Array(100), (v,k) => k+1));
-
排序
快速排序的复杂度和原理
归并排序
二分排序
答案都是自己整理的,有错误的话欢迎指出