日常疑问积累
目录
- js
1.1 如何理解事件委托?
1.2 高阶函数 - 公众号
2.1 公众号开发时,接口没有用/api开头却可以实现代理?
2.2 canvas微信拍照 - vue
3.1 如何实现监听对象中一个属性的变化?
3.2 如何实现路由懒加载?
3.3 如何实现路由嵌套?
3.4 如何实现路由拦截?
3.5 在单个vue文件实现流程切换,并做监听回退
3.6 项目如果重构你会选择重构哪些地方?重构的方法以及必要性?
3.7 vuex的用法,vuex和bus总线的区别
3.8 vue的响应式原理,以及get set分别做了什么 - ajax
4.1 对ajax的理解? 编写用ajax发生GET、POST请求
4.2 如何将后台返回的文件流转为excel? 并且不乱码 - 小程序
5.1 小程序为啥不能用window
5.2 bug:textarea与原生下拉框重叠
5.3 小程序文本可复制
5.4 实现分享到朋友圈
5.5 人脸识别 --wx.startFacialRecognitionVerify(OBJECT)
5.6 小程序内跳转至其他小程序 --wx.navigateToMiniProgram(Object object)
5.7 长按识别二维码
5.8 实现服务通知 --requestSubscribeMessage
5.9 base64转临时url
5.10 删除对象属性 --delete Object.属性
1 js
1. 如何理解事件委托?
- var currentTarget = e.target || e.srcElement;
*事件委托就是利用事件冒泡的原理,将事件绑定在父级元素身上。利用事件委托,可以给尚未存在的标签绑定事件。
goto(e) {
let currentTarget = e.target || e.srcElement;
let index = currentTarget.getAttribute("data-index");
if(index === 'userManage' || index === 'applyManage') {
this.$router.push({
path: `/userCenter/${index}`
})
if(index === 'userManage') {
this.userManageFlag = true;
this.applyManageFlag = false;
this.userMain = '用户管理';
} else if(index === 'applyManage') {
this.applyManageFlag = true;
this.userManageFlag = false;
this.userMain = '应用管理';
}
}
}
2. 高阶函数
- 接收函数作为参数或者返回函数的函数
/**
* 检验规则
* 大于18岁
* 密码长度大于8
* 统一用户协议
* */
const newUser = {
age: 24,
password: 'some long password',
agreeToTerms: true
}
function oldEnough(user) {
return user.age >= 18;
}
function passwordLongEnough(user) {
return user.password.length >= 8;
}
function agreeToTerms(user) {
return user.agreeToTerms === true;
}
// 高阶函数 --> 一次性完成所有验证
function validate(obj, ...tests) {
for(let i = 0; i < tests.length; i++) {
if(tests[i](obj) === false) {
return false;
}
}
return true;
}
// 使用
const newUser1 = {
age: 40,
password: 'qwertyuio',
agreeToTerms: true
}
validate(newUser1, oldEnough, passwordLongEnough, agreeToTerms);
// true
const newUser2 = {
age: 40,
password: 'qwer',
agreeToTerms: true
}
validate(newUser1, oldEnough, passwordLongEnough, agreeToTerms);
// false
// 遵循最少知识原则
function createValidator(...tests) {
return function(obj) {
for(let i = 0; i < tests.length; i++) {
if(tests[i](obj) === false) {
return false;
}
}
return true;
};
}
// 使用
const userValidator = createValidator(
oldEnough,
passwordLongEnough,
agreeToTerms
);
userValidator(newUser1); // true
userValidator(newUser2); // false
2 公众号
1. 公众号开发时,接口没有用/api开头却可以实现代理?
- 因为设置了电脑的host 实现了代理C:\Windows\System32\drivers\etc\host
2. canvas微信拍照
getPhoto(e) {
let input = e.target
let file = input.files[0]
// FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
let reader = new FileReader()
// 该事件在读取操作完成时触发。
reader.onload = (e)=> {
// 1 为了将图像显示到画布上,需要创建一个Image()对象的实例,
let img = new Image;
let iheight, iwidth;//图片resize宽度
let quality = 1;//图像质量
// 获取2d环境
let canvas = document.createElement("canvas");
let drawer = canvas.getContext("2d");
if (input.getAttribute('id') == 'fromCam3') {
iheight = 640 //1280////441
} else {
iheight = 720//500//300//200//960
}
// 2 将Image.src属性设为将要加载的图像的名字。
img.src = e.target.result
// 3 在显示图像之前,需要等待图像加载完毕。
img.onload = ()=> {
img.onload = null
iwidth = iheight * (img.width / img.height) // 保持图片的宽高比例 进行图片的缩放
canvas.width = iwidth
canvas.height = iheight
// 4 图像加载
drawer.drawImage(img, 0, 0, iwidth, iheight)
let finalSrc
let degree = 90 * Math.PI / 180 // 1/4圆
if (input.getAttribute('id') == 'fromCam1') {
// 5 将竖放的照片旋转为横放
if(iwidth<iheight){
canvas.width = iheight
canvas.height = iwidth
drawer.rotate(degree)
drawer.drawImage(img, 0, -iheight, iwidth, iheight)
}
}
if (input.getAttribute('id') == 'fromCam3') {
if(iwidth>iheight){
//将横放的照片旋转为竖放
iwidth = 640 //1280 //441
iheight = iwidth * (img.height / img.width)
canvas.width = iheight
canvas.height = iwidth
drawer.rotate(degree)
drawer.drawImage(img, 0, -iheight, iwidth, iheight)
}
}
// 返回一个包含图片展示的 data URI
// 参一:图片格式,默认为 image/png
// 参二:在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。
finalSrc = canvas.toDataURL("image/jpeg", quality)
if (input.getAttribute('id') == 'fromCam1') {
//身份正面
this.imageData1 = finalSrc
this.isActive = true
} else if (input.getAttribute('id') == 'fromCam3') {
//证件照
this.imageData3 = finalSrc
this.handleHistory(5)
}
this.loading = false
}
};
reader.readAsDataURL(file)
}
3 vue
1. 如何实现监听对象中一个属性的变化?
rule:{
name:"",
age:""
}
computed: {
getName: function() {
return this.rule.name
}
},
watch:{
getName:{
handler:function(){
//do something
}
}
}
2. 如何实现路由懒加载?
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const router = new VueRouter({
routes: [{
name: '',
path: '',
meta: {
title: '',
requireAuth: '',
},
// 使用import动态引入异步组件
component: () => import('@/index')
}]
})
3. 如何实现路由嵌套?
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const User = () => import('@/index');
const Profile = () => import('@/index/profile');
const router = new VueRouter({
routes: [{
name: 'user',
path: '/user',
component: User,
children: [{
// 当user/profile匹配成功时,组件会被渲染在User组件的<router-view></router-view>中
name: 'profile',
path: '/profile',
component: Profile
},{
name: '',
path: '',
component: ''
}]
}]
})
4. 如何实现路由拦截?
-
定义路由时,通过
meta属性
添加一个自定义字段requireAuth
-
利用
全局路由钩子beforeEach()
对路由进行判断 -
先判断该路由是否需要权限
to.meta.requireAuth
-
再获取当前
token
是否存在 -
存在则
next()
,否则将跳转的路由path
作为参数,登录成功后跳转至该路由
//定义路由元信息,确定哪个路由需要登陆权限
//router>index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const router = new VueRouter({
routes: [{
name:'cart',
path:'/cart',
component:Cart,
meta:{ requiresAuth :true}
}]
})
/**
* 进入路由后,确认用户是否登录[全局路由守卫中做判断]
* 如何实现登陆后跳回原页面? -- query & this.$route
* a: 登录则放行 -- [暂时]
* b: 否则跳转至登录界面并传递目标路由地址
*/
//app>routers>index.js -- 确认用户是否登录
router.beforeEach((to,from,next)=>{
//判断当前路由是否需要路由权限
if(to.meta.requiresAuth){
//获取token
let Authorization = localStorage.getItem('Authorization');
if(Authorization){
//登录则放行
next();
}else{
//否则跳转到登录页面
//同时传递路由地址 -- 为了登录后能够再次返回
// router.push('/login');
next({
path:'/login',
query:{
redirectUrl : to.fullPath
}
});
}
}else{
next();
}
})
5. 在单个vue文件实现流程切换,并做监听回退
watch: {
'$route.fullPath': function() {
let list = this.getQueryVariable('state')
this.statusArr.map((item,index) => {
if(index == list && this.status !== item) {
console.log(index,list,this.status,item);
this.handleHistory(list)
}
})
}
},
methods: {
//用于判断历史栈,是否推新的历史记录 @param n 当前的状态序号
handleHistory(n){
this.index=n
this.$router.push({name: 'shenLing', query: {state: this.index}})
},
//跳转到下一步
async toNext(){
if(this.status === 'xuZhi') {
setTimeout(() => this.handleHistory(1), 1000) ;
} else if() {}
}
}
6. 项目如果重构你会选择重构哪些地方?重构的方法以及必要性?
7. vuex的用法,vuex和bus总线的区别
-
vuex
是一个专门为vue.js程序开发的状态管理模式,vuex
实现数据共享,跨组件传参,适用大型项目; -
bus
当组件层级嵌套不深的时候可以用,适用于小型项目
8. vue的响应式原理,以及get set分别做了什么
-
vue在实例化时会遍历data下的属性,并通过
object.defineProperty()
把这些属性转为setter getter,并写入vue的实例。 -
getter的时候会收集依赖,setter的时候会触发依赖。
## 4 ajax
1. 对ajax的理解?编写用ajax发生GET、POST请求
- ajax即异步的
javaScript和XML
,它通过在后台与服务器进行少量数据交换,使得网页可以在不重新加载整个网页的情况下,对网页的某部分进行更新。即实现了异步更新。
// 先创建网络请求
let xhr = new XMLHttpRequest();
// 设置请求对象(方法、路径、异步)
xhr.open(method, url, async);
// 发送网络请求
xhr.setRequestHeader(); // post 请求设置请求头编码格式
xhr.send(string); // 一般用get时string为空
// 监听网络请求的状态
xhr.onReadyStateChange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
// json -> js对象
let data = JSON.parse(xhr.responseText);
} else {}
}
let timer = setTimeout(() => {
xhr.abort();
clearTimeout(timer)
},timeout)
}
2. 如何将后台返回的文件流转为excel?并且不乱码?
downloadFile() {
this.$axios.post('/applycard-service/admin/exportExcel',
this.formData, {
headers: {
Authorization: `Bearer ${this.token}`
},
// 请求头增加responseType,将后台返回的数据转为blob类型 [blob -- 类文件对象] -- 解决乱码
responseType: 'blob',
})
.then((res) => {
const blob = new Blob([res.data]);
const downloadElement = document.createElement('a');
// 创建下载的链接
const href = window.URL.createObjectURL(blob);
downloadElement.href = href;
// 下载后的文件名
downloadElement.download = `批量开卡_${this.getNowTime()}.xls`;
document.body.appendChild(downloadElement);
downloadElement.click(); // 下载
// 下载完成 移除 a
document.body.removeChild(downloadElement);
// 释放blob对象
window.URL.revokeObjectURL(href);
});
}
5 小程序
1. 小程序为啥不能用window
- 因为在jscode中运行的,这是一个没有窗口对象的环境
2. bug:textarea与原生下拉框重叠
- 实现textarea与view的切换展示
3. 小程序文本可复制
3.1 text标签
3.2 文本复制 wx.setClipboardData(object)
var inviteName = that.data.copyData[2].url;
wx.setClipboardData({
//准备复制的数据
data: inviteName,
success: function (res) {
this.toastComponent.showToastComponent("复制成功")
}
});
4. 实现分享到朋友圈
-
页面允许被分享到朋友圈,需满足两个条件:
- 页面需设置“发送给朋友” ---
Page.onShareAppMessage
- 页面需设置允许“分享到朋友圈”,同时可自定义标题、分享图等 ---
Page.onShareTimeline
- 页面需设置“发送给朋友” ---
Page({
// 第一步:设置可被分享
onShareAppMessage(res) {
return {
title: '传统分享的标题'
}
},
// 第二步:设置分享到朋友圈的标替
onShareTimeline(res) {
return {
title: '转发到朋友圈',
query: '我是携带的参数'
}
}
})
5. 人脸识别wx.startFacialRecognitionVerify(OBJECT)
- 验证方式:在线验证 -- 读数字 屏幕闪烁
/**
* return 值
* errMsg: String 错误信息
* errCode:Number 错误码
* verifyResult: String 本次认证结果凭证
*/
wx.startFacialRecognitionVerify({
name: String, // 必填
idCardNumber: String, // 必填
success: Function,
fail: Function,
complete: Function, // 必填
// 0-读数字 1- 反光 2-检查是否支持反光
checkAliveType: Number
})
6. 小程序内跳转至其他小程序wx.navigateToMiniProgram(Object object)
wx.navigateToMiniProgram({
appId: string, // 必填--要打开的小程序appId
path: string, // 打开的页面路径,为空则打开首页
})
7. 长按识别二维码
- image标签设置
show-menu-by-longpress属性为true
8. 实现服务通知requestSubscribeMessage
tmplIds
- 需要订阅的消息模板的id的集合,一次调用最多可订阅3条消息
- 消息模板id在[微信公众平台(mp.weixin.qq.com)-功能-订阅消息]中配置。每个tmplId对应的模板标题需要不相同,否则会被过滤。
wx.requestSubscribeMessage({
tmplIds: [''],
success(res) {},
fail() {},
complete() {}
})
9. base64转临时url
//声明文件系统
const fs = wx.getFileSystemManager();
//随机定义路径名称
var times = new Date().getTime();
var codeimg = wx.env.USER_DATA_PATH + '/' + times + '.png';
//将base64图片写入
fs.writeFile({
filePath: codeimg,
data: pics,
encoding: 'base64',
success: () => {
//写入成功了的话,新的图片路径就能用了
var urls = new Array(codeimg)
wx.previewImage({
//当前显示图片
urls,
})
}
});
10. 删除对象属性 delete Object.属性
设计模式
树的算法