在某外包公司的工作月记(1)

154 阅读12分钟

基于目前就业大环境,找工作确实不容易(僧多肉少,况且是我这种经验不足的新僧)。在今年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以及微调样式。在这里我就遇到一个比较麻烦的事,就是一个轮播图,然后每一页的图片色系不一样,黄橙蓝紫白。而麻烦的问题是,轮播图切换的时候,下面有五个点,对应的点要有一个光晕。然后五个点,中间有一条线连接...算了,我直接上图好了:

da6055929d3a17b7ca599377639ca6e.png

3a75633c9c9f1204b22ac0a05708828.png

应该能明白,当轮播图发生变化,下面这条线的颜色会发生变化,圆圈也会发生变化,光晕也有变化,几个颜色一起联动。联动就算了,颜色还不一样,不能直接拿到对应颜色一次性全部赋值,你得把颜色做一点微调之后才赋值。

这个我真的吐了一桌子都是。

我说真话,这天晚上我想着明天工作不少,还有一个单独的(难度不大的)抖音小程序要一天速成,所以想提前一晚早点写点,第二天不用狠赶。

所以我下班回家之后,搞了五个小时去盘逻辑修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个小时。

然后我把这个方法写上去。是成功了。我准备收拾收拾书包回家吃饭。

可是我突然想起,公司另一个前端姐姐跟我说了另一种方法,只是我下午没看懂。

于是我又坐了下来,重新装好电脑,联系了我在黑马培训班的老师。

“老师,我这里有个方法没看懂,不知道有什么用。”

然后我把我的问题一股脑说了出来。然后老师只回了一个图片:

276c547aa2e0b6225b1fe8a9ebe8cc9.png

我直接大彻大悟。

异形屏顶部适配

异形屏的刘海啊,底部横杠啊,这些东西,一直都是多端适配的痛点啊!!!

因为我画的页面有的时候经常需要用到自定义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小时,不算多,但真的学到了很多真材实料的东西。