根据对面试的回忆撰写的 、标准答案在网上查的,记录和学习使用,侵删
公司业务:企业管理、代账、法律咨询
公司技术栈:vue2、vue3
1、uniapp中rpx和upx的区别
rpx (Responsive Pixel):
rpx 是一种可以根据屏幕宽度进行自适应转换的单位。
1rpx 等于设备宽度的 1/750。也就是说,在一个宽度为 750px 的设计稿上,如果一个元素的宽度是 100px,那么在 UniApp 中应该设置为 100rpx。
使用 rpx 可以让开发者更方便地实现不同屏幕尺寸设备上的适配布局。
upx (UniApp Pixel):
upx 是 UniApp 自定义的一种长度单位,和 rpx 类似,也是为了实现响应式布局而设计的。
在最新的 UniApp 版本中,实际上已经将 rpx 单位更名为 upx,因此两者在功能上是一致的。
同样地,1upx 也等于设备独立像素宽度的 1/750。
总结来说,在 UniApp 当前版本下,rpx 已经被替换为 upx,它们的作用都是帮助开发者创建能自动适应各种屏幕尺寸的应用界面。
2、uniapp如何实现页面自适应
在uniapp中实现页面自适应,可以通过以下方法:
-
使用
<view>
标签作为容器,并设置样式display: flex;
来布局。 -
使用
rpx
单位,这是uniapp提出的响应式单位,可以根据屏幕宽度进行自适应。 -
使用
@import
引入全局样式文件,在该文件中设置基础的字体大小、边距等样式,确保页面元素按照屏幕大小适配。3<!-- 全局样式 global.css --> .p-10 { padding: 10rpx; } .m-10 { margin: 10rpx; } .font-14 { font-size: 14rpx; } <!-- 页面文件 --> <template> <view class="container"> <view class="box">自适应框</view> </view> </template> <script> export default { data() { return {}; } }; </script> <style> /* 引入全局样式 */ @import "global.css"; .container { display: flex; justify-content: center; align-items: center; height: 100%; } .box { width: 50%; /* 假设屏幕宽度大于640rpx,则宽度为屏幕宽度的50% */ background-color: #f0f0f0; padding: 20rpx; box-sizing: border-box; } </style>
3、vue的目录结构
4、Vue 组件之间的通信方式
(1)父组件向子组件传值
//App.vue父组件
<template>
<div id="app">
<users :users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名
</div>
</template>
<script>
import Chilren from "./components/chilren "
export default {
name: 'App',
data(){
return{
users:["HelloKK"]
}
},
components:{
Chilren:Chilren
}
}
//chilren子组件
<template>
<div class="hello">
<ul>
<li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面
</ul>
</div>
</template>
<script>
export default {
name: 'chilren',
props:{
users:{ //这个就是父组件中子标签自定义名字
type:Array,
required:true
}
}
}
</script>
(2)子组件向父组件传值
// 子组件
<template>
<header>
<h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
</header>
</template>
<script>
export default {
name: 'app-header',
data() {
return {
title:"Vue.js Demo"
}
},
methods:{
changeTitle() {
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
}
}
}
</script>
// 父组件
<template>
<div id="app">
<app-header v-on:titleChanged="updateTitle" ></app-header>
//与子组件titleChanged自定义事件保持一致
// updateTitle($event)接受传递过来的文字
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from "./components/Header"
export default {
name: 'App',
data(){
return{
title:"传递的是一个值"
}
},
methods:{
updateTitle(e){ //声明这个函数
this.title = e;
}
},
components:{
"app-header":Header,
}
}
</script>
5、深拷贝和浅拷贝
浅拷贝:在栈内存中重新开辟一块内存空间,并将拷贝对象储存在栈内存中的数据存放到其中。
深拷贝:基于浅拷贝的过程如果栈内存里面存储的是一个地址,那么其在堆内存空间中的数据也会被重新拷贝一个并由栈空间新创建的地址指向。
1、基本类没有问题
因为,基本类型赋值时,赋的是数据(所以,不存在深拷贝和浅拷贝的问题)。
例如1:
var x = 100;
var y = x; //此时x和y都是100;
如果要改变y的值,x的值不会改变。
2、引用类型有问题
因为,引用类型赋值时,赋的值地址(就是引用类型变量在内存中保存的内容)
例如2:
var arr1 = new Array(12,23,34)
var arr2 = arr1; //这就是一个最简单的浅拷贝
如果要改变arr2所引用的数据:arr2[0]=100时,那么arr1[0]的值也是100。
原因就是 arr1和arr2引用了同一块内存区域(以上的第二点中有体现)。
这是最简单的浅拷贝,因为,只是把arr1的地址拷贝的一份给了arr2,并没有把arr1的数据拷贝一份。所以,拷贝的深度不够。
一、常见的 “浅” 拷贝方法:
除了上面我们演示的对于赋值操作,下面将介绍一些开发中可能会用到,当然也可以会被面试官问到的实现深浅拷贝的方法。
1. Object.assign()
方法解释:方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象,它将返回目标对象可以实现一个浅拷贝的效果。
参数一:目标对象
参数二:源对象
var obj1 = {
a: 1,
b: 2,
c: ['c', 't', 'r']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
obj2.b = 3
console.log(obj1); // {a:1,b:2,c:["c", 5, "r"]}
console.log(obj2); // {a:1,b:3,c:["c", 5, "r"]}
console.log(obj1.c); // ["c", 5, "r"]
console.log(obj2.c); // ["c", 5, "r"]
注意:可见Object.assign()方法对于一维数据是深拷贝效果,但是对于多维数据是浅拷贝效果。Object.assign是一个浅拷贝,它只是在根属性(对象的第一层级)创建了一个新的对象,但是对于属性的值是仍是对象的话依然是浅拷贝,
2. slice()
方法解释:数组进行截取,如果不传参数,会使用默认值,得到一个与原数组元素相同的新数组。
参数一:截取的起始位置
参数二:截取的结束位置
var a = [1, [1, 2], 3, 4];
var b = a.slice();
a[0] = 99
b[1][0] = 2;
console.log(a); // [99,[2,2],3,4]
console.log(b); // [1,[2,2],3,4]
注意:可见slice()方法也只是对一维数据进行深拷贝,但是对于多维的数据还是浅拷贝效果。
3. concat()方法
方法解释:数组的拼接(将多个数组或元素拼接形成一个新的数组),不改变原数组,如果不传参数,会使用默认值,得到一个与原数组元素相同的新数组 (复制数组)。
var a = [1, 2, [3, 4]]
var c = [];
var b = c.concat(a);
a[0] = 99
b[2][1] = 88
console.log(a); // [99,2,[3,88]]
console.log(b); // [1,2,[3,88]]
注意:可见concat()方法也只对一维数据具有深拷贝效果,对于多维的数据任然只是浅拷贝
4. ES6拓展运算符
var a = [1, 2, [3, 4]]
var b = [...a];
a[2][1] = 88
b[1] = 99
console.log(a); // [1,2,[3,88]]
console.log(b); // [1,99,[3,88]]
注意: 可见ES6的展开运算符对于一维数据是深拷贝效果,但是对于多维数据任然是浅拷贝效果。
二、实现 “深” 拷贝常见方法:
1. JSON.parse(JSON.stringify(obj))
JSON.stringify()是目前前端开发过程中最常用的深拷贝方式,原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse()反序列化将JSON字符串变成一个新的对象
JSON.stringfy() 将对象序列化成json对象
JSON.parse() 反序列化——将json对象反序列化成js对象
function deepCopy(obj1){
let _obj = JSON.stringify(obj1);
let obj2 = JSON.parse(_obj);
return obj2;
}
var a = [1, [1, 2], 3, 4];
var b = deepCopy(a);
b[1][0] = 2;
console.log(a); // 1,1,2,3,4
console.log(b); // 1,2,2,3,4
注意:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object类型,这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,
也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。
2. 使用第三方库实现对象的深拷贝,比如:lodash、jQuery
import lodash from 'lodash'
var objects = [1,{ 'a': 1 }, { 'b': 2 }];
var deep = lodash.cloneDeep(objects);
deep[0] = 2;
deep[1].a = 2;
console.log(objects); // [1,{ 'a': 1 }, { 'b': 2 }]
console.log(deep); //[2,{ 'a': 2 }, { 'b': 2 }]
3. 递归
这里简单封装了一个deepClone的函数,for in遍历传入参数的值,如果值是引用类型则再次调用deepClone函数,并且传入第一次调用deepClone参数的值作为第二次调用deepClone的参数,如果不是引用类型就直接复制
var obj1 = {
a:{
b:1
}
};
function deepClone(obj) {
var cloneObj = {}; //在堆内存中新建一个对象
for(var key in obj){ //遍历参数的键
if(typeof obj[key] ==='object'){
cloneObj[key] = deepClone(obj[key]) //值是对象就再次调用函数
}else{
cloneObj[key] = obj[key] //基本类型直接复制值
}
}
return cloneObj
}
var obj2 = deepClone(obj1);
obj1.a.b = 2;
console.log(obj2); //{a:{b:1}}
但是还有很多问题
首先这个deepClone函数并不能复制不可枚举的属性以及Symbol类型
这里只是针对Object引用类型的值做的循环迭代,而对于Array,Date,RegExp,Error,Function引用类型无法正确拷贝
对象循环引用成环了的情况