zl程序教程

您现在的位置是:首页 >  APP

当前栏目

【微信小程序高频面试题——精选一】

2023-03-31 11:02:38 时间

简介: uni-app是一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可以发布到IOS、Android、Web(响应式)、以及各种小程序、快应用等多个平台。
uniapp真正做到一套代码多端发行,支持原生代码混写和原生sdk集成。
运行体验更好。组件、api与微信小程序一致,兼容 Weex 原生渲染。
通用技术栈,学习成本更低。Vue的语法,微信小程序的api,对于前端开发人员来说更容易上手。
开放生态,组件更丰富。支持通过npm安装第三方包;支持微信小程序自定义组件及sdk;兼容 mpvue 组件及项目;app端支持与原生混合编码;

小程序中如何进行接口请求?会不会跨域,为什么

微信小程序有自带的api接口,wx.request();
不会跨域
跨域问题的出现是因为浏览器在进行请求时存在同源策略, 但是微信小程序不受同源策略的影响.所以不存在跨域问题

    wx.request({
 
      url: 'https://showme.myhope365.com/api/cms/article/open/list',
 
      method: "POST",
 
      data: {
 
        pageNum: 1,
 
        pageSize: 10
 
      },
 
      header: {
 
        "content-type": "application/x-www-form-urlencoded"
 
      },
 
      success: res => {
 
        console.log(res.data.rows)
 
      }
 
})

wx.request——参数说明

url 开发者服务器接口地址。注意这里需要配置域名
data 请求的参数
header 设置请求的 header,header 中不能设置 Referer,默认header[‘content-type’] = ‘application/json’
method(需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
dataType json 回包的内容格式,如果设为json,会尝试对返回的数据做一次 JSON解析
success 收到开发者服务成功返回的回调函数。
fail 接口调用失败的回调函数
complete 接口调用结束的回调函数(调用成功、失败都会执行)

小程序的常用命令有哪些

  1. 引用数据
    {{}} 小程序中任何需要获取数据的地方都需要用{{}},包括标签内的属性
    WXML 提供两种文件引用方式import和include。
    import 需要注意的是 import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件中 import 的 template,简言之就是 import 不具有递归的特性。
    include,可以将目标文件中除了 外的整个代码引入,相当于是拷贝到 include 位置。
  1. 逻辑渲染 wx:if wx:elif wx:else hidden
    hidden 条件渲染
    wx:if在不满足条件的时候会删除掉对应的DOM
    hidden属性则是通过display属性设置为none来进行条件渲染
  1. 列表渲染 wx:for wx:for-item wx:for-index wx:key,使用 wx:for-item 指定数组当前元素的变量名,使用 wx:for-index 指定数组当前下标的变量名。
    wx:key 的值以两种形式提供:
    字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
    保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

<view wx:for="{{array}}" wx:for-index="index" wx:for-item="itemName.id">{{index.cra}}</view>
  1. 驱动视图 this.setData({})
  2. 事件绑定 bind

你认为微信小程序的优点是什么,缺点是什么

优势

  1. 微信助理,容易推广。 在微信中,小程序拥有众多入口,例如附近的小程序、小程序码、分享、发现-小程序等五十多个的入口。这些入口有助于企业更好的获取流量,从而进行转化、变现。
  2. 使用便捷。 用户在使用小程序时,只需要轻轻点一下就可以使用,更加符合用户对使用方便、快捷的需求,所以小程序的用户数量不断增加。
  3. 体验良好,有接近原生app的体验 。 在微信生态里,小程序在功能和体验上是可以秒杀掉 H5 页面的,H5 页面经常出现卡顿、延时、加载慢、权限不足等原因,而这些问题在小程序里都不会出现。
  4. 成本更低。 从开发成本到运营推广成本,小程序的花费仅为APP的十分之一,无论是对创业者还是传统商家来说都是一大优势。

不足

  1. 单个包大小限制为2M。 这导致无法开发大型的应用,采用分包最大是20M(这个值一直在变化,以官网为准)。
  2. 发布审核麻烦。 需要像app一样审核上架,这点相对于H5的发布要麻烦一些。
  3. 处处受微信限制。 例如不能直接分享到朋友圈,涉及到积分,或者虚拟交易的时候,小程序也是不允许的

微信小程序中的js和浏览器中的js以及node中的js的区别

直观的说小程序中没有DOM和BOM对象,也无法对npm包进行管理

浏览器中JS

  • ES
  • DOM
  • BOM

Node中的JS

  • ES
  • NPM
  • Native

NPM 是包管理系统、NPM是目前最大的开原库生态系统,通过各种NPM扩展包快速的实践一些功能。
Native 就是原生的模块,通过这个模块来使用JavaScript语言本身不具有的一些能力(native方法简单的讲,即Java调用非Java代码的接口)。

在这里插入图片描述

小程序中的JS

  • ES
  • 小程序框架
  • 小程序API

在这里插入图片描述

微信小程序中的数据渲染浏览器中有什么不同

浏览器中渲染是单线程的;

而在小程序中的运行环境分成渲染层和逻辑层, WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。

小程序中如何渲染数据

  1. WXML模板使用 view 标签,其子节点用 {{ }} 的语法绑定一个 msg 的变量。

  2. 在 JS 脚本使用 this.setData 方法把 msg 字段设置成 “Hello World”。

简述一下微信小程序中通讯模型

小程序的渲染层和逻辑层分别由2个线程管理:

  1. 渲染层的界面使用了WebView 进行渲染;

  2. 逻辑层采用JsCore线程运行JS脚本。

一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(Native)做中转。
逻辑层发送网络请求也经由Native转发。

在这里插入图片描述

谈谈对微信小程序中生命周期函数的理解

小程序中的生命周期函数,分为 应用生命周期函数页面生命周期函数
在这里插入图片描述
应用生命周期函数

onLaunch 函数的参数也可以使用 wx.getLaunchOptionsSync 获取;
onShow 也可以使用 wx.onAppShow 绑定监听;
onHide 也可以使用 wx.onAppHide 绑定监听;

App.js是小程序入口文件,所以在App.js中调用应用生命周期函数:
微信小程序官网

App({
  onLaunch: function () {
  // 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
  },
  onShow: function (options) {
  // 当小程序启动,或从后台进入前台显示,会触发 onShow 
  },

  onHide: function () {
  // 当小程序从前台进入后台,会触发 onHide
  },
  onError: function (msg) {
  // 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
  }
})

页面生命周期函数有:
微信小程序官网

在这里插入图片描述

还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义。其中可用的生命周期包括:

生命周期参数描述
show组件所在的页面被展示时执行
hide组件所在的页面被隐藏时执行
resizeObject Size组件所在的页面尺寸变化时执行

微信小程序中如何进行事件的定义,传参

  1. 事件定义 bind开头
    在小程序中绑定事件可以以bind开头然后跟上事件的类型,如bindtap绑定一个点击事件,对应的值是一个字符串,需要在page构造器中定义同名函数,每次触发事件之后就会执行对应函数的内容。

  2. 阻止事件冒泡 catch开头
    在小程序中除了通过bind之外,还可以通过catch进行事件绑定,通过catch绑定的事件不会触发事件冒泡。

  3. 事件捕获 capture-bind开头
    事件的触发分为两个阶段,首先是捕获阶段,其次是冒泡阶段。默认情况下事件都是在冒泡阶段触发。如果希望事件可以在捕获阶段触发,可以通过capture-bind进行事件绑定。

  4. 事件传参 data-
    在小程序中进行事件传参不能像传统的Web项目中一样,在括号里写参数。在小程序中需要在标签上通过data-方式定义事件所需的参数。

关于事件对象其他属性

type 事件类型
timeStamp 页面打开到触发事件所经过的毫秒数
target 触发事件的组件的一些属性值集合
currentTarget 当前组件的一些属性值集合
detail 额外的信息
touches 触摸事件,当前停留在屏幕中的触摸点信息的数组
changedTouches 触摸事件,当前变化的触摸点信息的数组

这里需要注意的是target和currentTarget的区别,currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。

<!-- data-参数名=’参数值’ -->
 
<view bindtap="handleTap" data-msg="我是事件的参数">点击事件</view>
 
       每个事件回调触发时,都会收到一个事件对象,通过这个对象可以获取路由传递的参数。
 
handleTap(e){
	console.log("执行了点击事件");
	// 通过currentTarget中的dataset属性可以获取时间参数
    console.log(e.currentTarget.dataset.msg);//我是事件的参数
}

wxss和css有什么区别

WXSS和CSS类似,不过在CSS的基础上做了一些补充和修改。

  1. 单位 1rpx(Rpx) = (屏幕宽度/750)px
    在WXSS中,引入了rpx尺寸单位。引用新尺寸单位的目的是,适配不同宽度的屏幕,开发起来更简单。
    在小程序中,规定所有手机的屏幕宽度都是750rpx,所以在不同尺寸的屏幕下1rpx的宽度都不同。
    在iphone6手机下,屏幕宽度是375px,所以1rpx=0.5px。
    wxss尺寸单位rpx的引入,来提升不同屏幕的适配体验,750rpx = 375px;
  2. 提供了全局的样式和局部样式
    项目根目录中的 app.wxss 会作用于所有小程序页面
    局部页面的 .wxss 样式仅对当前页面生效
    • wxss仅支持部分css选择器:
      • .class和#id
      • element
      • 并集选择器 后代选择器
      • ::after ::before等伪类选择器
  3. 外联样式导入不同,wxss 使用@import标识符来导入外联样式。

小程序如何进行页面的跳转传参以及接收数据

最常用的两个页面的跳转和传参方式:1.wx.navigateTo 2.navigator标签

保留当前页面,只能打开非 tabBar 页面。

<navigator url="/page/navigate/navigate?title=navigate" hover-class="navigator-hover">跳转到新页面</navigator>

wx.navigateTo({
     url: `/pages/details?id=${xxx}`
});

其他方式:

  • wx.switchTab() 不能进行页面传参
    用来 跳转至tabBar页面,并关闭其他所有非 tabBar 页面

  • wx.redirectTo() 关闭卸载当前页面,只能打开非 tabBar 页面。

  • wx.navigateTo() 一样,都 跳转至非tabBar页面,但会关闭当前页面

  • wx.reLaunch() 关闭卸载所有页面,可以打开任意页面。

  • wx.navigateBack() 用来返回上一页面或多级页面,并关闭当前页面。
    返回前面的页面,可以指定返回多少页,如果用过redirectTo,那么被关闭的页面将不能返回

wx.navigateBack({
 
  delta: 2  //返回的页面数,如果 delta 大于现有页面数,则返回到首页。
 
})

接收参数
路由跳转传参可以通过?的方式拼接参数。跳转到指定界面之后,可以在该页面的onLoad方法中的options参数(本身是个对象)拿到路由跳转的参数。

小程序如何进行本地存储?

小程序提供了读写本地数据缓存的接口,通过wx.setStorage写数据到缓存,在小程序中几乎所有接口都是异步的,这里存储数据也是一个异步操作,如果希望进行同步存储需要调用wx.setStorageSync。

异步存储👲

    wx.setStorage({
 
      data: {name:"天亮教育",age:4},
        //需要存储的内容。只支持原生类型、Date、及能够通过JSON.stringify序列化的对象。
 
      key: 'list',//本地缓存中指定的 key
 
})

同步存储👲

wx.setStorageSync('list1', {name:"尚云科技",age:5})

同步读取

const list = wx.getStorageSync('list')

缓存的限制和隔离

  • 小程序宿主环境会管理不同小程序的数据缓存,不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB,如果当前缓存已经达到10MB,再通过wx.setStorage写入缓存会触发fail回调。
  • 小程序的本地缓存不仅仅通过小程序这个维度来隔离空间,考虑到同一个设备可以登录不同微信用户,宿主环境还对不同用户的缓存进行了隔离,避免用户间的数据隐私泄露。
  • 由于本地缓存是存放在当前设备,用户换设备之后无法从另一个设备读取到当前设备数据,因此用户的关键信息不建议只存在本地缓存,应该把数据放到服务器端进行持久化存储。

谈谈你对微信小程序请求封装的理解

封装前

wx.request({
  url: 'xxx',
  data: {
    a: '',
    b: ''
  },
  header: {
    'content-type': 'application/json' // 默认值
  },
  success(res) {
    console.log(res.data)
  },
  fail(err){
    console.log(err)  
  }
})

封装后

const baseUrl = "123456.com"
function request(method, url, dataObj) {
    return new Promise(function(resolve, reject) {
        let header = {
            'content-type': 'application/json',
        };
        wx.request({
            url: baseURL + url,
            method: method,
            data: dataObj.data,
            header: dataObj.header||header,
            success(res) {
                //请求成功
                if (res.code == 0) {
                    resolve(res);
                } else {
                    //其他异常
                    reject('运行时错误,请稍后再试');
                }
            },
            fail(err) {
                //请求失败
                reject(err)
            }
        })
    })
}

(上面的方法)由于每个页面单独请求效率低下且不便于维护,所以需要封装 wx.request 接口。
通常以返回 promise 对象的形式进行请求的封装:
下面的时候封装后的,可以直接通过 .then() 方法使用

封装的优点

  1. 提高代码的复用性
  2. 提高代码安全性
  3. 便于修改增加可维护性
  4. 简化外部调用,便于开发
  5. 符合高内聚低耦合特性
  6. 代码美观

作用:

  1. 添加统一的请求配置
  2. 可以添加请求拦截器和响应拦截器,在请求和响应之前加一些通用的处理。

小程序如何实现数据驱动视图

在JS文件中的data中动态操控数据:使用 this.setData方法修改视图层data中的数据;

在wxml文件通过{{}}将数据绑定,即可在页面中显示

注意:

  • 直接修改this.data,而不调用this.setData(),是无法改变当前页面的状态,会导致数据不一致
    仅支持可以JSON化的数据
  • 单次设置的数据不能超过1024KB,尽量避免一次设置过多的数据
  • 不要把data中的任何一项的value设为undefined,否则这一项将不能被设置,可能会有潜在的问题
<!-- page.wxml -->
 
<view>{{text}}</view>
 
// page.js
 
Page({
 
  data: {
    text: '天黑教育',
  },
 
onLoad(){
 
      console.log(this.data.text)//天黑教育
      this.setDatta.text = '50'
      console.log(this.data.text)//50

 
}
 
})

为什么微信小程序会出现登录鉴权的问题, 如何解决

原因

通常后端采用的登录鉴权方式是通过cookie的方式进行的鉴权,即登录成功之后,后端会给我们cookie上增加一个JSESSIONID,这个JESSIONID就标识了当前登录用户的身份。

在浏览器中,我们每次发送请求都会携带cookie,所以说在浏览器中我们登录成功之后就可以直接调用登录之后才能访问的接口。但是在小程序端,小程序默认不会帮我们在发送请求的时候带上cookie,这个时候就需要我们手动添加请求cookie了。

解决方法

    1. 在登录成功之后,我们获取到后台返回的cookie中的JESSIONID并进行记录。

    2. 在每次发送请求的时候,在请求头中添加上cookie属性。
function request(options) {
 
  // 请求拦截器
 
  //  ...
 
  // 1. 加一些统一的参数,或者配置
 
  if (!options.url.startsWith("https://") && !options.url.startsWith("http://")) {
	 //地址仅供参考
    options.url = "https://showme.myhope365.com" + options.url
 
  }
 
  // 默认的请求头
 
  let header = {
 // 默认的格式
"content-type": "application/x-www-form-urlencoded",
 
// 加上统一的cookie
 
"cookie": wx.getStorageSync("cookie") || ""
 
  };
 
  if (options.header) {
 
    header = {
 
      ...header,
 
      ...options.header
 
    }
 
  }
 
 
 
  return new Promise((reslove, reject) => {
 
    // 调用接口
 
    wx.request({
 
      // 默认的配置
 
      // 加载传入的配置
 
      ...options,
 
      header,
 
      success(res) {
 
        // 响应拦截器,所有接口获取数据之前,都会先执行这里
 
        //  1. 统一的错误处理
 
        if (res.statusCode != 200) {
 
          wx.showToast({
 
            title: '服务器异常,请联系管理员',
 
          })
 
        }
 
 
 
        reslove(res)
 
      },
 
      fail(err) {
 
        reject(err)
 
      }
 
    })
 
  })
 
}

对小程序中常见的开放能力API有什么了解

获取网络状态(2G/3G/4G/5G/WIFI…)

Page({
  // 点击“预览文档”的按钮,触发tap回调
  tap: function() {
    wx.getNetworkType({
      success: function(res) {
        // networkType字段的有效值:
        // wifi/2g/3g/4g/5g/unknown(Android下不常见的网络类型)/none(无网络)
        if (res.networkType == 'wifi') {
          // 从网络上下载文档
          wx.downloadFile({
            url:' https://lark-temp.oss-cn-hangzhou.aliyuncs.com/__temp/464110/docx/bb5d8e7d-97bc-406b-be94-ca2b4724c0e6.docx?OSSAccessKeyId=LTAI4GKnqTWmz2X8mzA1Sjbv&Expires=1644944885&Signature=qUYOtNWZOaopjkEFbcKpvgmn%2B1U%3D',
            success: function (res) {
              // 下载成功之后进行预览文档
              wx.openDocument({
                filePath: res.tempFilePath            
				})
            }
          })
        } else {
          wx.showToast({ title: '当前为非Wifi环境' })
        }
      }
    })
  }
})

扫码能力

Page({
  // 点击“扫码订餐”的按钮,触发tapScan回调
  tapScan: function() {
    // 调用wx.login获取微信登录凭证
    wx.scanCode({
      success: function(res) {
        var num = res.result // 获取到的num就是餐桌的编号
      }
    })
  }
})

分享能力(分享朋友圈-聊天页面)

Page({  
onShareAppMessage(){    
    // 我们要记录转发的记录    
    return {      
    // 分享的标题     
     title:'网友热议',      
    // 分享的封面, 默认为当前页面的截图      
    imageUrl:"/assets/icon/index.png",      
    // 点击分享跳转的路径,默认是当前路径,也可以自定义配置,添加额外的跳转参数      path:"/pages/index/index?userId=10&entry=share"
    }
},  // 省略了别的属性  ...}) 

wx.canIUse(string schema)
判断小程序的API、回调、参数、组件等是否在当前版本可用

wx.getSystemInfoSync() | wx.getSystemInfo()
获取系统信息

wx.getUserProfile(Object object)
获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo

小程序的父子传参和vue中的有什么区别

区别
父传子 properties接收
子传父 triggerEvent方法

父传子的不同点是:微信小程序在子组件中接受父组件传 用 propertites 进行接收,而不是 props

  properties: {
     msg:{
      // type 要接收的数据的类型
      type:String,
      // value 默认值
      value:""
    },
  },

子传父的不同点是:微信小程序在子组件中使用 triggerEvent 抛出自定义事件名,而不是 this.$emit()

 methods: {
    sendData() {
      console.log(this.data.msg)
      this.triggerEvent('eventName', '要传递的参数')
    }
  }

谈谈你对behavior的理解

behaviors 是用于组件间代码共享的特性,类似于一些编程语言中的 mixins 或 traits。

每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior ,behavior 也可以引用其它 behavior 。

组件引用时,在 behaviors 定义段中将它们逐个列出即可。

// my-component.js
var myBehavior = require('my-behavior')
Component({
  behaviors: [myBehavior],
  properties: {
    myProperty: {
      type: String
    }
  },
  data: {
    myData: 'my-component-data'
  },
  created: function () {
    console.log('[my-component] created')
  },
  attached: function () { 
    console.log('[my-component] attached')
  },
  ready: function () {
    console.log('[my-component] ready')
  },
  methods: {
    myMethod: function () {
      console.log('[my-component] log by myMethod')
    },
  }
})

如何优化首次加载小程序的速度

包体积优化

  • 分包加载(优先采用,大幅降低主包体积)。

  • 图片优化(1.使用tinypng压缩图片素材; 2.服务器端支持,可采用webp格式)。

  • 组件化开发(易维护)。

  • 减少文件个数及冗余数据。

请求优化

  • 关键数据尽早请求(onLoad()阶段请求,次要数据可以通过事件触发再请求);整合请求数据,降低请求次数。
  • 采用cdn缓存静态的接口数据(如判断用户登录状态,未登录则请求缓存接口数据),cdn稳定且就近访问速度快(针对加载总时长波动大)。
  • 缓存请求的接口数据。

首次渲染优化

  • 图片懒加载(节省带宽)。
  • setData优化(不要一次性设置过多的数据等)。
  • DOM渲染优化(减少DOM节点)

微信小程序如何实现瀑布流效果?

思路:把屏幕分为左右两个容器,根据容器的高度决定下一个元素应该放在哪个容器内(高度相对较低的容器)。

  // 处理数据
  initList(list) {
    this.data.finish = false
    // 临界值
    if (list.length == 0) {
      this.data.finish = true
      return
    }
    let item = list.shift()
    wx.getImageInfo({
      src: item.coverImgUrl,
      success: (res) => {
        if (this.data.leftHeight <= this.data.rightHeight) {
          // 默认从左往右渲
          this.data.leftList.push(item)
          this.data.leftHeight += res.height / res.width
        } else {
          this.data.rightList.push(item)
          this.data.rightHeight += res.height / res.width
        }
        this.setData({
          leftList: this.data.leftList,
          rightList: this.data.rightList,
        })
      },
      complete: () => {
        this.initList(list)
      }
    })

I guess it comes down to a simple choice: get busy living or get busy dying.
该做个简单的选择了:要么忙着活,要么忙着死。