基于目前就业大环境,找工作确实不容易(僧多肉少,况且是我这种经验不足的新僧)。在今年8月18(周一)我于苏州某外包公司入职。工资不高,4k一个月,对于我这种应届毕业专科生来说,在苏州这种地方能刚好生活就已经足够了。目前以积攒经验为主,不求高薪,只求站住脚。
公司主要是承接各种小程序、app、H5等移动应用,主要框架是uniapp。当然了,pc端也能做。
这一周的工作周期是五天,收获良多。但是要说的话,还是得从面试说起。
上周五约到了面试,我人在上海,公司在苏州。领导约问周六有没有空,我说没问题。因为是跨市,时间上不太好弄,领导让我挑时间。我看了看时间,从我上海的住处到苏州公司的地方,全程接近四个小时。于是我询问领导,面试时间约在下午能否可以。领导也爽快,给的时间是下午两点。
当天中午提前到了公司附近,天气真的很热,还有一个小时,我便在楼下餐厅吃了点东西。
/吐槽一下真的恶心,3个菜28块钱/
我看着时间差不多就去楼上公司面试。
面试领导看了我简历,应届,培训,他表示培训出来的没必要问面试题,就让我直接上机,用uni写一个页面好了。一个小时,页面难度不大,上面一个tab栏,然后下边是个list列表,item中是样式相同的card,用组件做的话,也就是两个部分。因为接口还没产出,所以页面就做静态的就好,然后数据用假的数据。
嗯...怎么说呢,可能是太久不写骨架和样式了,所以写的太慢,手生。这就算了,最夸张的是,在引用组件库的时候,组件库还出了问题。结果就是骨架搭建好了,但是组件迟迟不能使用。结果一个多小时过去了,我的card还没开始做。
时间到了之后,面试官出来问情况,看我bug,帮我调试。然后调试了大概半小时,才找到bug的大概原因。
又拉我回办公室聊。
面试官表示自己很多年前也是培训班出来的,所以对培训班出身的水平有了解。页面没写完,对我的影响并不大。他表示他一般约面试都是周六周日,而非工作日。原因是考察面试者的态度,看看对待工作的渴望程度。我坐高铁地铁四个小时(上海地铁通勤时间太久,动不动就是一个多小时的地铁路程),又不介意休息日的时间面试,态度是很诚恳的。
然后他又说,他以前也是培训出来的前端,后来转了不做代码方面了,但是写也能写出东西了,bug什么的也会搞。我的水平不是很高,但是态度够真,他也愿意培养。但工资就是4k,如果一年后能继续干下去,水平上去之后,是可以涨的。
/说到底还是应届毕业工作经验===0/
我这一想,这不还是工作经验论薪酬吗?
可我现在又有什么办法呢?应届出来的,就是不吃香,我还不包装简历,坚持要真实,那就只好被社会真实一顿了
因为面试是在周六,领导说让我先回去,最迟周日晚上给我结果(不过结果还是通过了,告知周一开始上班)。
这是第一次正式的工作,想到要接触到最真实的项目经验了,我确实有些难捱的激动和紧张。
大概是知道我刚开始做,会有这些心态问题,所以一上来就是画页面。/对待新入行的年轻人,公司基本上大多数都是这一个套路,先画页面,页面画熟了就开始走逻辑了。/
培训班到后期其实还是很少画页面样式的,更多的还是业务逻辑的处理。所以我大概在画页面这个维度有两三个月的空缺,刚开始的时候,很慢。一天下来大概就是一个多页面。
因为是uniapp的框架,很多可复用的东西都是以组件的形式做。所以我先把页面里面可复用的组件找一找,把组件先做出来然后封装,以便后面需要的时候直接调用。比如一个很常用的button,以下是我项目中这个btn组件的完整代码。
<template>
<view>
<button @click="clcikBtn(way,jumpURL)" :class="'assBtn' + BGcolor"
:style="{ height: computedHeight,width: computedWidth,fontSize:computedFS}" :disabled="disabled">
<slot></slot>
</button>
</view>
</template>
<script>
// 判断参数是否是其中之一
function oneOf(value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
}
export default {
props: {
height: {
type: String,
default: "60rpx"
},
width: {
type: String,
default: "160rpx"
},
fontSize:{
type:String||Number,
default:"32rpx"
},
disabled: {
type: Boolean,
default: false
},
BGcolor: {
validator(value) {
return oneOf(value, ['Orange', 'Grey'])
},
default: 'Orange'
},
way: {
type: String,
validator(value){
return oneOf(value,['navi','switch','redi'])
},
default: 'navi'
},
jumpURL: {
type: String,
default: '../../pages/index/index'
}
},
computed: {
computedHeight() {
return /^[0-9]+$/.test(this.height) ? `${this.height}rpx` : this.height;
},
computedWidth() {
return /^[0-9]+$/.test(this.width) ? `${this.width}rpx` : this.width;
},
computedFS(){
return /^[0-9]+$/.test(this.fontSize) ? `${this.fontSize}rpx` : this.fontSize;
}
},
data() {
return {
}
},
methods: {
clcikBtn(way, jumpURL) {
if (way === 'navi') {
uni.navigateTo({
url: this.jumpURL
})
} else if (way === 'switch') {
uni.switchTab({
url: this.jumpURL
})
}else if (way === 'redi'){
uni.redirectTo({
url:this.jumpURL
})
}
}
}
}
</script>
<style lang="scss" scoped>
button {
width: 160rpx;
height: 60rpx;
font-size: 32rpx;
font-weight: 700;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
&::after {
border: none;
background-color: #00000000;
}
}
.assBtnOrange {
background-color: #FE5E10;
color: #ffffff
}
.assBtnGrey {
background-color: #ffffff;
border: 1px solid #999999;
color: #999999;
}
</style>
在这个代码中,btn接受的传值有宽(width),高(height),字体大小(fontSize),是否禁用(disabled),背景颜色(BGcolor),跳转地址(jumpURL)以及跳转方式(way),之所以要传一个way是因为,跳转的链接除了有navigateTo方法跳转,还有switchBar方法等。然后对传来的值进行判断,是否属于限定的数组中的内容,如果是数组中的数值,那就是匹配的属性值,那我就给加上对应的样式。
而组件封装时的传值问题,一开始我也没考虑到这么多东西,只是写了个宽高,后来发现需要的越来越多,就再往上加——发现背景颜色会不一样,就加一个BGcolor;发现字体大小不一样,就加一个fontSize。理论上,只要是css存在不一样,都可以在这里进行定义,增加组件的自定义属性。当然,如果不是个性化特别丰富的组件,大多数时候给定一个固定的样式,在一小部分样式上允许传值干涉就好。
而btn里面的文字有不一样的,这也只是一行代码,给一个插槽的事情罢了。如果还需要有个icon,那就给个具名插槽,这都不是什么麻烦事。
而我所写的商户端,页面不多,也就十多个。
这整个就是我第一周的工作计划。
第二周页面画完了,我开始研究接口了。中途,领导给了要求让我临时改几个其他项目的bug以及微调样式。在这里我就遇到一个比较麻烦的事,就是一个轮播图,然后每一页的图片色系不一样,黄橙蓝紫白。而麻烦的问题是,轮播图切换的时候,下面有五个点,对应的点要有一个光晕。然后五个点,中间有一条线连接...算了,我直接上图好了:
应该能明白,当轮播图发生变化,下面这条线的颜色会发生变化,圆圈也会发生变化,光晕也有变化,几个颜色一起联动。联动就算了,颜色还不一样,不能直接拿到对应颜色一次性全部赋值,你得把颜色做一点微调之后才赋值。
这个我真的吐了一桌子都是。
我说真话,这天晚上我想着明天工作不少,还有一个单独的(难度不大的)抖音小程序要一天速成,所以想提前一晚早点写点,第二天不用狠赶。
所以我下班回家之后,搞了五个小时去盘逻辑修bug和改样式直到夜里两点才调整好。
swiper好弄,无论是什么组件库还是uni内置组件,都有,问题就是下面那条线。我没有通过组件库(如果我没猜错,组件库中下边有点,但是样式跟这个完全不一样),这部分的内容属于是uni内置组件纯手写的功能。
这个业务的实现方案我不想解释,硬怼当然能实现,毕竟我就是用最蠢的办法去赋值然后解决的。不过应该还有更巧的办法,只是我懒得去想。光是几个变量的值我都反复记混,当晚电脑容量-10kb,个人脑容量-1极...
蠢办法代码如下:
<template>
<view class="page_content">
<swiper @change="swiperChange" previous-margin="55rpx" next-margin="25rpx" class="swiper"
:indicator-dots="false" :autoplay="false" :duration="500" :current="bigIdx">
<template v-for="(vip, i) in vips">
<swiper-item :key="'vip_'+i">
<view class="bgi">
<image :src="vip.url" mode=""
style="width: 644rpx;height: 284rpx;display: inline-block;overflow: hidden;position: relative;">
</image>
<image :src="vip.level" mode="" class="Vtext"
style="width: 296rpx;height: 104rpx;z-index: 999;left: 20rpx;top:40rpx;position: absolute;">
</image>
<text class="sub_title">{{vip.subTitle}}</text>
<!-- 设置进度条 -->
<template>
<view class="uni-padding-wrap uni-common-mt">
<view class="progress-box">
<!-- stroke-width宽度;activeColor已走完的进度;backgroundColor未走完进度 -->
<progress :percent="vip.Progress" stroke-width="6" :activeColor="vip.color"
backgroundColor="#EBEBEB66" />
</view>
</view>
</template>
</view>
</swiper-item>
</template>
</swiper>
<view class="dots" style="position: relative;">
<view class="line" :style="{borderColor:lineColor}">
<view class="ball" :style="{backgroundColor:ballColor}" v-for="(vip, id) in vips" :key="id"
@click="clickBall(id)">
<view class="" :class="{activeBall: id === bigIdx}" :style="{backgroundColor:vip.color}"></view>
<!-- :class="{activeBallText: id === bigIdx }" -->
<view class="ball-text" :style="{color:id===bigIdx?activeTextColor:textColor}">
{{vip.title}}
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
components: {
// level
},
data() {
return {
//选定的文本color,应该和选定的球颜色一样
//即this.activeTextColor.color=this.activeBallColor
activeTextColor: '',
textColor: '',
title: 'Hello',
bigIdx: 0,
//进度条的bgc
color: '',
//线的borderColor
lineColor: '',
//未选定的球的bgc
ballColor: '',
//选定的球的bgc
activeBallColor: '',
vips: [{
url: '../../static/member/qingtong.png',
level: '../../static/member/v1.png',
Progress: 50,
title: "青铜",
color: '#FF9D53',
lineColor: '#EFBE7A',
ballColor: '#EFBE7A',
activeBallColor: '#FF9D53',
subTitle: '还差300点成长值可升级为大众会员'
}, {
url: '../../static/member/baiyin.png',
level: '../../static/member/v2.png',
Progress: 40,
title: "白银",
color: '#BFBFBF',
lineColor: '#C3CACF',
ballColor: '#CECECE',
activeBallColor: '#F5F5F5',
subTitle: '还差300点成长值可升级为大众会员'
}, {
url: '../../static/member/huangjin.png',
level: '../../static/member/v3.png',
Progress: 69,
title: "黄金",
color: '#FFBB00',
lineColor: '#FFA629',
ballColor: '#FFC370',
activeBallColor: '#FFDD00',
subTitle: '还差300点成长值可升级为大众会员'
},
{
url: '../../static/member/bojin.png',
level: '../../static/member/v4.png',
Progress: 48,
title: "铂金",
color: '#3765FF',
lineColor: '#87A2FF',
ballColor: '#87A2FF',
activeBallColor: '#3765FF',
subTitle: '还差300点成长值可升级为大众会员'
},
{
url: '../../static/member/zuanshi.png',
level: '../../static/member/v5.png',
Progress: 36,
title: "钻石",
color: '#9000FF',
lineColor: '#9A00FF',
ballColor: '#D18BFF',
activeBallColor: '#9A00FF',
subTitle: '还差300点成长值可升级为大众会员'
}
],
}
},
onLoad() {
this.render()
},
methods: {
render() {
const b = this.vips[this.bigIdx]
//此时
//进度条的color是列表vips中该项进度条的color
this.color = b.color
//被选中的文字的color是列表vips中该项被选中的球的color
this.activeTextColor = b.activeBallColor
//未被选中的文字的color是列表vips中该项未被选中的球的color
this.textColor = b.ballColor
//线的color是列表vips中该项线的color
this.lineColor = b.lineColor
//未选中的球的color是列表vips中该项未选中的球的color
this.ballColor = b.ballColor
//选中的球的color是列表vips中该项选中的球的color
this.activeBallColor = b.activeBallColor
console.log(this.activeTextColor, this.textColor);
},
swiperChange(e) {
// console.log(e.detail.current);
let i = this.bigIdx = e.detail.current
// console.log(this.bigIdx);
let item = this.vips[i]
this.color = item.color
this.activeTextColor = item.activeBallColor
this.lineColor = item.lineColor
this.ballColor = item.ballColor
this.activeBallColor = item.activeBallColor
this.textColor = item.ballColor
console.log(this.activeTextColor, this.textColor);
},
clickBall(id) {
// console.log(id);
this.bigIdx = id
// console.log(this.bigIdx);
},
}
}
</script>
可能我在复制粘贴的时候有遗漏,或者多余的部分。我也不想多做什么解读,看到我的代码就知道,能解决问题的屎山再臭,都是龙涎香。
当然,如果有人愿意来吧屎山铲走,换成金山,我也会相当兴奋。
然后第一周工作完成后,第二周我开始上接口。这个是我画页面的项目的另一个兄弟项目,就是一个是商家端一个是用户端。然后这个现在这个端呢,有的问题就比较多了,也比较有意思。
1、个人主页的图片回显和上传
照片视频上传,不难吧?拿到数据,然后回显,不难吧?
但是这两业务放一起我就没搞出来。
业务逻辑参考各种陪玩软件的陪陪主页,他们上传了视频和图片之后肯定还要随时更新,这个时候要回显,并且准备好下次上传。
我当天研究了一整个下午。怎么回事呢?就是服务器传回来的图片地址,是不带根目录(基地址)的,就是http://一直到.com的那部分。然后你用这部分做回显,是不是肯定要给他拼接上基地址,不然图片地址是错误的,显示不出来。
问题就在这了!!
如果你对他图片路径进行字符串拼接:this.src='基地址'+res.url,那你的回显确实不会有问题。可如果要更换图片和视频,然后再点击上传,那么那些没有被更换的视频或者图片,本来就是带有http的完全路径,此时会在后端再次在前面加上一个http地址,然后下次回显的时候,他就变成了xxxxxxxxx.comhttp://xxxxxxxxxx… 你说这种图片路径,谁给你加载的出来?
针对这种情况,我跟我朋友进行三四个小时的研究后认为要在第二次上传的时候,对图片路径进行一次判断,判断是否存在http部分,如果有,就把头部去掉,没有就不动。
对,思路完全没问题。在完善逻辑之后,一个小时后终于完成,这时候我已经加班(应该说是自主学习)了1个小时。
然后我把这个方法写上去。是成功了。我准备收拾收拾书包回家吃饭。
可是我突然想起,公司另一个前端姐姐跟我说了另一种方法,只是我下午没看懂。
于是我又坐了下来,重新装好电脑,联系了我在黑马培训班的老师。
“老师,我这里有个方法没看懂,不知道有什么用。”
然后我把我的问题一股脑说了出来。然后老师只回了一个图片:
我直接大彻大悟。
异形屏顶部适配
异形屏的刘海啊,底部横杠啊,这些东西,一直都是多端适配的痛点啊!!!
因为我画的页面有的时候经常需要用到自定义navbar,如果不写适配,会发现刘海把头皮削掉了,就留了左右一边一个大耳朵,还被状态栏的各种碎发给挡住。(emm。中间的是刘海,那侧边的就是碎发吧。)
于是我抽了一个工作量不重的一天,那个上午我就专门去研究这个异形屏适配问题。
不知道是不是我没用对,反正啊,uniapp内置的一个获取系统信息的api————————uni.getSystemInfo,我是完全没拿到res,所以也没获取到顶部刘海的高度。其实还包括一些别的方法。
然后我发现有两个比较有效的适配方案,一个是css计算的'var(--state-bar)height'这样子的一种。
另一种就很棒了。uview-ui里面有一个专门的组件:
这个组件怎么用呢...就你如果需要异形屏适配,你就直接在template下的根节点,里面第一个元素就写个它,然后就解决了适配问题....
<template>
<view class="page_content">
<u-status-bar></u-status-bar>
<view>
其他内容
</view>
</view>
</template>
就这么简单...
监听键盘高度变化
uni中内置了个系统的api,叫 uni.onKeyboardHeightChange(),具体有需要的去uni的文档看用法。我不多做解读。在这里我只说一个我踩了的坑。业务逻辑是,点击了固定在最底部的input之后,input会弹起,出现在键盘上方。这个各种评论功能都有这个业务实现,应该不难想象。
然后我的逻辑是,点击input,然后触发聚焦事件,然后唤起键盘,同时调用这个方法监听键盘高度变化。让input下面垫一个view容器,这个容器高度不写,由键盘决定。键盘出现,把键盘的高度赋予view的高度。然后点击遮罩层之后,键盘收起。
整个逻辑就是翻城墙,键盘上去了,iput踩着垫起来的梯子也爬上去。
整个逻辑没什么问题,问题出在哪里?uni.onKeyboardHeightChange()这个方法,一直没有监听到第一次键盘高度变化。
但是第二次及以后,键盘高度变化都能监听到。我思来想去找不到原因。
我自言自语一直重复着“监听不到第一次”。突然就恍然大悟,对啊,是监听,既然是监听,应该从页面onload一开始就存在,这才叫监听,通过方法去开启监听,那不就是点击的那个时候弹起的键盘就是不在监听的时间段里,那肯定监听不到啊!
然后我就把这个监听事件写到了onload里面去了,果然,页面一打开就开始监听,键盘一弹起,input也跟着上去了。整个效果果然就正常了。
再重复一边:uni.onKeyboardHeightChange()是监听事件!!!要在事件发生之前就开启监听器,才能正常监听页面中发生的该事件!!
总的来说,第一个月,三周共15天的时间,我的工作非常充实,累计加班约30小时,不算多,但真的学到了很多真材实料的东西。