追风

我的前端之路


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

8月项目回顾

发表于 2019-09-14 | 分类于 前端三剑客

开车了项目回顾总结

问题回顾(技术问题,业务问题皆可,或者项目中使用的新技术,插件,解决方案)

问题1 safari浏览器抖动问题

问题描述:(问题的背景,出现场景)

描述: Safari浏览器,多个input框聚焦输入,当input失去焦点时,页面会整体往上移动,导致底部留白,并且页面其他按钮错位?

解决方案(代码,截图)

解决: 当前页面,没有激活状态的input框是,在将页面复原。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 可以附上代码
const reg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;
let msg='';
if (this.boardNumber.replace(/^ +| +$/).length === 0) {
return;
}
if (!reg.test(this.boardNumber)) {
msg = '请输入正确的车牌格式';
}
if (msg) {
this.$toast.show({text: msg})
}
if (document.activeElement.tagName.toLowerCase() !== 'input') {
window.scrollTo(0,0);
}

问题2 clipboardjs多个按钮复制

问题描述:(问题的背景,出现场景)

vue组件中循环渲染‘复制’按钮,当全局只创建一个clipboard对象或者不动态绑定‘文本复制源’,那么每个按钮复制的文本会相同?

1
2
3
4
5
6
// 动态指定文本源
new ClipboardJS('.btn', {
target: function(trigger) {
return trigger.nextElementSibling;
}
});

解决方案(代码,截图)

在每个按钮的点击事件中,均创建一个clipboard对象,并且动态地绑定按钮对应的文本元素

1
2
3
4
5
6
7
8
9
<input
type="text"
:value="awardInfo.snCode"
id="sncode"
:class="{['sncode'+index]:true}"
:ref="'sncode'+index"
style="position: absolute;opacity: 0;top: -0.4rem;"
/>
<button class="operator" :class="{['copyBtn'+index]:true}" @click="copyLink(awardInfo.prizeType)" >复制劵码</button>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 copyLink(prizeType) {
console.log(1111)
let _this = this,
clipboard = null;
clipboard = new this.$clipboard(`.copyBtn${_this.index}`,{
target: function() {
return _this.$refs['sncode'+ _this.index]
}
});
// }
this.domPoint('KZQ003001','点击复制券码');
clipboard.on('success', function() {
// console.log(_this.text)
_this.$toast.show({
text: '复制成功',
type: 'success'
});
// clipboard.destroy();
});
clipboard.on('error', function() {
_this.$toast.show({text: '复制失败', type: 'fail'});
});

}

问题3 动画按顺序执行

问题描述:(问题的背景,出现场景)

项目中遇到,一次可能走2段或多段弧线的问题,如果一次循环执行运动函数,那么会执行跳到最后一段弧线初始位置并执行动画,前面的弧线没有动画效果?

1
2
3
4
5
6
7
// draw 是每段曲线的运动函数
let arr = this.points.slice(currentSiteIndex, targetSiteIndex);
const lastIndex = arr.length - 1,
self = this;
arr = arr.forEach((item, index) => {
draw.apply(self, [...item,150,20,true])(3)
})

解决方案(代码,截图)

采用动画队列的思想,前面弧线运动动画执行完后,再执行数组队列中的下一段弧线。

1
2
3
4
5
6
7
8
9
// nextRun
function nextRun(self,arr,index) {
let point = arr[index];
draw.apply(self,point)(3)
}
// draw 动画执行完,判断
if (index <= self.toRunPoints.length-1) {
nextRun(self,self.toRunPoints,index)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 // 根据起点查找弧线,执行
runCar(currentSiteIndex, targetSiteIndex) {
let arr = this.points.slice(currentSiteIndex, targetSiteIndex);
const lastIndex = arr.length - 1,
self = this;
arr = arr.map((item, index) => {
if (targetSiteIndex == 12 && index == lastIndex) {

/*
* 需要判断最后一段弧线
* draw.apply(self, [...item,150,20,true])(3)
*/
item = [...item, index, 150, 20, true];
} else {
item = [...item, index];
// draw.apply(self,[item)(3)
}
return item;
});
this.toRunPoints = arr;
// 动画按队列执行
nextRun(self, arr, 0);
}

问题4 Http 转态为0

问题描述:(问题的背景,出现场景)

开车了项目‘看咨询添加加速机会’,需要跳转页面,inituer接口没有完成,导致加速机会没有及时刷新?

解决方案(代码,截图)

initUser接口的状态码为0,是ajax的send没有执行,所以我们需要等咨询请求完成后,再跳转页面和initUser()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 // 看资讯
showInfomation(str) {
const self = this;
getInfomation().then(res => {
const {code, msg} = res;
if (code == 0) {
// 初始化
self.initUser(1).then(()=>{
window.location.href =
'https://owner.car.cmbchina.biz/information-h5/details.html?informationId=MAZcLgfZ&popup=true';
});
} else {
window.location.href =
'https://owner.car.cmbchina.biz/information-h5/details.html?informationId=MAZcLgfZ&popup=true';

self.$toast.show({text: msg, type: 'fail'});
}
});
if (str!='isnpc') {
self.domPoint('KZQ001004','点击看资讯');
}
}

问题5 原生audio在苹果手机不能成功播放

问题描述:(问题的背景,出现场景)

开车了项目要播放‘小车’运动时的背景音乐,使用原生的audio标签在苹果手机中兼容问题。

解决方案(代码,截图)

使用soundjs插件播放音频,注意soundjs与mock数据冲突。
具体代码:

1
2
<title>点亮回家路</title>
<script src="https://operation-kaichela.srv.cmbchina.biz/sound.min.js"></script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 注册音频
mounted() {
window.createjs.Sound.alternateExtensions = ['mp3'];
window.createjs.Sound.on('fileload', function() {
console.log('sound ok')
}, this);
window.createjs.Sound.registerSound(require('../../public/car_music.mp3'), 'carMusic');
// window.createjs.Sound.registerSound(require('../assets/media/btn_music.mp3'), 'btnMusic',1);

}
// 播放
carPlay() {
this.instance = window.createjs.Sound.play('carMusic');
this.instance.volume = 1;
}

项目心得/改进/建议(个人或团队)

开车了小结

  1. 项目前期多花些时间,梳理,确认需求,团队应加强沟通,完善好客户的需求,也方便后期的测试。
  2. 对项目有一个概览,对于数据状态的管理需要认真思考,可和同事交流,让代码结构灵活一些,以便后期应对需求改动的情况。
  3. 经过了开车了项目的开发,我对h5嵌套页面这种开发模式有了一定的了解,但是许多地方还是一知半解,比如分享链接参数的传递,首先请求接口
    获取参数,拼接在链接上,通过微信分享,点击链接,会进入后端,后端重新获取参数,再重定向到前端页面。。。 这一系列流程,还是有些不理解,希望在后面的开发过程中,能理解这套方案。
  4. 项目中遇到以前没有用到的插件,可向导师求助,了解基本用法。如果在使用中,出现bug,一定要去官网查看相关API,搜索博客找到API的用法,我在项目中遇到使用clipboardjs多个按钮复制文本相同的问题,就是结合官网和博客解决的。
  5. 前期的话要规划好项目的状态管理,比如项目中有许多弹框,在开车了中有10个左右的弹框,每个弹框都需要一个变量记录其显示与隐藏的状态,并且全部在 home.vue组件中维护,通过sync层层传递到home.vue步骤很繁琐,后面的项目中会尝试在vuex中配置一个弹框字段的对象dialogConfig,每个弹框都有对应的字符串,再使用一个变量isDialogShow来取dialogConfig相应的字段,如果字符相同弹框就显示,isDialogShow直接设置为空就可以让弹框隐藏。

王者荣耀小结

  1. 基本了解了分享助力带参数的流程。首先,前端调用初始化接口获取到自己的userId,然后在微信分享链接后面传自己的userId给后台;用户点击分享链接,后端会重定向到前端的wxIndex.vue微信落地页,这里我们可以从url上面截取到 帮我助力的helpId和微信图像等信息,再通过短链拼接将helpId和微信图像等信息传给后台,后台再次重定向再App首页 ,前端就可以截取到helpId并通过助力接口传给后台,判断助力情况。
  2. 了解了唤醒登录和微信禁止分享功能,代码块已收藏到为知笔记。

不受控制的 position:fixed

发表于 2019-09-07 | 分类于 前端三剑客

场景

最近在一个活动H5页面中,使用了translate3d技术来移动‘小车’,实现的效果在移动端测试还不错,小车按着规定的曲线,不急不慢的运动着,一切都是完美的。然而,问题来了,我后面加上的任务栏,明明是fixed相对屏幕定位,竟然在小车运动的时候,跟着背景图滚动,我的心也跟着了。。。
抱着万事找度娘的想法,我开始了网上冲浪之旅。终于,找了fixed定位失效的场景。

失效的 position:fixed

首先MDN 用一句话概括了这种情况:

当元素祖先的 transform 属性非 none 时,定位容器由视口改为该祖先。

通俗的讲就是指定了 position:fixed 的元素,如果其祖先元素存在非 none 的 transform 值 ,那么该元素将相对于设定了 transform 的祖先元素进行定位。

那么,为什么会发生这种情况呢?说好的相对视口(Viewport)定位呢?继续百度后,发现了堆叠上下文的概念(Stacking Context)

  • 任何非 none 的 transform 值都会导致一个堆叠上下文(Stacking Context)和包含块(Containing Block)的创建。
  • 由于堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个父元素。

Stacking Context – 堆叠上下文

堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。简单理解,就是生成了 Stacking Context 的元素会影响该元素的层叠关系与定位关系。

按照上面的说法,堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个父元素。

那么问题来了,是否所有能够生成堆叠上下文的元素,都会使得其子元素的 position:fixed 相对它,而不是相对视口(Viewport)进行定位呢?

阅读全文 »

vue递归组件

发表于 2019-08-25 | 分类于 Vue

递归组件与动态组件

递归组件

递归组件就是指组件在模板中调用自己,开启递归组件的必要条件,就是在组件中设置一个 name 选项。比如下面的示例:

1
2
3
4
5
6
7
8
9
10
<template>
<div>
<my-component></my-component>
</div>
</template>
<script>
export default {
name: 'my-component'
}
</script>

在 Webpack 中导入一个 Vue.js 组件,一般是通过 import myComponent from 'xxx' 这样的语法,然后在当前组件(页面)的 components: { myComponent } 里注册组件。这种组件是不强制设置 name 字段的,组件的名字都是使用者在 import 进来后自定义的,但递归组件的使用者是组件自身,它得知道这个组件叫什么,因为没有用 components 注册,所以 name 字段就是必须的了。除了递归组件用 name,也会通过遍历匹配组件的 name 选项来寻找组件实例。

阅读全文 »

Vue的构造器-extend

发表于 2019-08-20 | 分类于 Vue

Vue 的构造器——extend 与手动挂载——$mount

我们来看看Vue.js 内置但却不常用的 API——extend 和 $mount,它们经常一起使用。不常用,是因为在业务开发中,基本没有它们的用武之地,但在独立组件开发时,在一些特定的场景它们是至关重要的。

使用场景

我们在写 Vue.js 时,不论是用 CDN 的方式还是在 Webpack 里用 npm 引入的 Vue.js,都会有一个根节点,并且创建一个根实例,比如:

1
2
3
4
5
6
7
8
<body>
<div id="app"></div>
</body>
<script>
const app = new Vue({
el: '#app'
});
</script>

Webpack 也类似,一般在入口文件 main.js 里,最后会创建一个实例:

1
2
3
4
5
6
7
import Vue from 'vue';
import App from './app.vue';

new Vue({
el: '#app',
render: h => h(App)
});

因为用 Webpack 基本都是前端路由的,它的 html 里一般都只有一个根节点 <div id="app"></div>,其余都是通过 JavaScript 完成,也就是许多的 Vue.js 组件(每个页面也是一个组件)。

阅读全文 »

Vue组件通信-广播与派发

发表于 2019-08-15 | 分类于 Vue

组件的通信 2:派发与广播 dispatch 和 broadcast 方法

provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。然后有两种场景它不能很好的解决:

  • 父组件向子组件(支持跨级)传递数据;
  • 子组件向父组件(支持跨级)传递数据。

这种父子(含跨级)传递数据的通信方式,Vue.js 并没有提供原生的 API 来支持,而是推荐使用大型数据状态管理工具 Vuex,而我们之前已经介绍过 Vuex 的场景与在独立组件(或库)中使用的限制。我们可采用已经废弃的apidispatch 和 broadcast实现父子组件间通信的方法

$on 与 $emit

$emit 会在当前组件实例上触发自定义事件,并传递一些参数给监听器的回调,一般来说,都是在父级调用这个组件时,使用 @on 的方式来监听自定义事件的,比如在子组件中触发事件:

1
2
3
4
5
6
7
8
// child.vue,部分代码省略
export default {
methods:{
handleEmitEvent (){
this.$emit('test','hello vue.js')
}
}
}

在父组件中监听由 child.vue 触发的自定义事件 test:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- parent.vue,部分代码省略-->
<template>
<child-component @test="handleEvent"></child-component>
</template>
<script>
export default {
methods: {
handleEvent (text){
console.log(text) // hello vue.js
}
}
}
</script>

这里是在父组件 parent.vue 中绑定的自定义事件 test 的处理句柄,然而事件 test 并不是在父组件上触发的,而是在子组件 child.vue 里触发的,只是通过 v-on 在父组件中监听。既然是子组件自己触发的,那它自己也可以监听到,这就要使用 $on 来监听实例上的事件,换言之,组件使用 $emit 在自己实例上触发事件,并用 $on 监听它。

阅读全文 »
1…345…15
陈虎

陈虎

记录学习,记录生活,记录点滴

74 日志
12 分类
27 标签
RSS
© 2020 陈虎
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.4