wj'blog


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索

js实现二叉树及遍历

发表于 2017-09-28 | 分类于 JavaScript

什么是二叉树

今天在做百度前端技术学院的任务时,遇到一题涉及二叉树算法的,然而我是一脸懵逼,因为没接触过二叉树算法,所以无存下手。后来上网找资料,渐渐明白了是个什么东西。

这是一篇关于二叉树的详细介绍文章

搞清楚了二叉树是啥,然后怎么实现呢,显然,我需要用js实现,于是又各种找资料,实话说,资料还挺多的,不过也很杂,现在做个总结。

js实现二叉树

说明:将一个数组的值按照二叉树规则遍历,形成二叉树结构。

代码如下:

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

function BinaryTree(){

//定义新节点的构造函数
function Node(text){
this.text = text;
this.left = null;
this.right = null;
}

//定义根节点
var root = null;

//判断根节点
this.insert = function(text){
var newNode = new Node(text);
if (root === null) {
root = newNode;
}else{
insertNode(root,newNode);
}
};


//中间节点的处理函数
function insertNode(node,newNode){

if (newNode.text < node.text) {
if (node.left === null) {
node.left = newNode;
}else{
insertNode(node.left,newNode);
}
}else{
if (node.right === null) {
node.right = newNode;
}else{
insertNode(node.right,newNode);
}
}

}



//定义数组用来存储各节点的数值
var nodes = [8,3,10,1,6,14,4,7,13];

//创建二叉树实例
var binaryTree = new BinaryTree();

//遍历数组,将数组值按照二叉树规则插入
for(var i=0;i<nodes.length;i++){
binaryTree.insert(nodes[i]);
}

上面代码最终形成的二叉树结构如下图:
二叉树结构

规则说明:

  • 根据取到的数组值,先判断二叉树中根节点是否存在,如果不存在,就将第一个值作为根节点,即上述的8是根节点值。

  • 有了根节点后,再判断后面的值与根节点值大小关系。如果小于根节点值,且左边无值,就放在左边,如果左边已经有值,就回调遍历。如果大于根节点值,且右边无值,就放在右边,如果右边已经有值,就回调遍历。参考上面代码中insertNode函数

遍历

二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。

二叉树的遍历有三种方式,如下:

  1. 前序遍历(DLR),首先访问根结点,然后遍历左子树,最后遍历右子树。简记根-左-右。

  2. 中序遍历(LDR),首先遍历左子树,然后访问根结点,最后遍历右子树。简记左-根-右。

  3. 后序遍历(LRD),首先遍历左子树,然后遍历右子树,最后访问根结点。简记左-右-根。

在上述代码中的BinaryTree()中添加遍历接口( … 表示省略的代码 ):

中序遍历

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

function BinaryTree(){

//...

//中序遍历
this.inOrderTraverse = function(callback){
inOrderTraverseNode(root,callback);
}

function inOrderTraverseNode(node,callback){
if(node !== null){
inOrderTraverseNode(node.left,callback);
callback(node.text);
inOrderTraverseNode(node.right,callback);
}
}

//...

//定义回调函数,打印节点数值
var callback = function(text){
console.log(text);
}


}


//调用
binaryTree.inOrderTraverse(callback);

//打印结果
1 3 4 6 7 8 10 13 14

前序遍历

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

function BinaryTree(){

//...

//前序遍历
this.preOrderTraverse = function(callback){
preOrderTraverseNode(root,callback);
}

function preOrderTraverseNode(node,callback){
if (node !== null) {
callback(node.text);
preOrderTraverseNode(node.left,callback);
preOrderTraverseNode(node.right,callback);
}
}


//...

//定义回调函数,打印节点数值
var callback = function(text){
console.log(text);
}


}


//调用
binaryTree.preOrderTraverse(callback);

//打印结果
8 3 1 6 4 7 10 14 13

后序遍历

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

function BinaryTree(){

//...

//后序遍历
this.postOrderTraverse = function(callback){
postOrderTraverseNode(root,callback);
}

function postOrderTraverseNode(node,callback){
if (node !== null) {
postOrderTraverseNode(node.left,callback);
postOrderTraverseNode(node.right,callback);
callback(node.text);
}
}


//...

//定义回调函数,打印节点数值
var callback = function(text){
console.log(text);
}


}


//调用
binaryTree.postOrderTraverse(callback);

//打印结果
1 4 7 6 3 13 14 10 8

注意:遍历代码是写在BinaryTree()中的,部分代码已省略

关于JSONP跨域

发表于 2017-09-23 | 分类于 JavaScript

JSONP是干嘛的

提到JSONP,首先想到的就是AJAX,因为人们时常将它们放在一起说。那么,它们到底是什么关系呢?

其实它们本身并没有实质的关系,只是JSONP可以解决AJAX一件办不到的事情。哪件事情是AJAX办不到的?就是跨域!

简单来说,JSONP就是一种跨域的手段。

跨域:意思是说,在当前网址去获取另一个域下的数据。浏览器有一个“同源策略”——两个页面的域名必须在同域的情况下,才能允许通信。

所谓同源是指,域名,协议,端口相同。

浏览器的“同源策略”有效地阻止了很多危险行为,因为在没有“同源策略”的情况下,网站的信息可以被所有人任意获取,那么用户的隐私就受不到保护了,这是很可怕的。但事情有利有弊,“同源策略”也带来了麻烦,这时如果我们想从信任的网站获取数据,显然也做不到了。

JSONP怎么用

可能JSONP听起来很高大上,但其实其原理很简单,是我们每天都接触的。”同源策略”虽然很厉害,阻止了一个页面到另一个页面的通信,可是src指向的路径它放过了。提到src,我们再熟悉不过了,<img>、<script>和<iframe>都有src属性。JSONP就是利用<script>标签来实现跨域通信的。

讲一个简单的小例子:

现在假设有两个域,需要互相通信,分别是:www.aaa.com和www.bbb.com

www.aaa.com中:

1
2
3
4
5
6
7
8
<script src='http://www.bbb.com/abc.js'></script>
<script>

function abc(data){
alert(data['name']);
}

</script>

www.bbb.com/abc.js中:

1
abc({'name':'wungjyan','age':23});

结果页面弹出了wungjyan。

JSONP工作过程:通过<script>标签,获取到www.bbb.com/abc.js,里面有一个函数abc,函数会被加载到www.aaa.com。加载完成后,就执行abc函数,而在www.aaa.com中已经定义好了一个abc函数,函数里写了一些处理数据的语句。这样就简单地实现了跨域访问数据了,这也就是JSONP的原理了。

JSONP实例

运用JSONP做一个类似百度搜索下拉框。

在这之前,先取到百度的接口。

打开百度首页,在输入框随便输入点什么,比如,输入a,

打开Network,点击all,找到地址

这个地址是:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=a&json=1&p=3&sid=23534_1436_21084&req=2&csor=1&cb=jQuery110206731850454839907_1506167060552&_=1506167060555

只取本次实例需要的参数,精简为:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=a&cb=jQuery110206731850454839907_1506167060552&_=1506167060555

其中wd是关键字,即输入的内容,cb是回调函数,百度内定的,cb后面的是函数名,可以修改,相当于上面小例子中的abc函数。

现在就修改为abc,并输入到浏览器地址栏中,看看得到什么内容:

可以看到,这个abc函数里的参数是一个json数据,其中s就是我们需要的数据。

完整代码:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>百度下拉菜单</title>
<style type="text/css">
#text{
width: 300px;
height: 30px;
border:1px solid #6495ED;
line-height: 30px;
font-size: 16px;
}

#ul1{
margin: 0;
padding:0;
border:1px solid #6495ED;
border-top: none;
width: 300px;
display: none;
}
#ul1 li{
list-style: none;
margin-top: 5px;
}

#ul1 li a{
font-size: 16px;
color: #696969;
text-decoration: none;
}
</style>
</head>
<body>
<input type="text" id="text">
<ul id="ul1">

</ul>

<script>
//定义abc函数,添加数据处理程序
function abc(data){
var oUl=document.getElementById('ul1');
var html='';
if (data.s.length) {
oUl.style.display='block';
for(var i=0;i<data.s.length;i++){
html+="<li><a target='_blank' href='https://www.baidu.com/s?wd="+data.s[i]+"'>"+data.s[i]+"</a></li>";
}
oUl.innerHTML=html;
}else{
oUl.style.display='none';
}
}


var oT=document.getElementById('text');
var oBtn=document.getElementById('btn');
var oUl=document.getElementById('ul1');

oT.onkeyup=function(){
if (oT.value!='') {
var aScript=document.createElement('script');
aScript.src='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+oT.value+'&cb=abc';
document.body.appendChild(aScript);

if(aScript){ //避免过多script标签
document.body.removeChild(aScript);
}

}else{
oUl.style.display='none';
}
}



</script>
</body>
</html>

代码中,动态添加<script>标签,加载完成后就执行abc函数,使获取到的数据展示在页面中。

CSS特殊布局

发表于 2017-09-19 | 分类于 CSS

三列布局

三列布局的特征是两侧两列固定宽度,中间列自适应宽度。

1.margin + float

原理说明:设置两个侧栏分别向左向右浮动,中间列的宽度根据浏览器窗口自适应。对中间面板设置左右外边距,margin-left的值为左侧栏的宽度,margin-right的值为右侧栏的宽度。

DOM文档

1
2
3
<div id="left"></div>
<div id="right"></div>
<div id="center"></div>

CSS样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#left{
width: 200px;
height: 100px;
float: left;
background-color: red;
}
#right{
width: 100px;
height: 100px;
float: right;
background-color: yellow;
}
#center{
margin-left: 210px;
margin-right:110px;
height: 100px;
background-color: blue;
}

==注意==:DOM文档的书写顺序,先写两侧栏,再写中间主面板,更换后则侧栏会被挤到下一列

2.position + margin

原理说明:通过绝对定位将两个侧栏固定,中间列自适应。对中间面板设置左右外边距,margin-left的值为左侧栏的宽度,margin-right的值为右侧栏的宽度

CSS样式

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
body{
margin:0;
padding: 0;
}
#left{
width: 200px;
height: 100px;
position: absolute;
top: 0;
left: 0;
background-color: red;
}
#right{
width: 100px;
height: 100px;
position: absolute;
top: 0;
right: 0;
background-color: yellow;
}
#center{
height: 100px;
margin:0 110px 0 210px;
background-color: blue;
}

两列布局

原理和上面三列布局一样,去掉一个侧栏

1.margin + float

DOM文档

1
2
3

<div id="left"></div>
<div id="main"></div>

CSS样式

1
2
3
4
5
6
7
8
9
10
11
12
#left{
width: 200px;
height: 100px;
float: left;
background-color: red;
}

#main{
height: 100px;
margin-left: 210px;
background-color: blue;
}

2.position + margin

CSS样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body{
margin:0;
padding:0;
}
#left{
width: 200px;
height: 100px;
position: absolute;
top: 0;
left: 0;
background-color: red;
}

#main{
height: 100px;
margin-left: 210px;
background-color: blue;
}

圣杯布局

左右两栏固定宽度,中间部分自适应

步骤:

  1. 三者都设置向左浮动
  2. 设置中间主面板宽度为100%,设置两侧栏的宽度。
  3. 设置 负边距,左侧的设置负左边距为100%,右侧的设置负左边距为负的自身宽度。
  4. 设置父级的padding值给左右两栏留出空间。
  5. 设置两个左右两侧为相对定位,左侧的left值为负的左侧的宽度,右侧的right值为负的右侧宽度。

DOM文档

1
2
3
4
5
<div id="content">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>

CSS样式

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
.main{
width:100%;
height:100px;
float:left;
}

.left{
width:200px;
height:100px;
float:left;
margin-left:-100%;
position:relative;
left:-200px;
}

.right{
width:100px;
height:100px;
float:left;
margin-left:-100px;
position:relative;
right:-100px;
}

#content{
padding:0 100px 0 200px;
}

==注意==:DOM元素的书写顺序不得更改

双飞翼布局

原理说明:双飞翼布局和圣杯布局的思想有些相似,都利用了浮动和负边距,但双飞翼布局在圣杯布局上做了改进,在main元素上加了一层div, 并设置margin,由于两侧栏的负边距都是相对于main-wrap而言,main的margin值变化便不会影响两个侧栏,因此省掉了对两侧栏设置相对布局的步骤。

步骤:

  1. 三者都设置向左浮动。
  2. 设置main-wrap宽度为100%,设置两个侧栏的宽度。
  3. 设置 负边距,left设置负左边距为100%,right设置负左边距为负的自身宽度。
  4. 设置main的margin值给左右两个子面板留出空间。

DOM文档

1
2
3
4
5
<div id="main-wrap">
<div class="main"></div>
</div>
<div class="left"></div>
<div class="right"></div>

CSS样式

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
#main-wrap{
width: 100%;
height: 100px;
float: left;
background-color: blue;
}

.left{
width: 200px;
height: 100px;
float: left;
margin-left: -100%;
background-color: red;
}

.right{
width: 100px;
height: 100px;
float: left;
margin-left: -100px;
background-color: yellow;
}

.main{
margin:0 100px 0 200px;
}

待续

Vue组件之Slots分发内容

发表于 2017-09-10 | 分类于 Vue

介绍

在使用组件时,父组件中的内容会被丢弃,比如:

1
2
3
<my-component>
<p>这是一些内容</p>
</my-component>

组件my-component中的p标签是不会被渲染的,但实际开发中,我们可能希望运用到父组件中的内容,因为在使用组件时,常常需要这样组合它们:

1
2
3
4
<app>
<app-header></app-header>
<app-footer></app-footer>
</app>

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为 内容分发,vue提供了一个API,使用特殊的<slot>元素作为原始内容的插槽。

单个Slot

要想使用父组件的内容,需要在子组件中加入<slot>插口。

假设 my-component 组件有下面模板:

1
2
3
4
5
6
7
<div>
<h3>我是子组件的标题</h3>
<p>我是子组件的内容</p>
<slot>
只有在没有要分发的内容时才会显示。
</slot>
</div>

父组件模板:

1
2
3
4
5
<h2>我是父组件的标题</h2>
<hr>
<my-component>
<p>我是父组件的内容</p>
</my-component>

渲染结果:

1
2
3
4
5
6
7
<h2>我是父组件的标题</h2>
<hr>
<div>
<h3>我是子组件的标题</h3>
<p>我是子组件的内容</p>
<p>我是父组件的内容</p>
</div>

可知,父组件中的内容被渲染到子组件的slot插口所在的DOM位置,并替换掉slot标签本身。

说明:

当子组件模板只有一个没有属性的 slot 时,父组件整个内容片段将插入到 slot 所在的 DOM 位置,并替换掉 slot 标签本身

最初在<slot>标签中的任何内容都被视为备用内容,在父组件中无内容时显示。

具名Slot

元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 可以有不同的名字。具名 slot 将匹配内容片段中有对应 slot 特性的元素。

例子:

父组件模板:

1
2
3
4
5
6
7
8
9
10
11
12
<my-component>

<p slot="one">这是替换第一个内容</p>

<template slot="two">
<p>替换第二个内容</p>
<span>一个span标签,替换第二个内容</span>
</template>

<p slot="three">这是替换第三个内容</p>

</my-component>

子组件模板:

1
2
3
4
5
6
<div>

<slot name="one"><p>这是子组件第1个内容</p></slot>
<slot name="two"><p>这是子组件第2个内容</p></slot>
<slot name="three"><p>这是子组件第3个内容</p></slot>
</div>

渲染结果:

1
2
3
4
<p>这是替换第一个内容</p>
<p>替换第二个内容</p>
<span>一个span标签,替换第二个内容</span>
<p>这是替换第三个内容</p>

Vue组件之单向数据流

发表于 2017-09-08 | 分类于 Vue

什么是单向数据流?

prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

这是官网给的说明,说白了就是父组件通过props传递给子组件的数据不能在子组件里修改,否则浏览器会报错。

实例

先来看看如果不听话的结果:

1
2
3
<div id="app">
<my-input :val="1"></my-input>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>

Vue.component('my-input',{
props:['val'],
template:'<input type="button" :value="val" @click="changeVal">',

methods:{
changeVal:function(){
this.val++;
}
}
});

new Vue({
el:'#app'
});
</script>

上面代码中,父组件传递给子组件一个val数值,绑定在value上,并给按钮添加一个点击事件,点击时val做加一运算。在浏览器中运行,发现效果可以实现,即val值增加了,咋一眼会觉得单向数据流扯淡( • ̀ω•́ )✧。 当然,这是天真的想法。打开控制台,你会发现一行大大的红字:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “val”

显然,不听话是会吃亏的。浏览器报错了,并友情地提示了怎么解决,你看到了吗?

解决办法

  1. 如果你想把它当作局部数据来用,那么就定义一个局部变量,并用 prop 的值初始化它;

  2. 如果你想将它处理成其它数据输出,那么就定义一个计算属性,处理 prop 的值并返回。

首先看第一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vue.component('my-input',{
props:['val'],

template:'<input type="button" :value="counter" @click="changeVal">',

data:function(){
return {counter:this.val}
},

methods:{
changeVal:function(){
this.counter++;
}
}
});

上面代码中,将传入的val赋给counter,然后直接操作this.counter,这时浏览器就不会报错了,注意data的书写格式,必须是函数。

第二种方法:

1
2
3
4
5
6
7
8
9
10
Vue.component('my-input',{
props:['val'],
template:'<input type="button" :value="changeVal">',
computed:{
changeVal:function(){
return this.val+100;
}
}

});

这时,我们希望将传过来的值加100,得到新的数值,通过计算属性轻松实现。

Vue组件之父子通信

发表于 2017-09-08 | 分类于 Vue

前言

vue组件的通信部分是很重要的,组件是协同工作的,这意味着它们要互相通信。看官网文档时,我是比较吃力的,谁让我是菜鸟呢 o( ̄▽ ̄)d

引用官网一段话:

在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息

并配图:

刚开始看的时候,我是懵逼的,后来敲了几遍,初步了解了怎么回事,为啥是初步呢,因为没踩过坑啊,也不知道坑在哪啊。哎,我废话真多。

父组件向子组件通信

使用props传递数据

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,我们需要通过子组件的 props 选项

先前写了一篇Vue组件之props传递数据,这其实就是一个父向子传递数据的过程。在这,我再举一个例子。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app">
<my-button val="toggle"></my-button>
<my-button val="search"></my-button>
<my-button val="click"></my-button>
</div>

<script>

Vue.component('my-button',{
props:['val'],
template:'<input type="button" :value="val">'
});

var vm=new Vue({
el:'#app',
});
</script>

上面代码中,div部分是父级,Vue.component(...)部分是子级,子组件要显式地用props选项声明它期待获得的数据。

在这里,子级想要获取的就是val,这是父级传递过来的,是手动添加的自定义属性,属性值是希望展现的内容。我希望每个按钮实现不同功能,所以传递不同的val值,并动态绑定在子级的value上,格式如上。要注意的是,必须动态绑定在value上,即用v-bind,缩写为:。

结果:

这其实是这样的一个过程:我定义了一个按钮组件,需要在页面中多处引用,它们的样式是一致的,但是我想它们实现不同的功能,于是通过在父组件上绑定自定义属性,并使用props传递给子组件,去修改子组件的一小部分。从上面代码可以看出,这很方便。(我希望我没说错)

子组件向父组件通信

使用自定义事件

  • 使用 $on(eventName) 监听事件
  • 使用 $emit(eventName) 触发事件

这到底是几个意思呢,我也是懵逼的,我按着自己的理解,写了一个例子。

实例

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
<div id="app">
<p>{{count}}</p>
<button-counter @add="addCount"></button-counter>
</div>

<script>

Vue.component('button-counter',{
template:'<input type="button" value="change count" @click="changeCount">',
methods:{
changeCount:function(){
this.$emit('add');
}
}
});

var vm=new Vue({
el:'#app',
data:{
count:1
},
methods:{
addCount:function(){
this.count++;
}
}
});
</script>

暗示自己不要被代码吓到,我写的太简单了。子组件button-counter是一个按钮,我需要点击它去改变父组件的count值。步骤:

  • 在子组件,即按钮上添加changeCount点击事件
  • 在changeCount事件函数中,添加代码this.$emit('add'),这个add是自定义事件,需要添加到父级上,this.$emit()就当做固定格式吧
  • 在父级添加add自定义事件,用v-on指令,缩写为@,如上
  • 在add自定义事件上添加事件函数addCount,addCount定义在实例里,这个函数里就是具体操作代码,即this.count++,以实现count的改变

这些就是基本步骤了,好吧,好像说的比较烂,不过应该是对的,至少我运行成功 ̄▽ ̄ 。 错了也没人知道,反正我自己看。开玩笑,其实是我不会用专业语言叙述,不少东西我也没提到,因为我也不熟啊,推荐看官网文档,虽然说的比较隐晦,但保证质量啊。

Vue组件之字面量语法与动态语法

发表于 2017-09-06 | 分类于 Vue

定义一个组件:

1
<comp message="1"></comp>  //使用的是字面量语法传递数值
1
2
3
4
5
6
7
8
9
Vue.component('comp',{
props:['message'],
template:'<span v-on:click="alertType">{{message}}</span>',
methods:{
alertType:function(){
alert(typeof this.message);
}
}
});

给组件定义一个函数用于检测传递的数据是什么类型,此处检测到 message 是 string 类型,然而我本意是想传递数值1,即 number 类型。可能会受到双引号影响,觉得去掉双引号就是数字了,其实不然,我不知道去掉双引号是否规范,但是去掉后结果依然是 string。这是字面量语法的结果。

vue规定,如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算,然后计算结果赋值:

1
<comp :message="1"></comp>  //用v-bind绑定

此时检测结果为number。

两个例子:

1
<comp message="1+2"></comp>  //1+2

1
<comp :message="1+2"></comp>  //3

CSS居中布局

发表于 2017-09-02 | 分类于 CSS

居中

  • 水平居中
  • 垂直居中

水平居中

  • 行内元素:对父元素设置text-align:center;
  • 定宽块状元素: 设置左右margin值为auto;
  • 不定宽块状元素: 设置子元素为display:inline,然后在父元素上设置text-align:center;
  • 通用方案: flex布局,对父元素设置display:flex;justify-content:center;

垂直居中

知道子元素宽高情况(以下所有父元素都设置了相对定位)

  1. 使用position:absolute,设置left、top、margin-left、margin-top的属性(相对父元素)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #children{
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -50px;
    margin-top: -50px;
    }
  2. 使用position:fixed,同样设置left、top、margin-left、margin-top的属性(相对浏览器窗口)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #children{
    width: 100px;
    height: 100px;
    background-color: red;
    position: fixed;
    top: 50%;
    left: 50%;
    margin-left: -50px;
    margin-top: -50px;
    }
  3. 使用position:fixed和margin:auto,设置left、right、top和bottom(相对浏览器窗口)如果不设置宽高会覆盖浏览器窗口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #children{
    width: 100px;
    height: 100px;
    background-color: red;
    position: fixed;
    left:0;
    right: 0;
    top: 0;
    bottom: 0;
    margin:auto;
    }
  4. 使用position:absolute和margin:auto,设置left、right、top和bottom(相对父元素)如果不设置宽高会覆盖父元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #children{
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    left:0;
    right: 0;
    top: 0;
    bottom: 0;
    margin:auto;
    }

不知道子元素宽高情况

1
2
3
4
5
6
#children{
background-color: red;
position: absolute;
top:50%;
transform:translateY(-50%);
}

设置父元素,使内容居中

  1. 设置父元素line-height等于它的高,使内容垂直居中(常用于文字居中)

    1
    2
    3
    4
    5
    6
    7
    #parent{
    width: 100px;
    height: 100px;
    border:1px solid #000;
    line-height: 100px;
    text-align: center;
    }
  2. 利用display:table-cell和vertical-align:middle使内容垂直居中(适用与多行文本居中)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #parent{
    width: 100px;
    height: 100px;
    border:1px solid #000;
    text-align:center;
    display:table-cell;
    vertical-align:middle;

    }

Flex布局

通用,给父元素设置display:flex和align-items:center,考虑兼容

1
2
3
4
5
6
7
#parent{
width: 500px;
height: 500px;
border:1px solid #000;
display: flex;
align-items: center;
}

load和DOMContentLoaded的区别

发表于 2017-08-29 | 分类于 JavaScript

今天看到一个面试题:

$(function(){console.log(1)}); 和 window.onload = function(){console.log(2)};输出结果

答案:

1
先输出1,再输出2

这一题考察的就是原生js中的load和DOMContentLoaded的区别。那么它们的区别是什么?

1
2
3
4
5
6
7
8
window.addEventListener('load',function(){
// 页面的全部资源加载完才执行,包括图片,视频等
})


document.addEventListener('DOMContentLoaded',function(){
//DOM渲染完即可执行,此时图片,视频还可能没有加载完
});

对应的它们在jQuery中的写法为:

1
2
3
4
5
6
7
8
9
// DOMContentLoaded
$(document).ready(function() {
// ...代码...
});

//load
$(document).load(function() {
// ...代码...
});

js中浅拷贝和深拷贝

发表于 2017-08-27 | 分类于 JavaScript

简介

深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。

浅拷贝

实现代码:

1
2
3
4
5
6
7
function extendCopy(p){
var c={};
for(var attr in p){
c[attr]=p[attr];
}
return c;
}

实例:

1
2
3
4
5
6
7
var a={
num:10,
arr:[1,2,3]
}

var b=extendCopy(a);
console.log(b);

结果:

此时,b已经继承了a的属性。

阅读全文 »
1…456
wungjyan

wungjyan

56 日志
9 分类
24 标签
RSS
练习册
© 2020 wungjyan
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.2
本站访客数 人次 本站总访问量 次