追风

我的前端之路


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

用js的方式实现vue弹框

发表于 2019-11-30 | 分类于 Vue

在平常,我们使用vue组件的时候,都要先在.vue文件中引入我们要使用的组件。虽然这样能满足大部分日常开发的需求,但这种方法在某些场景下,就有些难以应对。

  1. 组件的模板是通过调用接口从服务端获取的,需要动态渲染组件;
  2. 实现类似原生 window.alert() 的提示框组件,它的位置是在 下,而非
    ,并且不会通过常规的组件自定义标签的形式使用,而是像 JS 调用函数一样使用。

extend

Vue.extend 的作用,就是基于 Vue 构造器,创建一个“子类”,它的参数跟 new Vue 的基本一样,但 data 要跟组件一样,是个函数,再配合 $mount ,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue';

<!-- 创建了一个构造器,这个过程就可以解决异步获取 template 模板的问题 -->
const AlertComponent = Vue.extend({
template: '<div>{{ message }}</div>',
data () {
return {
message: 'Hello, Aresn'
};
},
});
<!-- 调用 $mount 方法对组件进行了手动渲染, -->
const component = new AlertComponent().$mount();
<!-- 挂载节点 -->
document.body.appendChild(component.$el);
<!-- 快捷的挂载方式 -->
new AlertComponent().$mount('#app');

这样就可以满足我们用js方法调用的方式来控制组件,但是在平常的开发中,我们用的vue的runtime编译环境,不支持template模板,而且用字符串来描述组件的模板,也有些不太友好。那么,我们可以试试用new Vue()的方式。

new Vue

new Vue()也可以直接创建 Vue 实例,并且用一个 Render 函数来渲染一个 .vue 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue';
import Notification from './notification.vue';

const props = {}; // 这里可以传入一些组件的 props 选项

const Instance = new Vue({
render (h) {
return h(Notification, {
props: props
});
}
});

const component = Instance.$mount();
document.body.appendChild(component.$el);

这样既可以使用 .vue 来写复杂的组件,还可以根据需要传入适当的 props。渲染后,如果想操作 Render 的 Notification 实例,也是很简单的:

1
const notification = Instance.$children[0];

阅读全文 »

js处理字符串和数字

发表于 2019-10-20 | 分类于 前端三剑客

字符串

字符串在自然世界中充当着非常重要的角色,所有的自然语言(比如汉语、英语等)都由多个字符组成,比如经典的 “Hello World” 这句话则由 11 个字符组成:H,e,l,l,o,,W,o,r,l,d。

创建字符串

在 JavaScript 中创建一个字符串跟其他语言并没有较大的区别,可以分别使用 ‘、” 和 ` 作为边界标识。

1
2
3
const str1 = 'string 1'
const str2 = "string 2"
const str3 = `string 3`

虽然 ` 同样可以以与 ' 和 " 一样的使用方式使用,但也可以有更高级的用法。

1
2
const target = 'World'
const word = `Hello ${target}` //=> Hello World

同时 ` 也可以用于创建一个“多行字符串”,即字符串内容中包含多行文本。

1
2
3
4
5
6
7
8
const str = `
Hello
World
`

//=>
// Hello
// World

分割字符串

一般来说人们都会使用词频统计作为数据科学的 “Hello World”,简单来说就是对一段英语内容中的单词进行频次(出现次数)统计。我们在进行词频统计之前,我们首先需要对源内容进行预处理。首先我们要了解的是,我们可以看到这段内容中有小写字母、大写字母以及标点符号(包括逗号、句号、括号、双引号、斜杠和冒号)。

而从语言角度,HELLO、hello 和 Hello 都是一样的,所以我们需要先完成以下预处理任务:

  1. 去除文本中的标点符号、数字
  2. 将所有大写字母转换为小写字母
    阅读全文 »

vue项目配合axios实现loading效果

发表于 2019-10-13 | 分类于 Vue

问题

在实际项目中,前端发送请求获取数据刷新页面是大家非常熟悉的操作。请求响应的快慢,与业务逻辑的复杂程度和网络环境有关,很有可能出现请求延迟的情况,如果我们不处理请求响应前后的交互,那么页面在请求响应成功之前这段事件就没有任何提示信息,这是非常影响用户体验的。但是如何为每个请求单独处理loading状态,那么工作量是非常大的。
axios是我们开发中常用的请求工具库,并且和vue能很好的搭配。下面向大家介绍我自己在项目中使用axios配置来完场全局的loading状态处理

store状态记录

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
state: {
// 是否在请求中
isAppending: false
},
mutations: {
changeAppending(state, bool) {
state.isAppending = bool;
}
}
});

阅读全文 »

SVG01

发表于 2019-10-05 | 分类于 svg

理解SVG中的 viewport,viewBox, preserveAspectRatio

理解viewport

该属性表示的是SVG可见区域的大小。或者也可以叫画布的大小。就好比我们的电脑屏幕,我们只能看到我们电脑屏幕的可视区里面的内容,但是看不到电脑屏幕之外的内容。比如如下代码:
1
<svg width="200" height="200" style="border: 1px solid red"></svg>

上述代码设置了svg的画布大小为200px*200px, 如果没有带单位的话,该单位默认是 px(像素)。当然也有其他单位:

  • em: 相对于父元素的字体大小。
  • ex: 相对于小写字母的 ‘x’ 的高度(不常用)
  • px: 像素(在支持css2的图形系统中,每英寸为96像素)。
  • pt: 点(1/72英寸)
  • pc: 12点(1/6英寸)。
  • cm: 厘米
  • mm: 毫米
  • in: 英寸

svg元素的width和height还可以为百分比,当我们的svg元素嵌套在一个div里面去的话,那么它的百分比是相对于外层的div元素的宽度和高度进行计算的。当然如果我们的svg元素为根元素的话,那么它的百分比是相对于窗口的尺寸来计算的

1
2
3
<div style="width:400px;height:400px; border: 1px solid red; ">
<svg width="20%" height="20%" style="border: 1px solid red;"></svg>
</div>

如果我们没有给svg设置宽度和高度的话,它默认的宽度为300px,高度为150px

理解默认用户坐标

在svg中有一个默认的坐标系统,其中 水平坐标(x坐标)向右递增的,垂直坐标(y坐标)是向下递增的。原点坐标是(0, 0). 该坐标系统类似于我们数学几何中的坐标。

比如我们现在建立一个200px宽,200px高的视口,然后我们在里面绘制一个矩形,该矩形左上角在坐标(10, 10)的位置,该矩形的宽度为50px, 高度为 50px,基本代码如下:

1
2
3
4
<svg style="border: 1px solid red;" width="200" height="200">
<rect x="10" y="10" width="50" height="50" style="stroke: black; fill:none;"></rect>
</svg>
<div style="width:100px;height:100px;margin-left:10px;background: red;"></div>
阅读全文 »

vue倒计时组件

发表于 2019-09-28 | 分类于 Vue

倒计时vue组件

最近在项目中,有了倒计时的需求,于是结合vue自己写了一个组件,我们只需传入一个结束时间endtime,即可开启倒数计时,倒计时结束后,我们可以监听timeOver事件。

注意事项

  • 倒计时无缝滚动,安卓手机bug处理nextTick和 setTimeout
  • timeOver事件,最好判断下 是否传入的endtime 是不一样的,不然可能出现死循环
    本组件支持时、分、秒的倒计时,并实现了无缝滚动的效果。具体参看代码呀!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
<template>
<div class="time">
<!-- 小时 十位数 -->
<div class="column" :class="{ animation: col1 }" ref="col1">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">6</div>
<div class="num" :class="{ android: isArd }">7</div>
<div class="num" :class="{ android: isArd }">8</div>
<div class="num" :class="{ android: isArd }">9</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
<!-- 小时各位数 -->
<div class="column" :class="{ animation: col2 }" ref="col2">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">6</div>
<div class="num" :class="{ android: isArd }">7</div>
<div class="num" :class="{ android: isArd }">8</div>
<div class="num" :class="{ android: isArd }">9</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
<div class="colon"></div>
<!-- 分钟十位 -->
<div class="column" :class="{ animation: col3 }" ref="col3">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
<!-- 分钟各位数 -->
<div class="column" :class="{ animation: col4 }" ref="col4">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">6</div>
<div class="num" :class="{ android: isArd }">7</div>
<div class="num" :class="{ android: isArd }">8</div>
<div class="num" :class="{ android: isArd }">9</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
<div class="colon"></div>
<!-- 秒钟十位数 -->
<div class="column" :class="{ animation: col5 }" ref="col5">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
<!-- 秒钟个位数 -->
<div class="column" :class="{ animation: col6 }" ref="col6">
<div class="num" :class="{ android: isArd }">0</div>
<div class="num" :class="{ android: isArd }">1</div>
<div class="num" :class="{ android: isArd }">2</div>
<div class="num" :class="{ android: isArd }">3</div>
<div class="num" :class="{ android: isArd }">4</div>
<div class="num" :class="{ android: isArd }">5</div>
<div class="num" :class="{ android: isArd }">6</div>
<div class="num" :class="{ android: isArd }">7</div>
<div class="num" :class="{ android: isArd }">8</div>
<div class="num" :class="{ android: isArd }">9</div>
<div class="num" :class="{ android: isArd }">0</div>
</div>
</div>
</template>
<script>
export default {
name: "TimeClock",
props: {
activityInfo: {
type: Object,
default() {
return {
endTime: "",
type: ""
};
}
}
},
data() {
return {
fontSize: "0.26rem",
nowTime: new Date(),
classList: ["visible", "close", "far", "far", "distant", "distant"],
lastEndtime: 0,
timer: null,
col1: true,
col2: true,
col3: true,
col4: true,
col5: true,
col6: true,
// 是否为安卓手机
isArd: false
};
},
watch: {
activityInfo(val) {
if (this.timer) {
clearInterval(this.timer);
}
const endTime = val.endTime;
// 在这里触发定时器 能获取最新的endTime ,但在触发结束事件 timeOver 作判断防止死循环
this.run(endTime);
}
},
created() {
this.isArd = this.isAndroid();
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer);
}
},
methods: {
isAndroid() {
const ua = navigator.userAgent.toLowerCase();
if (ua.match(/android/i) == "android") {
return true;
} else {
return false;
}
},
padClock(n, i) {
n = parseInt(n) > 9 ? n + "" : String(n).padStart(2, "0");
i = parseInt(i) > 9 ? i + "" : String(i).padStart(2, "0");
return n + i;
},
getClock(surplusTime) {
// 858631309
let hours = Math.floor(surplusTime / (1000 * 3600)),
// 计算小时候的剩余 毫秒数
leave1 = surplusTime % (1000 * 3600),
// 分钟
minutes = Math.floor(leave1 / (1000 * 60)),
// 分钟后剩余的毫秒数
leave2 = leave1 % (1000 * 60),
// 秒
seconds = Math.floor(leave2 / 1000);
return [hours, minutes, seconds].reduce(this.padClock);
},
getClass(n, i2) {
return (
this.classList.find(function(class_, classIndex) {
return i2 - classIndex === n || i2 + classIndex === n;
}) || ""
);
},
run(endTime = "0") {
const self = this;
let columns = ["col1", "col2", "col3", "col4", "col5", "col6"],
fontSize = 0.4,
lastTimeNums = "";
this.timer = setInterval(() => {
let surplusTime = new Date(endTime) - new Date(),
timenums = this.getClock(surplusTime);
if (surplusTime <= 0) {
clearInterval(this.timer);
// 倒计时结束后,通知父组件
// console.log("endTime", endTime);
if (endTime != "0" && self.lastEndtime != endTime) {
this.$emit("timeOver", this.activityInfo.type);
}
self.lastEndtime = endTime;
return false;
}
columns.forEach((ele, i) => {
let n = parseInt(timenums[i]),
cuRef = this.$refs[ele],
len = cuRef.children.length,
// 每个格子的高度
offset = -n * fontSize;
if (lastTimeNums[i] != n) {
if (n == len - 2) {
this[ele] = false;
// 安卓手机bug
this.$nextTick(() => {
cuRef.style.transform = `translateY(${-(len - 1) *
fontSize}rem)`;
});
setTimeout(() => {
this[ele] = true;
// 安卓手机bug
this.$nextTick(() => {
cuRef.style.transform = `translateY(${offset}rem)`;
});
// 大于浏览器的帧数
}, 30);
} else {
cuRef.style.transform = `translateY(${offset}rem)`;
}
}
});
lastTimeNums = timenums;
//
}, 1000);
}
}
};
</script>
<style lang="less" scoped>
// @isArd: `navigator.userAgent.toLowerCase() .match(/ android/i) == "android" `;
.time {
height: 0.4rem;
overflow: hidden;
.column {
display: inline-block;
vertical-align: top;
font-size: 0.26rem;
color: #fff;
width: 0.24rem;
text-align: center;
margin-left: 0.05rem;
// position: relative;
}
.colon {
width: 0.16rem;
display: inline-block;
font-size: 0.26rem;
line-height: 0.4rem;
}
.column:nth-of-type(1) {
margin-left: 0;
}
.animation {
transition: transform 300ms;
}

.num {
-webkit-transition: opacity 500ms, text-shadow 100ms;
transition: opacity 500ms, text-shadow 100ms;
text-align: center;
height: 0.4rem;
line-height: 0.4rem;
width: 100%;
// opacity: 0.025;
opacity: 1;
box-sizing: border-box;
padding-left: 0.02rem;
}

.android {
padding-top: 0.02rem;
}

.num.visible {
opacity: 1;
text-shadow: 1px 1px 0px #336699;
}

.num.close {
opacity: 0.35;
}

.num.far {
opacity: 0.15;
}

.num.distant {
opacity: 0.1;
}
}
</style>
1234…15
陈虎

陈虎

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

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