写在前面
本人从事前端4个月以来参与了一个PC端vue项目和JS定制器练习,本博文是对PC端项目经验的总结,方便后续查找和翻阅。同时也希望自己的项目经验能够帮助到大家,不足之处,烦请大家批评指正,谢谢大家的支持。
PC端项目经验总结(排名不分先后,随心随性)
1.尽量少使用绝对定位,多使用万能的flex布局
如果一个页面使用很多绝对定位来布局,后期维护网页需要增添和删除内容修改样式时,会极为不便。使用父盒子包裹需要布局的内容,并给父盒子一个flex布局,可以很轻松地将不同的div和span放在一行显示。
2.网页请求优化
- 对同步模块框中不经常变化的接口,使用axios的config参数进行缓存。
/**
* 获取产品目录列表
* @param {object} catalog_id 请求参数
* @returns {Promise<Object|AxiosError>} 请求结果
*/
getProductsCatalogs(catalog_id) {
return this._get(`${catalog_id}/products/catalogs`, {
cache: true,
cache_seconds: 600
})
}
- 请求接口时去掉多余的参数。
- 可以使用web.dev对网站的性能进行测评。
3. 不能连写if条件中的判断条件
- 错误示范:
/**
* 获取分销商申请信息
*/
getDropshipApplyInfo() {
this.$storeDispatch('me/getDropshipperInfo', { skip_cache: true })
.onSuccess(({data}) => {
if(data.dropshipper.status === 'success' || 'pending') {
this.setMessagePromptBox(this.success_message, 'success')
this.$router.push(this.localePath({ name: 'dashboard' }))
} else {
this.setMessagePromptBox(this.$t('b_register.account_review'), 'error')
}
})
},
if(data.dropshipper.status === 'success' || 'pending')
是先判断data.dropshipper.status === 'success'
的值。如果值为真,就不会执行后面的判断条件,结果就为真;如果值为假,就会和 'pending'
做或运算,得到 'pending'
的结果,最后if
会将这个字符串强制转换为布尔值true
,所以最终结果也是真。即不管data.dropshipper.status === 'success'
的值是什么,最后的结果都为真,都会执行if条件语句中的内容。因此,不能连写if条件中的判断条件,不然会产生不同的判断语义。
-
正确示范:
if(['success', 'pending'].includes(data.dropshipper.status))
或者if (['success', 'pending'].indexOf(data.dropshipper.status) !== -1)
-
特别注意:
此处请求不常用的接口(设置的缓存时间为120s )获取分销商申请信息, 使用到
{ skip_cache: true }
。因为这个接口在C端用户进入B端发起申请分销商的请求后,如果返回的状态为成功,就会继续请求获取分销商申请信息的接口。如果此时不清除缓存,则不会发起获取分销商申请信息的请求,也就无法获取接口返回的状态了,因此需要清除缓存。所以区别于2.网页请求优化的第一点,给接口加缓存和清除缓存是要看情况的。
4 . 可以使用富文本编辑器(如vue-quill-editor)解析后端传入的html代码
5. 使用overflow-x:hidden来隐藏网页底部出现的滚动条
6.自定义组件如果要定义点击事件,需要使用@click.native
7.字符串模板``中使用${变量名}来获取变量
字符串模板只能在JS中引用,不能在html中使用。
8.当产品路由id发生变化时,轮播的当前索引并未重置
watch: {
'$route.params.id'() {
this.current_index = 0
}
}
9.根据路由地址判断是否为shopify页面
/**
* @returns {boolean} 是否是shopify页面
*/
is_shopify_page() {
return this.$route.path.indexOf('/shopify') === 0
}
shopify-app项目是基于B端代码进行兼容开发,网页大部分逻辑和样式都与B端相同。因此,对不同于B端的逻辑和样式需要使用is_shopify_page()
方法进行判断,从而达到兼容开发互不影响的效果。
10.使用git和arcanist工具进行开发
arc branch fix //新建fix分支进行开发,需要安装和配置arcanist
git checkout develop //切换到develop分支
git pull //拉取最新代码
git add . //暂存代码
git commit -m 'fix(登录模块): 修正...的问题' //添加评论
arc 4d //提交代码审核申请
arc 4l //代码审核通过,拉取合并代码,并解决冲突后,将代码提交到仓库
11.使用vue 内置组件component切换不同模态框的显示与隐藏
<template>
<el-dialog
class="shopify-modal-wrapper"
:close-on-click-modal="false"
center
:visible.sync="is_show_sync_product_modal"
width="980px"
@close="closeModal"
>
<div slot="title">
<p>{{ current_title }}</p>
<p
v-if="product.shopify_product"
class="red synced-message"
>
{{ $t('shopify_app.the_product_has_been_synced') }}
</p>
</div>
<component
:is="current_component"
v-loading.fullscreen.lock="is_sync_product_modal_loading"
:product="product"
@close-modal="closeModal"
/>
</el-dialog>
</template>
给整个页面加loading可以结合v-loading.fullscreen.lock
和vuex数据控制页面的加载状态。当点击Next按钮,则会切换为step2组件;当点击Back按钮,则会切换为step1组件;当关闭模态框时,会切换为默认的step1组件。
12.模态框的数据流问题(出错的原因纯属自己猜想,如有错误之处,麻烦评论区纠正,感谢)
- 公共产品模块:
- step1模态框:
- step2模态框:
-
问题1: 在第一个模态框修改数据后,点击进入第二个模态框。当切回第一个模态框时,发现第一个模态框修改的数据并未更新。
原因: 使用vue内置组件component控制的模态框相互独立,模态框切换的过程中,其余的模态框组件被销毁,而里面的数据并没有更新并保存下来,数据自然会丢失。如果要使模态框的切换成为一个连续的过程,可以在第一个模态框下一步按钮触发的next方法中,控制模态框的显示与隐藏。
做法:在step1组件下一步按钮触发的next方法中,使用vueX保存第一个模态框需要保存的数据。并在step1组件的created生命周期函数(只有在第一次点击同步按钮,显示第一个模态框和来回切换step1和step2组件的时候才触发生命周期函数)中,触发created生命周期函数中的第二个赋值函数,先判断vueX中存储的数据是否为空。
如果为空,就直接return。同时会触发created生命周期函数中的第一个赋值函数,获取产品的默认信息,将接口返回的产品信息展示到模态框上;如果不为空,就将vueX中存储的数据赋值给step1模态框需要使用的属性。
总结:所以step1组件中的created生命周期函数存在
两个赋值函数
。第一个赋值函数(用于每次重新打开step1模态框,初始化产品数据):当vueX数据为空(vueX的数据不存在或者每次在关闭模态框后被清空,问题2中会解释),说明是第一次打开step1组件或者关闭了模态框。此时step1模态框处于打开状态或者在打开step1模态框的状态,会将默认的产品信息展示到模态框上。这个赋值函数不论vueX数据是否为空都会被调用。
第二个赋值函数(用于从step2组件切换到step1组件,不会丢失修改的产品数据信息): 当vueX数据为空时,直接return,触发第一个赋值函数;当vueX中存在数据,说明已经进入过step2组件,此时切换到第一个模态框,会将vueX的数据赋值到step1组件中。此处需要特别注意,因为切换组件的过程会触发created生命周期函数,会同时调用两个赋值方法,此时将第二个赋值函数放在第二个,覆盖掉第一个的赋值即可。
vueX数据为空,则只会触发第一个赋值函数;vueX数据不为空,则会同时触发两个赋值函数,且第二个赋值函数由于在后面,会覆盖掉第一个赋值函数的值。
-
问题2:如果修改step1组件中的数据,切换到step2组件。然后关闭step1模态框,数据发生更新。此时再点击其他产品进行同步,step1组件默认都会展示相同的修改后的数据;如果修改step1组件中的数据,但不切换到step2组件,然后关闭step1模态框,数据不会发生更新;
原因:出现问题的原因在于step1组件中的数据是由vueX来控制,而vueX数据的保存是在点击Next按钮进入step2组件之后才触发。触发之后,会同时调用生命周期函数的两个赋值函数,此时模态框的初始值都被第二个赋值函数给覆盖掉了,所以每次打开模态框都会默认展示修改后的数据信息。因此需要在每次关闭模态框时,清空vueX中保存的step1组件的数据。
做法:监听
is_show_sync_product_modal(用于控制模态框是否显示的变量,在10中可以看到)
的值。如果值为假,说明模态框处于关闭状态,就将保存在vueX中的step1数据清空。这样每次在step1组件被初始化时,就会调用created生命周期函数中的第一个赋值函数,展示默认的产品信息;如果值为真,说明模态框处于打开状态,则会同时调用created生命周期函数的两个赋值方法(这里也需要同时调用两个赋值方法的原因在于,created只有在第一次打开step1组件和切换组件的时候才会触发,is_show_sync_product_modal
的值只要在第一个或者第二个模态框处于打开的状态就为真。
JS定制器练习经验总结(电商私人定制)
1. 给canvas上的图片增加翻转功能,需要点击翻转按钮和画布才能完成图片翻转
需要使用canvas.renderAll()更新画布,此时点击翻转按钮就能完成图片的翻转功能。
2. svg转换为base64,可以解决跨域问题
3. 网页效果图请求优化
- 个人JS定制器demo展示(界面很丑,但不要在意这些细节):
上传对应刀版的定制图片:
效果图预览:
- 当前canvas上的定制图未发生变化,不发起请求
- 对应刀版未上传定制图,不发起请求
4. 颜色选择器的颜色发生变更时,需要点击颜色选择器外部才能更新颜色
<!--错误的写法-->
<input type="color" id="color" onchange="changeFontColor()" />
<!--正确的写法,将onchange事件改为oninput事件,此时点击不同的颜色就能更新-->
<input type="color" id="color" oninput="changeFontColor()" />
5. 原型挂载
// 避免图片上的操作图标被overlayImage覆盖
fabric.Canvas.prototype.controlsAboveOverlay = true;
//canvas的scaleX可能会出问题,需要修改精确度,确保canvas能够正常导出为json数据
fabric.Object.NUM_FRACTION_DIGITS = 20
6. 使用变换矩阵调整缩放比例的值
//加载背景图
function setBackgroundAttribute(file) {
fabric.util.loadImage(file, (img) => {
var rect = this.__rect = new fabric.Rect({
hasControls: false,
fill: new fabric.Pattern({
source: img,
//使用相同图案进行填充
repeat: 'repeat',
//变换矩阵(第1个和第4个是缩放比例)
patternTransform: [1, 0, 0, 1, 0, 0]
}),
left: 0,
top: 0,
type: 'Background',
width: canvas.width,
height: canvas.height,
// 不缓存,避免图片发生变化时,因为已经缓存导致图片无法更新
objectCaching: false,
selectable: false
})
canvas.add(rect);
canvas.moveTo(rect, 0);
_getElement('BackgroundResize').value = 100;
canvas.renderAll();
backgroundObject = rect;
}, null, 'anonymous')
}
//获得变换矩阵
function _getBackgroundImagePatternTransform() {
return this.__rect.fill.patternTransform;
}
//处理背景图片的转换方法
function _handleBackgroundImageTransformAction(type, transform, value = null) {
const actionMap = {
toggleFlipX: (_transform) => {使用```event.target.va"```,可以在上传多张图片的业务情形时,上传相同图片
_transform[0] = _transform[0] * (-1);
},
toggleFlipY: (_transform) => {
_transform[3] = _transform[3] * (-1);
},
scale: (_transform) => {
_transform[0] = value;
_transform[3] = value;
}
}
if (!Object.keys(actionMap).includes(type)) return;
return actionMap[type](transform, value);
}
// 缩放/方法
function resizeBackgroundImage(value) {
if (!this.__rect) return;
const factor = value / 100;
_handleBackgroundImageTransformAction('scale', _getBackgroundImagePatternTransform(), factor);
_getElement('BackgroundResize').title = `${value}%`;
canvas.requestRenderAll();
}
7. 上传本地图片
- 使用
label for
和input type = "file"
组合形成上传组件,将label for
改造成按钮的样式,同时隐藏input type = "file"
的样式;
<label class="bold btn add-background" for="background">
Add Background
</label>
<input type="file" onchange="addBackground(event)" id="background" accept="image/*" class="file-ipt">
- 使用
event.target.value=""
,可以应用在上传多张图片的业务情景时,上传相同图片; - 定义全局变量
imageObject
。在每次调用上传本地图片的方法时,先canvas.remove(imageObject)
清除图片,再将上传的图片赋值给全局变量imageObject
,这种情况适合只能上传一张图片的业务情景。
8.使用固定定位做遮罩层
- loading效果:
<!--span的类我没加上-->
<div class="loading" id= "loading">
<img src="images/loading.gif" >
<span>loading...</span>
</div>
.loading {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: white;
opacity: 0.8;
z-index: 2021;
display: flex;
justify-content: center;
align-items: center;
}
9.fabric.js功能属性
//禁止缩放时翻转
lockScalingFlip: true,
//绕图片中心点缩放
centeredScaling: true,
//绕图片中心点旋转
centeredRotation: true,
//设置坐标的中心点
OriginX: 'center', //X轴方向,有'left','center','right'这三个属性可供选择
OriginY: 'center',//Y轴方向,有'top','center','bottom'这三个属性可供选择
//fabric.js中的left和top
//left是中心点到画布左侧的距离
//top是中心点到画布上方的距离
写在最后
还是很小白,还有很多知识需要学习和总结,专心学习技术。
总结:有点小绕,但只要自己看得懂就行了。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!