机器学习实例——室内定位

背景介绍:

 使用监督学习,利用在位置上获取wifi列表的强度,来预测当前所处的房间。是一个多分类的监督学习例子。

数据准备:

locating_data.csv 用来训练的数据
locating_test.csv 用来测试预测结果准确率
 准备了一份wifi强度的数据,同时打上了area(区域数据), shanghai(上海房),zhuhai(珠海房), man(男厕), women(女厕)标签。
也就是将室内分为四个房间的数据和四个房间以外的数据。

工具准备: Jupyter Notebook

  • 数据读取与处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #引入包
    import pandas as pd
    # 设置输出所有的变量
    from IPython.core.interactiveshell import InteractiveShell
    InteractiveShell.ast_node_interactivity = "all"
    #读取数据
    train_data = pd.read_csv('conver_locating_data.csv')
    test_data = pd.read_csv('conver_locating_result.csv')
    train_data = train_data.fillna(0) #将空值进行填充为0
    test_data = test_data.fillna(0) #测试数据做相同处理
    train_data.head() #输出查看结果

image

  • 提取特征,13个wifi的强度作为训练的特性
1
2
3
4
5
6
7
train_x = train_data[['wifi1','wifi2','wifi4','wifi5','wifi6','wifi7','wifi8','wifi9','wifi10','wifi11','wifi12','wifi13']]
train_y = train_data['result']
# test data
test_x = test_data[['wifi1','wifi2','wifi4','wifi5','wifi6','wifi7','wifi8','wifi9','wifi10','wifi11','wifi12','wifi13']]
test_y = test_data['result']
train_x.head(2)
train_y.head(2)

image

  • 使用sklearn的多分类算法进行训练
1
2
3
4
5
from sklearn.multiclass import OutputCodeClassifier
from sklearn.svm import LinearSVC
clf = OutputCodeClassifier(LinearSVC(random_state=0),
code_size=2, random_state=0)
clf.fit(train_x,train_y); #喂入训练输入和输出数据
  • 将测试数据输入进行预测结果
1
2
preds = clf.predict(test_x)
preds.head()
  • 计算结果正确率,将准备好的正确结果test_y和预测到的结果preds,进行计算
1
2
3
from sklearn.metrics import accuracy_score
score = accuracy_score(test_y, preds)
print(score)

image

  • 将预测结果以csv格式导出
1
2
3
4
submission = pd.DataFrame({
'label': preds
})
submission.to_csv('predit_result.csv', index=False)

 以上是一个简单的监督学习的例子,使用13个wifi的强度进行位置的预测。


作者: Jessy Hong

机器学习基础知识

1. 什么是机器学习

 机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。
 机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。机器学习算法是一类从数据中自动分析获得规律,并利用规律对未知数据进行预测的算法。
举个简单的例子:
天气预测:(以下数据只为说明例子,无科学依据)

相对湿度 是否下雨
60%
65%
65%

 机器学习使用一定的算法对这些数据进行计算。
 例如这里:当湿度较高的时候那天就是下雨的。如果我想知道第二天是否下雨,我可以通过湿度去预测。

2. 机器学习分类

2.1 监督学习

 监督学习从给定的训练数据集中学习出一个函数,当新的数据到来时,可以根据这个函数预测结果。监督学习的训练集要求是包括输入和输出,也可以说是特征和目标。
 简单地说就是给定一组数据,我们知道正确的输出结果应该是什么样子。最简单的就是真和假的学习。要么是真,要么是假。我们已经知道输出的结果只能是真或者假。

2.2 无监督学习

 无监督学习与监督学习相比,训练集没有人为标注的结果。
 无监督学习使用无历史标签的数据。系统不会被告知“正确答案”。不需要给数据打标签的基础上,做数据挖掘。无监督学习主要体现在聚类(clustering)上。

总之,有标签的就是有监督学习,反之无标签的就是无监督学习

2.3 半监督学习

 半监督学习介于监督学习与无监督学习之间。
 半监督学习和它的名字一样,同时用了有监督学习的方法和无监督的方法,更准确的说是同时用了标记好的数据和未标记的数据。

2.4 增强学习

 增强学习经常被用于机器人,游戏和导航。通过强化学习,该算法通过试验和错误发现行动产生的最大回报。

3. 机器学习开发工具

3.1 Anaconda:

image
 Anaconda是一个用于科学计算的Python发行版,提供了包管理与环境管理的功能,
可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。

3.2 Jupyter Notebook:

image
 网页版开发编辑器.它是一个非常灵活的工具,有助于帮助我们构建很多可读的分析,
可以在里面保留代码,运行结果,图片,公式和绘制的图像。
方便我们分享给其他人查看我们的结果。
注意:直接安装anacanda,anacanda里面就已经包含了Jupyter Notebook组件。

4. 科学计算相关包

  • NumPy:科学计算工具包,提供强大的N维数组对象,成熟的函数库。
  • Matplotlib:提供了很多图表控件,方便进行数据可视化。
  • Pandas:提供了高性能的,简单易用的数据结构和数据分析工具。
  • Scikit-learn:机器学习库,其中包含大量机器学习算法、数据集,是数据挖掘方便的工具

作者: Jessy Hong

图表绘制的选择Echarts, D3, C3, SVG

那些年画过的图表

1. echarts http://echarts.baidu.com/

image
折线图和Element 滑块组成的图标,可以互相控制。

2. c3 http://c3js.org/

image
多条数据的折线图,不同段填充不同的背景颜色,灰、蓝、白。以及在一点位置绘制竖向分隔。

3. svg

image

4. D3.js https://d3js.org/

相当于是svg的jQuery,它的API 灵活且可定制性高,这是它的一大优点,缺点是上手难度偏大,学习成本偏高。

5. 说一说以上四者的区别:

  • Echarts 使用很方便,只是传入参数就可以绘制。
    但是一旦它提供的图表不符合你的需要,就分分钟炸了。Echarts是使用canvs绘制的,生成的是一张图片。想改相当的麻烦。

  • C3.js 是对D3.js进行了封装,与echarts类型,只需要往generate函数中传入数据对象就可以轻松的绘制出图表,方便开发者使用。同时它绘制的图表是真实的操作dom的,因此对于后期对图表的修改也是相对简单的。

  • svg 好处就是不用引第三方库了,HTML5自带的。绘制就需要一个个图形绘制了,可以随心所欲。绘制简单的图表比较适合。

  • D3.js 定制性高,使用SVG进行绘制。与SVG类似,同样需要自己写出图形拼成图表。API很多,图形丰富。适合复杂,自定义要求高的图表。
    它不像echarts/c3那样传入参数就可以绘制,上手难度偏大。

6. leaflet https://leafletjs.com/

是领先的开源JavaScript库,为移动设备设计的互动地图
image


作者: Jessy Hong

vue1和vue2组件通信

1. 父组件向子组件通信

props属性(vue1.x和vue2.x )

//父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div id="app">
<img class="logo" src="./assets/logo.png">
<hello from-father="I am from father"></hello>
</div>
</template>
<script>
import Hello from './components/Hello'
export default {
components: {
Hello
}
}
//子组件
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div class="hello">
<h1>{{ fromFather }}</h1>
</div>
</template>
<script>
export default {
props: ["fromFather"],
data () {
return {
}
}
}

2. 子组件向父组件通信:

2.1 $emit()触发事件,$on()监听事件(vue1.x和vue2.x )

//父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div class="hello">
<hello-world @child-click="receiveData"></hello-world>
</div>
</template>
<script>
import HelloWorld from './HelloWorld.vue'
export default {
name: 'Home',
components: {HelloWorld},
data () {
return {
}
},
methods:{
receiveData(data){
console.log(data); //I am from child
}
},
}
</script>

//子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="hello">
<button @click="onClick">Click</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
}
},
methods:{
onClick(){
this.$emit('child-click', 'I am from child');
}
},
}},
}

 在子组件向父组件通信借助了事件$emit() ,子组件在click事件里面:
this.$emit('child-click', 'I am from child');,传递了事件名称 "child-click" 和参数 “I am from child” 给父组件,在父组件中打印出来

3. $dispatch 和 $broadcast(vue 1.x )

向上派发事件 和 向下广播事件; vue 2.x中已经弃用

$dispatch:

派发事件,首先在实例上触发它,然后沿着父链向上冒泡在触发一个监听器后停止,除非它返回 true。

$broadcast:

广播事件,通知给当前实例的全部后代。因为后代有多个枝杈,事件将沿着各“路径”通知。每条路径上的通知在触发一个监听器后停止,除非它返回 true。
//父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div id="app">
<img class="logo" src="./assets/logo.png">
<hello></hello>
<button @click="clickBtn">点击</button>
</div>
</template>
<script>
import Hello from './components/Hello'
export default {
components: {
Hello
},
created () {
this.$on("son-dispatch", function (data) {
console.log(data);
})
},
methods:{
clickBtn(){
this.$broadcast("father-broadcast","I ma from father")
}
},
}

//子组件

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
<template>
<div class="hello">
<button @click="clickBtn">点击</button>
</div>
</template>

<script>
export default {
data () {
return {
msg: 'Hello World!'
}
},
created(){
this.$on("father-broadcast",function (data) {
console.log(data);
})
},
methods:{
clickBtn (){
//派发事件
this.$dispatch("son-dispatch","I am from son")
},
},
}
</script>

4. 兄弟组件通信: Event Bus

 适用于通信不是很复杂的小型项目
 Event Bus是在2.x的文档中才提到的,事实上1.x一样可以使用。
  Bus,其实是创建一个公共的实例,然后使用$on监听,使用$emit触发来进行通信的。

  •  1. 创建公共实例文件:eg:bus.js
1
2
import Vue from 'vue'
exports.bus = new Vue()
  •  2. 组件A,$emit触发事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div class="hello">
<button @click="clickBtn">Hello点击</button>
</div>
</template>
<script>
import {bus} from './../utils/bus.js'
export default {
methods:{
clickBtn (){
//触发事件
bus.$emit('click-btn','I am click button');
}
}
}
</script>
  • 3.组件B, $on监听事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div class="hello">
</div>
</template>
<script>
import {bus} from './../utils/bus.js'
export default {
created(){
bus.$on("click-btn", function (data) {
console.log(data) //I am click button
})
}
}
</script>

 如果是大型项目,通信更为的复杂。我们可以通过官方提供的 Vuex 轻松管理各组件之间通信问题。

总结:

方式 说明 适用版本
props属性 父组件向子组件传递 Vue1.x
Vue2.x
$on(事件名) 事件名的类型是字符串(下同),调用它可以通过this.$on()来调用 Vue1.x
Vue2.x
$emit(事件名, 参数) 用于触发事件,参数是用于传递给事件的参数。这个用于触发同级事件(当前组件的) Vue1.x
Vue2.x
$dispatch(事件名, 参数) ①向上派发事件,用于向父组件传播。
②会首先触发当前组件的同名事件(如果有);
③然后会向上冒泡,当遇到第一个符合的父组件的事件后触发并停止;
④当父组件的事件的返回值设为true会继续冒泡去找下一个。
Vue1.x
$broadcast(事件名, 参数) ①向下广播事件,用于向所有子组件传播。
②默认情况是仅限子组件;
③子组件事件的返回值是true,才会继续向该子组件的孙组件派发;
④不会触发自身同名事件
Vue1.x
Event Bus Bus 实现非父子组件的通信,$on / $emit实现 Vue1
Vue2
Vuex Vuex 专为 Vue.js 应用程序开发的状态管理模式。Vuex相当于一个仓库,管理着所有组件的公共数据 Vue2.x
Vue1.x(不建议)

作者: Jessy Hong

vue checkbox使用v-model和@click遇到的坑

vue checkbox使用v-model@click遇到的坑

1. 问题描述:

  • 使用v-model="value"对checkbox进行了绑定,同时监听checkbox 的click事件,在click方法中使用了this.value取值。发现不同浏览器下,取到的this.value的值是不同的。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="hello">
<input type="checkbox" v-model="checkboxValue" @click="onClick"/>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
checkboxValue: false
}
}
methods:{
onClick(){
console.log(this.checkboxValue);
}
}
}

 以上代码默认checkbox是未选中状态,value是false。
当点击Checkbox选中的时候,会进入onClick的方法中。
 发现不同浏览器读取的this.checkboxValue的值是不同的

Firefox / Chrome
打印输出: false
IE:
打印输出: true

 也就是说在Firefox/Chrome浏览器下,是先执行click方法,然后再对checkboxValue进行赋值。
 而在IE下,是先对checkboxValue进行赋值,然后在执行click方法。

2. 原因分析

 与v-model的语法糖有关,详情请看《v-model语法糖》

1
2
<input type="checkbox" v-model="sth" />
<input type="checkbox" :checked="checkboxValue" @change="checkboxValue= $event.target.checked" />

 第一行的代码其实只是第二行的语法糖。
 问题是:click方法中使用了变量this.checkboxValue,因此如果是先触发了change事件,对checkboxValue进行了赋值。之后再触发click那么获取的结果就是正确的。
 有了以上想法之后:对change,click事件做了实验
实验浏览器版本:

IE(11.0.9600.18977)
Firefox(52.7.3)
Chrome(66.0.3359.139)

 Firefox / Chrome: 先执行click事件,后执行change事件
 IE: 先执行change事件,后执行click事件

3. 解决方法

方法一:直接获取checked的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="hello">
<input type="checkbox" v-model="checkboxValue" @click="onClick($event)"/>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
checkboxValue: false
}
},
methods:{
onClick(event){
console.log(event.target.checked)
}
},
}

方法二:使用@change进行监听,等值变化了再使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="hello">
<input type="checkbox" v-model="checkboxValue" @change="onChange"/>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
checkboxValue: false
}
},
methods:{
onChange(){
console.log(this.checkboxValue)
}
},
}

作者: Jessy Hong

详解v-model:语法糖

v-model:语法糖

 vue的v-model为表单的完成提供了极大的便利,可以进行数据绑定,例如将input框的值和span值绑定,只要重新输入显示值会立即更改。下面我们来分析这一命令是如何实现的。在官方文档中解释这一名令实际仅是一个语法糖。
那么首先我们来看看语法糖的概念:

语法糖:指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

1. v-model用在input元素上时

1
<input v-model="something" />
1
<input v-bind:value="something" v-on:input="something= $event.target.value" />

 第一行的代码其实只是第二行的语法糖。然后第二行代码还能简写成这样:

1
<input :value="something" @input="something= $event.target.value" />

 要理解这行代码,首先你要知道 input 元素本身有个 oninput 事件,这是 HTML5 新增加的,类似 onchange ,每当输入框内容发生变化,就会触发 oninput ,把最新的value传递给 something。

 也就是v-model=”something”则表示将value值绑定在something上,当值发生改变时触发绑定的oninput事件。oninput事件绑定的函数是将触发oninput事件的目标(该input)的value值赋值给something这个变量。

 我们仔细观察语法糖和原始语法那两行代码,可以得出一个结论:
 在给input元素添加 v-model 属性时,将value值绑定在something变量上,当值发生改变时触发绑定的oninput事件,oninput事件绑定的函数是将触发oninput事件的目标的value值赋值给something这个变量。

2. v-model 用在组件上时

 v-model 不仅仅能在 input上用,在组件上也能使用。
从v-model的实现原理,我们知道要在组件中使用时,它相当于下面的简写:

1
<custon-input v-bind:value="something" v-on:input="something=arguments[0]"></custom-input>

所以要让组件的v-model生效,它应该:

  • 1. 接受一个value属性
  • 2. 在有新的值时触发input事件

 代码如下:自定义一个不能输入负数的input框

  • custon-input组件
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
<template>
<div>
<input :value="value" @input="updateValue($event.target.value)"/>
</div>
</template>
<script>
export default {
name: 'CustonInput',
props: ['value'],
data () {
return {
checkboxValue: false
}
},
methods:{
updateValue(value){
if (value < 0) {
this.$emit("input", 0) //值小于0时候,赋值为0
}else{
this.$emit("input", value) //触发input事件,父组件接收input事件
}
}
}
}
</script>
  • //父组件中使用
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
<template>
<div>
<custon-input v-model="custonValue"></custon-input>
</div>
</template>

<script>
import CustonInput from './CustonInput.vue'
export default {
name: 'Home',
components: {CustonInput},
data () {
return {
custonValue: '10', //给一个默认值
}
},
methods:{
receiveData(data){
console.log(data); //I am from child
}
},
watch:{
custonValue (val) {
console.log(val)
}
}
}
</script>

3. v-model 的缺点和解决办法

 在创建类似复选框或者单选框的常见组件时,v-model就不好用了。
 Vue 1.x版本中:checkbox使用v-model不起效

1
<input type="checkbox" v-model="sth" />

 v-model 给我们提供好了 value 属性和 oninput 事件,但是,我们需要的不是 value 属性,而是 checked 属性,并且当你点击这个单选框的时候不会触发 oninput 事件,它只会触发 onchange 事件。这就尴尬了

 因为 v-model 只是用到了 input 元素上,所以这种情况好解决:

1
<input type="checkbox" :checked="status" @change="status = $event.target.checked" />

 Vue 2.x版本中,可以使用v-model实现checkbox的双向绑定。

1
<input type="checkbox" v-model="sth" />

 在使用checkbox中遇到的坑,详情见《vue checkbox使用v-model和@click遇到的坑》


作者: Jessy Hong

Less的基本用法

1. 变量(Variables)

1
2
3
4
5
//less
@nice-blue: #5B83AD;
.container {
color: @nice-blue;
}
1
2
3
4
//生成的css
.container {
color: #5B83AD;
}

2. 混合(Mixins)

 混合可以将一个定义好的class A轻松的引入到另一个class B中,从而简单实现class B继承class A中的所有属性。

1
2
3
4
5
6
7
8
//less
.bordered {
border: solid 2px black;
}
.container {
color: @nice-blue;
.bordered;
}
1
2
3
4
5
//生成的css
.container {
color: @nice-blue;
border: solid 2px black;
}

3. 嵌套(Nesting)

 在一个选择器中嵌套另一个选择器来实现继承。

1
2
3
4
5
6
7
//less
.container{
color: #5B83AD;
.logo{
color: red;
}
}
1
2
3
4
5
6
7
//生成的css
.container{
color:#5B83AD;
}
.container .logo{
color: red;
}

&符号

 表示当前的选择器,写串联选择器,而不是写后代选择器,就可以用到&了.
 这点对伪类尤其有用如:hover 和 :focus.

1
2
3
4
5
6
7
//less
.container{
color:#5B83AD;
&:hover{
color:red;
}
}

1
2
3
4
5
6
7
//生成的css
.container{
color:#5B83AD;
}
.container:hover{
color:red;
}

4. 运算(Operations)

 运算提供了加,减,乘,除操作;任何数字、颜色或者变量都可以参与运算.

1
2
3
4
5
6
7
//less
@the-border: 1px;
@base-color: #666;
.container{
color: @base-colo * 2;
solid @the-border * 2 red;
}
1
2
3
4
5
//生成的css
.container{
color: #333;
border: solid 2px red;
}

less解析calc()问题

问题描述:

 在less中 calc(100% - 30px) 等带单位混合运算会被less解析忽略单位,全部按照百分比计算,
此例中的计算被less编译成calc(70%)

1
2
3
.container{
width: calc(100% - 30px)
}
1
2
3
4
//less解析成
.container{
width: calc(70%);
}
原因分析:

 less的计算方式跟calc方法有重叠,两者在一起有冲突

解决方案:

 把calc()里面的表达式加上~”“包起来。

1
2
3
.container{
width : calc(~"100% - 30px");
}
1
2
3
4
//解析成
.container{
width : calc(100% - 30px);
}

 进行数值和变量之间的运算可以这样设置:

1
2
3
4
@var = 50px;
.container{
width: calc(~"100% - @{var}")
}
结论:
  • less中 “~” 符号后面双引号里面的内容会被less编译忽略,而直接输出为css代码
  • less中@和{}配合可以在字符串里面使用变量,很像es6里面的模板字符串 `${}`

作者: Jessy Hong

单行、多行文本溢出省略号

单行文本溢出显示省略号:

 用text-overflow:ellipsis属性来,当然还需要加宽度width属来兼容部分浏览。

1
2
3
4
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
width: 100px;

重点说一下多行文本溢出显示省略号:

方法一: -webkit-line-clamp

1
2
3
4
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;

适用范围:
 因使用了WebKit的CSS扩展属性,该方法适用于WebKit浏览器及移动端。(Firefox/IE不起作用
注:

  • -webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:
  • display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
  • -webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。

方法二: after:content方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
p{
width: 200px;
border: solid 1px red;
position: relative;
line-height: 20px;
max-height: 40px;
overflow: hidden;
&:after{
content: "...";
position: absolute;
bottom: 0;
right: 0;
padding-left: 40px;
background: white;
}
}
缺点:
  1. 当文字未超出行的情况下也会出现省略号。
    image

2.并且”…”可能把字符覆盖了一半。
image

方法三: JavaScript的方式,根据像素截取字符串

 原理就是将字符串挂到dom上进行渲染,然后通过dom获取渲染后的元素宽度。就是每个字符真正的像素大小。
 传入参数:字符串 str, font-size,限制像素:比如2行每行200px,那么就是2 x 200 = 400。
这里要注意因为…也会占用一定的像素所以要自己做相应的调整。比如limitPixels设置成400 - 40 = 360px。
 方法的返回值就是通过计算截取后的字符串:如果字符超出了像素限制,那么就会补省略号…。否则不补。
代码实现如下:

1
<p>{{calcStringPixelsCount('多行文本溢出: 文字很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长', 14, 360)}}</p>
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
calcStringPixelsCount (data, strFontSize, limitPixels) {
let stringCharsCount = data.length;
let stringPixelsCount = 0;
let elementPixelsLengthRuler = document.getElementById('hidden-text');
let targetStr = '';
if (!document.getElementById('hidden-text')) {
elementPixelsLengthRuler = document.createElement('span');
elementPixelsLengthRuler.setAttribute('id', 'hidden-text');
elementPixelsLengthRuler.style.fontSize = strFontSize;
elementPixelsLengthRuler.style.visibility = 'hidden';
elementPixelsLengthRuler.style.display = 'inline-block';
elementPixelsLengthRuler.style.wordBreak = 'break-all';
document.body.appendChild(elementPixelsLengthRuler);
}
for (let i = 0; i < stringCharsCount; i++) {
if (data[i] === ' ') {
elementPixelsLengthRuler.innerHTML = '&nbsp;';
}
else {
elementPixelsLengthRuler.innerHTML = data[i];
}
stringPixelsCount += elementPixelsLengthRuler.offsetWidth;
if (stringPixelsCount <= limitPixels) {
targetStr = targetStr.concat(data[i]);
}
}
return `${targetStr}...`;
},

 效果如下图:
image


作者: Jessy Hong

css3 background背景属性详解

CSS3 background属性

描述
background-color 规定要使用的背景颜色。
background-position 规定背景图像的位置。
background-size 规定背景图片的尺寸。
background-repeat 规定如何重复背景图像。
background-origin 规定背景图片的定位区域。
background-clip 规定背景的绘制区域。
background-attachment 规定背景图像是否固定或者随着页面的其余部分滚动。
background-image 规定要使用的背景图像。
inherit 规定应该从父元素继承 background 属性的设置。

语法:

1
background:bg-color bg-image position/bg-size bg-repeat bg-origin bg-clip bg-attachment initial|inherit;

 准备两张背景图片:第一张是透明无背景的bkg1.jpg,第二张bkg2.jpg
image

1. background-image 背景图片

 设置背景图片,可以设置一到多张背景图像

1
2
3
4
#example1 { 
background-image: url("./img/bkg1.jpg"), url("./img/bkg2.jpg");
background-position: right bottom, left top;
}

 CSS3 允许你在元素上添加多个背景图像,不同的背景图像和图像用逗号隔开,所有的图片中显示在最顶端的为第一张。也可以给不同的图片设置多个不同的属性。用逗号隔开。
 以上的设置我们可以看到bkg1.jpg显示在顶端,bkg2.jpg显示在下方。效果如下图:
image

2. background-color 背景颜色

 有多种方式指定颜色

1
2
3
background-color: red;   
background-color: rgb(255, 0, 0);
background-color: #ff0000;

3.background-repeat 背景平铺

 设置背景图片时,默认把图片在水平和垂直方向平铺以铺满整个元素。

1
2
3
4
5
background-repeat: repeat; /* 默认值,在水平和垂直方向平铺 */  
background-repeat: no-repeat; /* 不平铺。图片只展示一次。 */
background-repeat: repeat-x; /* 水平方向平铺(沿 x 轴) */
background-repeat: repeat-y; /* 垂直方向平铺(沿 y 轴) */
background-repeat: inherit; /* 继承父元素的 background-repeat 属性*/

 repeat效果如下图:水平方向和垂直方向都会出现重复的背景图片,沿着x,y轴平铺:
image

4.background-position 背景定位

 属性用来控制背景图片在元素中的位置。技巧是,实际上指定的是图片左上角相对于元素左上角的位置。参数可以是数值,百分比,也可以是关键词
水平方向:left /right/center
垂直方向:top/center/bottom
 为了效果明显一点,把背景图片设置得比div容器小一些:

1
2
3
4
5
6
background-size: 300px 200px;
background-repeat: no-repeat;
background-position: 0 0; #默认值 元素的左上角
background-position: 100px 50px; #图片向右移动100px,向下移动50px
background-position: 50% 50%;
background-position: center bottom; #关键词

image

5.background-clip 背景剪裁

 CSS3中background-clip背景剪裁属性是从指定位置开始绘制。
content-box, padding-box, border-box

说明
border-box 默认值。背景绘制在边框方框内(剪切成边框方框)。
padding-box 背景绘制在衬距方框内(剪切成衬距方框)。
content-box 背景绘制在内容方框内(剪切成内容方框)。

 可以看下图效果:clip是剪裁的方式,也就是说每个背景内的内容是会被剪裁掉的。背景中顶部的花朵会被随着clip属性值的变化而被截取。
image

6. background-origin 位置区域

 background-origin属性指定了背景图像的位置区域。
 content-box, padding-box,和 border-box区域内可以放置背景图像。
 可以看下图效果:origin是指定背景图片的位置区域,并不会改变背景图的内容。每一张图的背景图中的花朵内容都是一样的。可以对比background-clip中的图片。

image

7. background-blend-mode 混合模式

 background-blend-mode属性定义了背景层的混合模式(图片与颜色)。

描述
normal 默认值。设置正常的混合模式。
multiply 正片叠底模式。
screen 滤色模式。
overlay 叠加模式。
darken 变暗模式。
lighten 变亮模式。
color-dodge 颜色减淡模式。
saturation 饱和度模式。
color 颜色模式。
luminosity 亮度模式。

 可以自己混合出很好看的样式:如下图:

1
2
background-color: #270526de;
background-blend-mode: color-dodge;

image

8. background-attachment 背景附着

 background-attachment设置背景图像是否固定或者随着页面的其余部分滚动。

说明
scroll 背景图片随页面的其余部分滚动。这是默认
fixed 背景图像是固定的
inherit 指定background-attachment的设置应该从父元素继承

 当设置 background-attachment 为 fixed 时,当页面向下滚动时,背景要待在它原来的位置(相对于浏览器来说)。也就是不随元素滚动。因此当元素滚动时,看到的就是背景图片的垂直方向有所变化。
 当设置 background-attachment 为 scroll时,当页面向下滚动时,背景要随着元素向下滚动。不管元素如何滚动,背景图片都是跟着边框一起的。不会有所变化
两者的效果如下图所示:
image

9. background-size 背景大小

语法:

1
background-size: auto || <length> || <percentage> || cover || contain

描述
auto 此值为默认值,保持背景图片的原始高度和宽度;
length 设置背景图片高度和宽度。第一个值设置宽度,第二个值设置的高度。如果只给出一个值,第二个是设置为 auto(自动)
percentage 将计算相对于背景定位区域的百分比。第一个值设置宽度,第二个值设置的高度。如果只给出一个值,第二个是设置为”auto(自动)”
cover 此时会保持图像的纵横比并将图像缩放成将完全覆盖背景定位区域的最小大小。此值是将图片放大,以适合铺满整个容器。
contain 此时会保持图像的纵横比并将图像缩放成将适合背景定位区域的最大大小。其主要是将背景图片缩小,以适合铺满整个容器

作者: Jessy Hong

JavaScript闭包的理解和用途

1. 什么是闭包?

 在了解闭包之前,应当了解一下JavaScript的作用域和作用域链的概念。详细可看《JavaScript作用域及作用域链的详解》
 闭包就是能够读取其他函数内部变量的函数。
 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。
 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

2.从代码理解闭包

1
2
3
4
5
6
7
8
var scope = "global scope"; //全局变量
function checkscope(){
var scope = "local scope"; //局部变量
function f(){return scope} //返回local scope
return f
}
var C = checkscope() //返回local scope
C()

 这是简单的闭包,函数checkscope的内部函数f被函数checkscope外的一个变量C引用。C能够读取checkscope函数内部变量的函数f。
这就形成了闭包的概念,闭包就是能够读取其他函数内部变量的函数

3.闭包的用途

3.1 用闭包模拟私有方法,私有变量

 使用闭包来定义公共函数,并令其可以访问私有函数和变量

以下使用例子Counter,实现一个计数器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var Counter = (function() {
var privateCounter = 0; //私有变量
function changeBy(val) { //私有方法
privateCounter += val;
}
return {
increment: function() { //计数器加1
changeBy(1);
},
value: function() {
return privateCounter;
}
}
})();
Counter.value(); //公有方法
Counter.increment(); //公有方法
Counter.privateCounter() //undefined

 Counter包含两个私有项:名为privateCounter的变量和名为 changeBy的函数。这两项都无法在这个匿名函数外部直接访问。必须通过匿名函数返回的两个公共函数访问。

3.2 立即执行函数

a.什么是立即执行函数?

 立即执行函数表达式,Immediately-Invoked Function Expression,简写为IIFE

b.立即执行函数的作用?

 IIFE只有一个作用:创建一个独立的作用域
 因为JavaScript中只有全局作用域和函数作用域。为了避免变量的污染,尽可能地少设置全局变量。所以我们就用立即执行函数表达式。

c.IIFE的经典场景
1
2
3
4
5
6
7
8
9
var arr = [];
for(var i = 0; i< 5; i++){
(function(i){
arr[i] = function(){
return i;
}
})(i)
}
arr[2]() // 2
d.闭包与立即执行函数表达式的关系

 闭包与立即执行函数它们是合作的关系,经常会看到立即执行函数中会存在函数,那这个函数就是闭包了

3.3. 封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var person=function()
{
var name='Jessy';// 定义成员函数,封装属性,外界无法直接使用
return{
setName:function(data)
{
name=data;
},
getName:function()
{
return name;
}
}
}();
person.name//undefined,不能访问
person.getName()//只能通过get/set方法调用
person.setName('Jessy')

3.4. 实现类和继承

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
//Person 类
function Person(){
var name = "Jessy";
return{
setName:function(data)
{
name=data;
},
getName:function()
{
return name;
}
}
}
//定义子类
var Jessy = function(){}
//集成Person类
Jessy .prototype = new Person()
//定义子类方法
Jessy.prototype.eat = function(){
console.log("eat.....");
}
var jessy = new Jessy()
//子类实例可以方法自身定义的eat方法和从父类中继承而来的setName/getName
jessy.eat()
jessy.getName()
jessy.setName("Jessy")

作者: Jessy Hong