日常疑问积累

目录

  1. js
    1.1 如何理解事件委托?
    1.2 高阶函数
  2. 公众号
    2.1 公众号开发时,接口没有用/api开头却可以实现代理?
    2.2 canvas微信拍照
  3. vue
    3.1 如何实现监听对象中一个属性的变化?
    3.2 如何实现路由懒加载?
    3.3 如何实现路由嵌套?
    3.4 如何实现路由拦截?
    3.5 在单个vue文件实现流程切换,并做监听回退
    3.6 项目如果重构你会选择重构哪些地方?重构的方法以及必要性?
    3.7 vuex的用法,vuex和bus总线的区别
    3.8 vue的响应式原理,以及get set分别做了什么
  4. ajax
    4.1 对ajax的理解? 编写用ajax发生GET、POST请求
    4.2 如何将后台返回的文件流转为excel? 并且不乱码
  5. 小程序
    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. 如何实现路由拦截?

  1. 定义路由时,通过 meta属性 添加一个自定义字段requireAuth

  2. 利用全局路由钩子beforeEach() 对路由进行判断

  3. 先判断该路由是否需要权限 to.meta.requireAuth

  4. 再获取当前 token 是否存在

  5. 存在则 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. 实现分享到朋友圈

  • 页面允许被分享到朋友圈,需满足两个条件:

    1. 页面需设置“发送给朋友” --- Page.onShareAppMessage
    2. 页面需设置允许“分享到朋友圈”,同时可自定义标题、分享图等 --- 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.属性

设计模式

树的算法

posted on 2021-01-19 14:46  pleaseAnswer  阅读(155)  评论(0编辑  收藏  举报