wwj-blog


  • 首页

  • 关于

  • 归档

Vue学习笔记总结

发表于 2019-03-16
字数统计 6,712 | 阅读时长 30
  • 这篇是用 markdown 写的,建议下载一个markdown阅读器 typora,方便阅读。
  • 公司前端项目基本都用的Vue全家桶:
    • 路由管理:Vue-Router,官方文档写的很清晰。
    • 数据请求:双控用的Axios、另外有一些项目用的 Vue-Resource。
    • 状态管理:Vuex,目前只有双控项目用到了,官方文档教程写的很清晰,需要花费时间去学习。
    • UI框架使用的Element-UI,注意老项目Element版本不同配置方法。
    • 依赖包管理:基本用的是yarn, 最好别和npm一起混用。
    • css预处理器:sass,sass可以做很多事情,变量、继承、函数、Mixin、运算、循环等、熟练了写起样式会很高效,官方文档教程也讲的很清晰。这是我收藏的几个CSS网站 css-tricks css3-generator gradient box-shadow,能够快速的生成一些好看的CSS效果。
  • 可以学一下 ES6 语法,解构赋值、对象的 assign、 展开操作符 、属性名简洁表示、async await 等一些经常会用到。有空的话可以了解下正则(JavaScript 正则表达式迷你书),最近经常能用到。
  • 下面的这些是我在刚开始学习Vue基础部分时做的笔记,整合删改了一些,又添加了一部分示例,基本涵盖了Vue基础知识,供参考,也可以直接看官方文档的教程。我学习Vue时主要也是通过官方文档,把基础部分过一遍,示例代码手敲自己运行一下,刚开始可以先不深究原理,先掌握基础用法,在项目中碰到看不懂的代码再去查阅文档或请教恒哥。

Vue基础知识部分

构造器

  • 实例化vue时,需传入一个选项对象,它可以包括 数据、模板、挂载元素、方法和生命周期钩子

属性与方法

  • 每个vue实例都会代理其data对象里所有的属性
  • vue实例暴露了一些有用的实例属性与方法,这些属性与方法都有前缀$,以便与代理的data属性区分

实例生命周期

  • created钩子——在实例被创建后被调用
  • mounted—-当编译好的HTML被挂载到对应的位置,这个操作完成后触发
  • updated—-当data中的数据改变,并且虚拟DOM重新渲染完成后触发
  • destroyed
  • 概要: 钩子的this 指向调用它的实例

生命周期图示

  • https://cn.vuejs.org/images/lifecycle.png

插值

  • 文本
    • 双大括号
    • v-text
  • 纯HTML
    • v-html
  • 属性
    • v-bind(大双括号不能在属性中使用,因此需使用v-bind)
  • 使用JavaScript表达式

指令

  • 哪些指令?

    • v-bind
    • v-on
    • v-if
    • v-for(特殊)
    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
                           v-if  
    <div id="app">
    <template v-if="ok==='username'">
    用户名: <input type="text" placeholder="请输入用户名" key="name-input">
    </template>
    <template v-else>
    密码: <input type="text" placeholder="请输入密码" key="psd-input">
    </template>
    <button @click="toggle">点击切换类型</button>
    </div>

    new Vue({
    el: "#app",
    data: {
    ok:'username'
    },
    methods: {
    toggle: function(todo){
    if(this.ok==='username'){
    this.ok = 'psd'
    }else{
    this.ok = 'username';
    }
    }
    }
    })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     					v-for
    <div id="app">
    <ul>
    <li v-for="item in items">{{item}}</li>
    </ul>
    </div>

    new Vue({
    el: "#app",
    data: {
    items:['a','b','c']
    },
    methods: {
    toggle: function(todo){
    todo.done = !todo.done
    }
    }
    })
  • 修饰符

    • v-on
      • .stop 阻止单击事件冒泡
      • .prevent 提交事件不再重载页面
      • .capture 添加事件侦听器时使用时间捕获模式
      • .self 只当事件在该元素本身(而不是子元素)触发时触发回调
      • 等等

过滤器

  • 过滤器的目的是用于文本转换,转化成你想要的格式

    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
    						filters
    <div id="app">
    <p>{{message | changeChar}}</p>
    <button @click="changeFirstChar">改变</button>
    </div>

    new Vue({
    el: "#app",
    data: {
    message:'nihao'
    },
    methods: {
    changeFirstChar: function(todo){
    this.message = 'good evening'
    }
    },
    filters:{
    changeChar(value){
    if(!value){
    return '';
    }else{
    return value.charAt(0).toUpperCase()+value.substring(1)
    }
    }
    }
    })

缩写

  • v-bind缩写

    • 原有:

      缩写:

  • v-on缩写

    • 原有:

      缩写:

计算属性

计算属性(减少模板的复杂度)

  • 计算属性的基础写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
						computed
<div id="app">
{{fullName}}
</div>

new Vue({
el: "#app",
data: {
firstName:'wang',
lastName:'weiJiang'
},
computed:{
fullName(){
return this.firstName+'----'+this.lastName;
}
}
})
  • 计算缓存vs方法(Methods)

    • 计算属性computed具有缓存,而methods无缓存
  • Computed属性vs 侦听器(Watch属性)

    • watch方法–观察Vue实例上的数据变动,只要指定的数据改变就会执行预定的函数
    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
    							watch
    <div id="app">
    {{msg}} <br>
    改变了吗? {{isChange}}
    <button @click="change">改变</button>
    </div>

    new Vue({
    el: "#app",
    data: {
    msg:'111',
    isChange:'No'
    },
    watch:{
    //只要msg改变,这个方法就会执行
    msg(val,oldVal){
    this.isChange = 'Yes'
    }
    },
    methods:{
    change(){
    this.msg = '222'
    }
    }
    })
    • computed方法
  • 计算setter 和getter

    • get和set,顾名思义,一个是获得,一个是设置,常规上来讲,计算属性中都是有get和set方法的,默认是只有getter方法,如果需要的话,自然可以写一个setter方法.
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
						get和set
<div id="app">
此时的onpiece: {{onepiece}} <br>
此时的msg: {{msg}} <br><br>
<button @click="setName">设置name</button>
</div>

new Vue({
el: "#app",
data: {
name:'Kobe',
msg:''
},
methods:{
setName(){
this.onepiece = 'james'
}
},
computed:{
onepiece:{
get(){
return this.name +'Bryant';
},
set(newVal){
//当给onepiece设置值的时候set就就会调用
this.msg = newVal+'is the greatest basketball player';
}
}
}
})

class与style绑定

绑定HTML class

  • 对象语法

    • 基本
    • 在对象中传入多个class属性(其会与原有class共存)
    • 直接传入对象
    • 与计算属性一起使用(绑定返回对象的计算属性)
  • 数组语法

    • 简单例子
    • 三元表达式
    • 当有多个条件class时,可以在数组语法中使用对象语法
  • 用在组件上

    • 简单例子
    • 绑定HTML class例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     		绑定class的几种方式
    .classC{
    color:red;
    }
    .classD{
    font-weight:bold;
    }
    .classE{
    font-size:20px;
    }
    .classF{
    color:blue;
    }
    .classM{
    display:block;
    }
    .classN{
    display:none;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div id="app">
    <h2>class属性绑定</h2>
    -------------------绑定变量-------------------------
    <div :class="{classA:a,classB:b}">
    绑定变量
    </div>
    -------------------绑定对象-------------------------
    <div :class="styleObj">
    绑定对象
    </div>
    -------------------绑定数组-------------------------
    <div :class="arrClass">
    绑定数组
    </div>
    -------------------绑定三元运算符-------------------------
    <div :class="m==true?'classM':'classN'">
    绑定变量
    </div>
    <button @click="toggle">toggle</button>
    </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
new Vue({
el: "#app",
data: {
a:true,
b:false,
styleObj:{
classC:true,
classD:true
},
m:true,
arrClass:['classE','classF']
},
methods:{
toggle(){
this.m=!this.m;
}
}
})

绑定内联样式

  • 对象语法
    • 内联式对象语法
    • 样式对象式对象语法(更推荐)
  • 数组语法
  • 自动添加前缀
    • v-bind:style 当需要特定的前缀时如transform,vue.js会自动添加
  • 多重值
    • 可以为一个属性添加多个值的数组,常用于含有多个前缀的情况

条件渲染

v-if(v-else)是真正的渲染

  • template元素与v-if

  • v-else(需要紧跟在v-if后边)

  • v-else-if

  • 用key管理可复用的元素

    • 例子:用户名和邮箱登录界面 如果有key就不会复用,可以把key去试一下,然后输入看一下效果
    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
    <div id="app">
    <template v-if="ok==='username'">
    用户名: <input type="text" placeholder="请输入用户名" key="name-input">
    </template>
    <template v-else>
    密码: <input type="text" placeholder="请输入密码" key="psd-input">
    </template>
    <button @click="toggle">点击切换类型</button>
    </div>

    new Vue({
    el: "#app",
    data: {
    ok:'username'
    },
    methods: {
    toggle: function(todo){
    if(this.ok==='username'){
    this.ok = 'psd'
    }else{
    this.ok = 'username';
    }
    }
    }
    })

v-show(其只是简单的切换display属性)

  • v-show不支持template语法
  • v-show不支持v-else

v-if VS v-show

  • v-if
    • 当条件不成立时不会渲染
    • 切换开销较大,适合不太可能变化的场景
  • v-show
    • 无论成不成立都会渲染
    • 首次渲染开销较大,但切换开销小,因此适合经常变化的场景

列表渲染

v-for

  • 基本用法
    • 简单例子
    • 带有index参数
    • 使用of 替代 in
  • template v-for
    • 简单例子
  • 对象迭代 v-for
    • 基础用法
    • 带其他参数用法
  • 整数迭代 v-for
    • 例子
  • 组件和v-for
    包含所有类型的例子
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
 <template>
<div id="app">
<hr>
<strong style="border:2px solid #ccc;">遍历数组:</strong>
<ul>
<li v-for="item in items" >{{item}}</li>
</ul>
<hr>
<strong style="border:2px solid #ccc;">遍历对象数组:</strong>
<ul>
<li v-for="(item,index) in pers">{{index}}--我是{{item.name}},今年{{item.age}}岁</li>
</ul>
<hr>
<strong style="border:2px solid #ccc;">遍历对象:</strong>
<ul>
<li v-for="(value,key) in obj">
key:{{key}} |
value:{{value}}
</li>
</ul>
</div>
</template>

<script>
new Vue({
el: "#app",
data: {
isOK:'true',
items:['香蕉','苹果','烤肉'],
pers:[{
name:'Kobe',
age:'40'
},
{
name:'James',
age:'38'
}],
obj:{
1:'one',
2:'two'
}
}
})
</script>

key

  • 作用

    • 用v-for更新已渲染过的列表时,它默认采用的是“就地复用”的原则,也就是如果数据项顺序发生了改变,vue将不是移动DOM元素来匹配数据项的顺序,而是简单复用此处的元素。如果想跟踪每个节点的身份,从而重用或重新排列现有元素,可使用key。
  • key有什么用,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <div id="app">
    KEY: <input type="text" v-model="id"> VALUE: <input type="text" v-model="name">
    <button @click="add">添加</button>
    <ul>
    <li v-for="item in list" :key="item.id"> //此处你可以吧key去了,先勾选一条,在追加一条试一下,然后加上key,勾选一条追加一条再试一下,一目了然
    <input type="checkbox" >
    {{item.id}}---{{item.name}}
    </li>
    </ul>
    </div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
new Vue({
el: "#app",
data: {
id:"",
name:"",
list:[
{id:1, name:'李斯'},
{id:2, name:'嬴政'},
{id:3, name:'赵高'},
{id:4, name:'韩非'},
{id:5, name:'荀子'},
]
},
methods: {
add: function(){
this.list.unshift({id:this.id,name:this.name})
}
}
})

因为加上key默认采取的就是就地复用策略
​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

### 数组更新检测

- 变异方法(会改变原有数组)

- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()

- 重塑数组

- filter()
- concat()
- slice()

- 注意事项
利用索引直接设置一个项时,vue不能检测变动,如:vm.items[indexOfItem] = newValue
如果要设置某一项

  • Vue.set(example1.items, indexOfItem, newValue)
  • example1.items.splice(indexOfItem, 1, newValue)

    1
    2








  • —


var vmm = new Vue({
el: “#app”,
data: {
id:””,
name:””,
list:[
{id:1, name:’李斯’},
{id:2, name:’嬴政’},
{id:3, name:’赵高’},
{id:4, name:’韩非’},
{id:5, name:’荀子’},
]
},
methods: {
setZF: function(){
Vue.set(this.list,1,{id:2,name:’张飞’})
},
setGY:function(){
this.list.splice(2,1,{id:3,name:’关羽’})
}
}
})

1
2


  • 修改数组长度时,vue不能检测变动,如:vm.items.length = newLength
  • 只能用example1.items.splice(newLength)
1
2
3
4
5
6

### 对于显示过滤/排序结果的两种方法

- 过滤数组--计算属性computed例子

- 过滤数组--方法methods例子
计算属性应用于过滤


new Vue({
el: “#app”,
data: {
nums:[1,2,3,4,5,6,7,8,9]
},
computed:{
specialNum(){
return this.nums.filter((item,index)=>{
return item%3==0;
})
}
}
})

1
2




  • //在v-for循环中直接嵌入方法

new Vue({
el: “#app”,
data: {
numbers:[1,2,3,4,5,6,7,8,9]
},
methods:{
fil(nums){
return nums.filter((item,index)=>{
return item%3==0;
})
}
}
})

1
2

## 两个简单的事件处理器

1





2




new Vue({
el: “#app”,
methods: {
sayHello: function(){
alert(‘sayHello’)
}
}
})

1
2
3
4

### 内联处理器方法

- 访问原生DOM事件的例子,如果click事件不传参数,就默认把原生DOM传递进去


//没有传参数,就是原生的!!!




new Vue({
el: “#app”,
data: {
msg:’’
},
methods: {
showBtnname: function(e){
this.msg = e.target.innerText;
}
}
})

1
2

- 未访问原生DOM事件的例子,如果传了参数.那么方法中接受的第一个参数就是该参数,在vue中所有的事件绑定都是这样的

—————————-html———————————


Todos:




      <del v-if="todo.done">
        {{ todo.text }}
      </del>
      <span v-else>
        {{ todo.text }}
      </span>
    </label>
  </li>
</ol>


—————————-js———————————
new Vue({
el: “#app”,
data: {
todos: [
{ text: “Learn JavaScript”, done: false },
{ text: “Learn Vue”, done: false },
{ text: “Play around in JSFiddle”, done: true },
{ text: “Build something awesome”, done: true }
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
—————————-css———————————
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}

#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}

li {
margin: 8px 0;
}

h2 {
font-weight: bold;
margin-bottom: 15px;
}

del {
color: rgba(0, 0, 0, 0.3);
}

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

### 事件修饰符

- .stop
- 阻止单击事件冒泡
- .prevent
- 提交事件不再重载页面
- .capture
- 使用事件捕获模式
- .self
- 只有当事件在该元素本身被触发时(不包含子元素)才触发回调
- .once
- 事件只触发一次(vue 2.1.4新增)
- 修饰符串联
- 例子

### 按键修饰符

- .enter

- keyCode
- .enter

- .tab

- .delete

- (捕获 “删除” 和 “退格” 键)

- .esc

- .space

- .up

- .down

- .left

- .right

- 组合使用,单独是使用的话,和click都是一样的,这里组合使用有点特殊,使用 . 进行连接简单给个例子



new Vue({
el: “#app”,
data: {
num:0
}
})

1
2
3
4
5
6
7
8
9
10
11
12
13

### vue2.1.0新增 按键修饰符

- .ctrl
- .alt
- .shift
- .meta

## 表单控件绑定

### 基础用法

- 文本





new Vue({
el: “#app”,
data: {
msg:’万年的msg’
}
})

1
2

- 多行文本---在文本区域插值( `<textarea></textarea>` ) 并不会生效,应用 `v-model` 来代替







1
2
3
4

- 复选框

- 单个复选框(直接绑定true,false)
<div id="app">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>

new Vue({
  el: "#app",
  data: {
   checked:true
  }
})

1
2

- 多个复选框(将选中的所有value绑定到一个数组)
<div id="app"> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> {{checkedNames}} </div> new Vue({ el: "#app", data: { checkedNames:[] } })
1
2

- 单选按钮(绑定选中的单选框的value)









Picked:

new Vue({
el: “#app”,
data: {
picked:’’
}
})

1
2
3
4

- 选择列表(不管是单选还是多选,v-model都要绑定到select元素上)

- 单选列表(绑定到被选中项的value)
<div id="app">
    <select v-model="selected">
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
    <span>Selected: {{ selected }}</span>
</div>

new Vue({
  el: "#app",
  data: {
    selected:''
  }
})

1
2

- 多选列表(绑定一个数组,数组的内容是所有的选中项的value)
<div id="app"> <select v-model="selected" multiple> <option>A</option> <option>B</option> <option>C</option> </select> <br> <span>Selected: {{ selected }}</span> </div> new Vue({ el: "#app", data: { selected: [] } })
1
2

- 动态选项
<div id="app"> <select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span> </div> new Vue({ el: "#app", data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } })
1
2
3
4
5
6

### 修饰符

- .lazy

- 由原有的input事件变更为change事件
<div id="app"> <input type="text" v-model.lazy="msg"> {{msg}} </div> new Vue({ el: "#app", data: { msg:'万年的msg' } })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

- .number

- 将输入的类型转换成数字类型(NaN则还是原有类型)

- .trim

- 去除两端空白



### v-model与组件

## 组件

### 使用组件

- 注册

- 注意事项

- 在初始化根实例前一定要确保注册了组件!!!!
- 名称最好 小写(可以使用短杆)
<div id="app"> <my-comp></my-comp> </div> Vue.component('my-comp',{ template:'<h3>我是新出炉的组件</h3>' }) new Vue({ el: "#app", data: { } })
1
2

- 局部注册


new Vue({
el: “#app”,
components:{
‘my-comp’:{template:’

我是新出炉的组件

‘}
},
data: {

}

})

1
2
3
4
5
6
7
8
9
10
11
12
13
14

- DOM模板解析说明

- 自定义组件在这些元素内受限

- ul

- ol

- table

- select

- 概要: 解决方案是 使用 特殊的is属性
  <div id="app">
   <table>
     <tr>
     <my-comp></my-comp>//注意:这样写是绝对错误的,因为tr中只允许有td,这样写他是不认识滴
     </tr>
   </table>
  </div>
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 上边是错误的


  ---------------------------------下边是正确的-----------------------------------
  <div id="app">
   <table>
     <tr>
       <td is="my-comp"></td>
     </tr>
   </table>
  </div>

  new Vue({
    el: "#app",
    components:{
        'my-comp':{
              template:'<td>我是组件td</td>'
      }
    },
    data: {

    }
  })


  
1
2
3
4

- 不受限的情况--使用字符串模板

- <script type="text/x-template"> 怎么用呢?给大家来个例子吧!
-------------------------------HTML----------------------------------------- <div id="app"> <table> <tr> <template> <my-comp></my-comp> </template> </tr> </table> </div> <script type="text/x-template" id="myComponent"> <td>This is a component!</td> </script> -----------------------------------JS---------------------------------- new Vue({ el: "#app", components:{ 'my-comp':{ template:'#myComponent' } }, data: { } })
1
2

- JavaScript内联模板字符串(什么是字符串模板)
<div id="app"> <table> <tr> <template> //这个就是字符串模板 <my-comp></my-comp> </template> </tr> </table> </div>
1
2
3
4

- .vue组件 (第三种)

- data必须是函数,在组件中使用data中定义的数据,必须使用函数返回,我自己的理解,最根本的三个字就是作用域,目的就是为了防止组件中使用的data和vue实例中的data进行相互污染,
<div id="app"> <mycomp></mycomp> </div> new Vue({ el: "#app", components:{ 'mycomp':{ template:'<button>{{btncount}}</button>', data(){ return {btncount:8} } } }, data:{ btncount:10 } })
1
2
3
4

### Prop(子组件从父组件获得数据)

- 使用prop传递数据
<div id="app"> <child msg="我是来自于父组件的内容"></child> </div> new Vue({ el: "#app", components:{ 'child':{ props:['msg'], template:'<h2>{{msg}}</h2>' } } })
1
2


动态绑定父组件中的数据 <div id="app"> <input type="text" v-model="fathertext"> {{fathertext}} <child :childText="fathertext"></child> </div> new Vue({ el: "#app", components:{ 'child':{ props:['childtext'], template:'<h1>{{childtext}}</h1>' } }, data: { fathertext:'' } })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

-

- props注意事项

- 一般情况下是数组形式,如果要想规定props的数据类型(后面用中括号 [ ])。默认值等(props验证),则是对象了(后面用花括号 { })

- 关于命名:要不然全小写,要不然kebabCase(驼峰式),kebab-case(短横线隔开式)Vue 能够正确识别出小驼峰和下划线命名法混用的变量,如这里的`forChildMsg`和`for-child-msg`是同一值。

- 动态Prop(使用v-bind):在模板中,要动态地绑定父组件的数据到子组件模板的 props,和绑定 Html 标签特性一样,使用v-bind绑定

- 局部注册组件
- 全局注册组件

- 字面量语法vs动态语法

- 单向数据流

- 解释

- 父组件数据更新后,子组件的所有prop都会更新为最新值,但是反过来就不会。(注意 :如果prop为数组或对象时,子组件改变prop,父组件的状态也会受到影响,因为数组或对象是引用类型,他们指向同一个内存空间。)如果子组件的prop值被修改,则vue会给出警告。
<div id="app"> <parent></parent> </div> let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> </div>`, props: { "for-child-msg": String } }; let parentNode = { template: ` <div class="parent"> <div> <span>父组件数据</span> <input v-model="msg"/> </div> <p>{{msg}}</p> <child :for-child-msg="msg"></child> </div> `, components: { child: childNode }, data() { return { msg: "default string." }; } }; new Vue({ el: "#app", components:{ parent:parentNode } })
1
2
3
4
5
6

- 特殊情况应对方法

- prop作为初始值传入后,可能子组件想把它当做局部数据来用的情况

- 方法:定义一个局部变量,并用prop的值初始化它
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } //直接使用counter作为子组件的局部变量就可以了
1
2
3
4

- prop作为初始值传入,可能子组件处理成其他数据输出的情况,比如处理成去空格并大写

- 方法:定义一个计算属性,处理prop的值并返回
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
1
2
3
4

- prop验证

- 例子
Vue.component('example', { props: { // 基础类型检测 (`null` 意思是任何类型都可以) propA: Number, // 多种类型 propB: [String, Number], // 必传且是字符串 propC: { type: String, required: true }, // 数字,有默认值 propD: { type: Number, default: 100 }, // 数组/对象的默认值应当由一个函数返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { return value > 10 } } } })
1
2
3
4
5
6
7
8

### 自定义事件(子组件将数据传回父组件)

- 使用v-on绑定自定义事件

- 给组件绑定自定义事件例子(用v-on来监听子组件触发的事件)

- 给组件绑定**原生事件**例子--使用native修饰符
<div id="app"> <btncomp @click.native="alertE"></btncomp> </div> new Vue({ el: "#app", components:{ btncomp:{ template:'<button>点击我弹出</button>' } }, methods:{ alertE(){ alert(777) } } })
1
2
3
4
5
6

- .sync修饰符

- 目的:使父子组件实现prop类似“双向数据绑定”(默认子组件无法更改prop的值,上边已经说到了,但是使用sync后子组件可以改变prop 的值,并传回父组件)

- 使用范例
<div id="app"> <child :name.sync="name"></child> //其实不加也能更改,但是会报错 <button type="button" @click="changePropsInFather">在父组件中将props值改变为'props'</button> </div> Vue.component('Child', { template: `<h1 @click="changePropsInChild">hello, {{name}}</h1>`, props: { name: String, }, methods:{ changePropsInChild(){ this.name = 'I am from child' } }, }) // 实例化一个Vue对象 const app = new Vue({ el: '#app', data(){ return { name: 'world' } }, methods:{ changePropsInFather(){ this.name='I am from father' }, }, })
1
2
3
4
5
6

- 使用自定义事件的表单输入组件

- v-model的语法糖

v-model只是一个语法糖,它的真身是下边这样:
<div id="app"> <input type="text" :value="price" @input="price = $event.target.value">{{price}} </div> new Vue({ el: '#app', data: { price: '' } });
1
2
3
4

- 例子

- html及实例部分和注册组件部分
<div id="app"> <price-input :value="price" @input="isinputing"></price-input> {{price}} </div> new Vue({ el: "#app", components:{ 'price-input':{ template:"<input type='text' @input='update($event.target.value)' />", props:['value'], methods:{ update(val){ this.$emit('input',val) } } } }, data: { price:'' }, methods: { isinputing: function(val){//此处的value就是子组件传递过来的 this.price = val; } } })
1
2
3
4
5
6

### 非父子组件通信

- 非父子组件通信(1 父传子是用props 2 子传父在vue中是不允许的,因为vue只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的.

- 简单的场景---采用空实例作为中央事件总线(EventBus),原理就是找一个人来当作一个中转站!
<div id="app1" @click="toApp2"> 我是组件一,点击我给二传值 </div> <br> <div id="app2"> {{app2msg}} </div> var bus = new Vue(); // 创建事件中心,创建中转站 new Vue({ el: "#app1", data: {}, methods: { toApp2: function(){ bus.$emit('change','上山打老虎') //使用中转站触发 } } }) new Vue({ el: "#app2", data: { app2msg:'' }, created(){ bus.$on('change',(val)=>{ this.app2msg = val; //在组件二创建完成的时候就使用中转站进行监听 }) } })
1
2
3
4
5
6
7
8

- 复杂的场景---专门的状态管理模式vuex

### 使用Slot分发内容

- 内容分发概念

- 为了让组件可以组合,因此需要混合父组件的内容与子组件的自己模板,这一过程就称作内容分发。
<app> <app-header></app-header> <app-footer></app-footer> </app> 如果给app指定了模板,那么里边的app-header和foot组件的内容就会被覆盖,因此,为了让他们能够组合.需要混用,这就是内容分发
1
2
3
4
5
6
7
8
9
10

- 编译作用域

- 分发内容是在父作用域内编译的

- 单个slot(无具名slot)

- 为什么用slot

- 当父组件中有内容子组件模板中无slot时,则父组件中的内容会被丢弃。
<div id="app"> <my-comp> <p>我是组件中的内容</p> //这个p会被覆盖 </my-comp> </div> new Vue({ el: "#app", components:{ 'my-comp':{ template:'<h1>我是一个组件</h1>' } } })
1
2


  • 单个slot怎么用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <div id="app"> 
    <children>
    <span>12345</span>
    <!--上面这行不会显示-->
    </children>
    </div>

    var vm = new Vue({
    el: '#app',
    components: {
    children: { //这个无返回值,不会继续派发
    template: "<button><slot></slot>(我是button)</button>"
    }
    }
    });
1
2
3
4
5
6
7
8
9
10
11
12

- 当父组件中有内容时

- 子组件中的slot会被父组件中内容所替换。(slot标签也会被替换掉)

- 当父组件中无内容时

- 子组件中slot内容会被显示出来

- 具名slot

- 用法:保子引父(保持子组件模板,引入父组件参数)--严格按照子组件的模板顺序来即:遇到具名slot对应的元素就渲染相应的元素,遇到不具名的slot,则会渲染除了具名slot对应的元素以外的所有元素。
<div id="app">
  <children>
    <span slot="first">12345</span>
    <span slot="second">56789</span>
    <!--上面这行不会显示-->
  </children>
</div>

var vm = new Vue({ 
el: '#app', 
components: { 
  children: { //这个无返回值,不会继续派发 
    template: "<button><slot name='first'></slot>我是button<slot name='second'></slot>所以使用button标签</button>"
  } 
} 
}); 
说白了,就是多一个name属性


1
2
3
4
5
6
7
8

- 作用域插槽(特殊的插槽)

- 作用:使用可复用模板替代已渲染元素

- 用法:同具名slot类似,都是严格按照子组件的模板顺序渲染,**只不过遇到slot元素时会将父组件中的template元素里的元素全部渲染**

- 列表组件例子
<div id="app"> <child :items="items"> <template slot="item" scope="props"> <!--必须存在的具有 scope属性的 template元素(作用域插槽的模板), props临时的变量名称,接受子组件中传递的props对象--> <!--slot = “item”是具名 slot的用法。--> <li> {{props.tex}} <!--引用子组件中绑定的tex属性值。--> </li> </template> </child> </div> Vue.component('child',{ props:["items"], template:'<ul><slot name="item" v-for="item in items" v-bind:tex="item.text"></slot></ul>' }); new Vue({ el:'#app', data:{ items:[ {text:'h'}, {text:'y'}, {text:'z'} ] } })
1
2
3
4

### 动态组件

- 使用is属性(注意,is前使用了v-bind!!!通过**is**来决定那个组件被渲染显示 )



var app=new Vue({
      el:'#app',
      data:{
          show:'tem1'
      },
      components:{
          tem1:{
              template:'<div>11111111111</div>'
          },
            tem2:{
              template:'<div>22222</div>'
          },
            tem3:{
              template:'<div>333333</div>'
          }
      },
      methods:{
          changeShow:function(){
              if(this.show=='tem1'){
                      this.show='tem2'
              }else  if(this.show=='tem2'){
                      this.show='tem3'
              }else{
                   this.show='tem1'
              }
          }
      }
  })
1
2
3
4
5
6
7
8

- keep-active

- 作用:可保留组件状态或避免重新渲染(包裹动态组件时会缓存不活动的组件实例而不是销毁它们)配合 <keep-alive>使用时,可以保留组件状态避免重新渲染(和v-show 比较的差别是v-show 是一开始就渲染的所有组件,而keep-alive 并不是一开始就渲染好所有组件,而已保留渲染过的组件

- 注意事项:使用环境应该是较大页面频繁切换的情景下

- 用法
        <div id="app">
            <component v-bind:is="show"></component>
            <button v-on:click="changeShow">change show</button>
        </div>

                 var app=new Vue({
            el:'#app',
            data:{
                show:'tem1'
            },
            components:{
                tem1:{
                    template:'<div>11111111111</div>'
                },
                  tem2:{
                    template:'<div>22222</div>'
                },
                  tem3:{
                    template:'<div>333333</div>'
                }
            },
            methods:{
                changeShow:function(){
                    if(this.show=='tem1'){
                            this.show='tem2'
                    }else  if(this.show=='tem2'){
                            this.show='tem3'
                    }else{
                         this.show='tem1'
                    }

                }
            }

        })


```

写给佩奇的使用说明~

发表于 2019-02-16
字数统计 619 | 阅读时长 2

佩奇的聊天记录导出指南


       你好呀,佩奇:这篇文档是用来帮助你把孩子们可爱的的语音收集起来的,由于iphone和微信的诸多很多限制,过程可能有些繁琐。我尽量做到简洁。那么我们开始吧,把孩子对侯老师说的话记录下来。🤭

一、准备工作

iTunes数据导出:

       不知道你之前有没有用过iTunes给手机备份,我之前有用过,恢复备份之后微信里的聊天记录也都还在,说明肯定这些文件在备份的时候保存到了电脑上。它们在哪里?苹果官方给了答案。简单地说,Windows 下在“\用户\(用户名)\AppData\Roaming\Apple Computer\MobileSync\Backup\”
那么你首先需要将微信聊天数据进行导出。也就是iTunes进行备份,按照下图使用iTunes备份整机数据,注意不要选择给iPhone备份加密,这一步应该比较久,取决于你聊天记录的多少,和电脑的硬盘,慢慢等吧,可以去喝杯牛奶。
873d5cef8b9db6e72ba081df64044e6.png

二、运行软件

       工具已经被打包成成了exe,应该很好用啦,解压文件夹,打开WechatExport.exe

  • 选择备份好的文件夹,应该能自动识别到的,没有的话手动选择下
  • 点击保存为网页,这样就能留下音频和图片
  • 保存的位置可以使用默认的放在桌面,也可以自己选择喜欢的位置,别找不到了哦
  • 点击开始,程序运行
    eb6aa4676f610b75b885738637deb0f.png
    这步顺利的话,那佩奇老师已老师已经差不多要完成了,
  1. 你可以在桌面上看到一个一个聊天记录.html,可以直接点击它查看,
  2. 还有一个以你微信号命名的文件夹,所有的信息都保存在这里面,里面的每一个小文件夹都是以你朋友的微信号命名的,点开可以看到你们所发的图片和语音MP3格式的。
  3. 有形如xxxx@chatroom_files是群聊的信息。

    三、TODO

这时佩奇可能发现了,这些聊天记录查看起来还是不太方便,我们还要进行数据的处理和分类

  • 文件夹显示中文
  • 单独提取语音
  • 语音按照日期姓名进行命名

这些我们稍后再进行吧~做到这一步你已经很棒了


1523868789620620.jpg

css 状态叠加

发表于 2018-09-13
字数统计 142 | 阅读时长 1

问题描述

在做网易云过程中遇到的一个问题,animation-play-state在微信内置浏览器和iosSafari中不起作用。导致歌曲播放动画无法暂停

解决方案

采用 css3 属性叠加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var isPlaying = false;
var container = document.querySelector(".container");
var disk = container.querySelector(".disk");

disk.addEventListener("click", function bindEvent() {
isPlaying ? pause() : play();
});
function pause() {
isPlaying = false;
var dTransform = getComputedStyle(disk).transform;
var cTransform = getComputedStyle(container).transform;
container.style.transform =
cTransform === "none" ? dTransform : dTransform.concat(" ", cTransform);
disk.classList.remove("active");
}
function play() {
isPlaying = true;
disk.classList.add("active");
}

源码链接
预览链接

网易云音乐手机端

发表于 2018-08-22
字数统计 477 | 阅读时长 2

环境搭建

2018年8月22日:初步搭建LeanClound 和 七牛云环境,测试admin界面上传七牛云功能正常

在搭建过程中,使用的是七牛云1.x版本,由于七牛云设置需要uptoken,在本地利用七牛Node.js SDK 构建后端服务返回uptoken,所需要的 accessKey secretKey保留在本地,切勿上传至GitHub。
共引用如下库

1
2
3
4
<script src="../node_modules/leancloud-storage/dist/av-min.js"></script>
<script src="../node_modules/qiniu-js/dist/qiniu.min.js"></script>
<script src="../node_modules/plupload/js/moxie.js"></script>
<script src="../node_modules/plupload/js/plupload.dev.js"></script>

服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
response.statusCode = 200;
response.setHeader("Content-Type", "text/json; charset=utf-8");
response.setHeader("Access-Control-Allow-Origin", "*");

var config = fs.readFileSync("xxx.json");//存有"accessKey""secretKey"的json文件
config=JSON.parse(config)
let{accessKey,secretKey}=config
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);

var options = {
scope: 'bucket',//项目名称
};
var putPolicy = new qiniu.rs.PutPolicy(options);
var uploadToken=putPolicy.uploadToken(mac);

response.write(`
{
"uptoken":"${uploadToken}"
}`);
response.end();

并在七牛云配置 中设置相应的路径uptoken_url,同时开启server服务器和自己的页面进行测试。

管理界面搭建及功能实现

  • 使用简单的界面,将整个后台管理页面面分为四部分,新建歌曲、歌曲列表、歌曲信息、上传区域。分别使用MVC。增添了eventHub,使用订阅/发布 来控制各部分之间的信息传递。
  • 上传歌曲后,可以在歌曲信息部分显示歌曲的名称、歌手、链接。并可以进行编辑在储存。
  • 读取后台歌曲信息,并显示在列表。点击列表显示信息。更改信息后刷新列表。

用户界面搭建

  • 仿照网易云音乐手机端,采用vw布局。
  • meat:vp 禁止缩放。
  • 媒体查询,不同屏幕大小导航栏是否固定。

源码链接
预览请手机扫二维码
预览链接

初步了解webpack

发表于 2018-08-19
字数统计 495 | 阅读时长 2

webpack基本安装

首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack)

1
2
3
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

建立如下目录

1
2
3
4
5
  webpack-demo
|- package.json
+ |- index.html
+ |- /src
+ |- index.js

配置文件

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')//将src/index.js 作为入口起点,生成 dist/main.js 作为输出。
}
};

执行

1
npx webpack --config webpack.config.js

会将我们的脚本 src/index.js 作为 入口起点,也会生成 dist/main.js 作为 输出。

babel-loader

安装

1
npm install --save-dev babel-loader babel-core

配置

在 webpack 里的 webpack.config.js 文件 同添加

1
2
3
4
5
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}

创建 .babelrc 配置文件

虽然已经配置好了 Babel ,但并没有让它真正生效。在项目的根目录中创建一个 .babelrc 文件并启用一些插件。
首先,可以使用转换 ES2015+ 的 env preset

1
npm install babel-preset-env --save-dev

为了让 preset 生效,你需要像下面这样定义你的 .babelrc 文件:

1
2
3
{
"presets": ["env"]
}

sass-loader

安装

1
npm install sass-loader node-sass webpack --save-dev

node-sass 和 webpack 是 sass-loader 的 peerDependency,因此能够精确控制它们的版本。

配置

1
2
3
4
5
6
7
8
9
10
11
12
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" //将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" //将 Sass 编译成 CSS
}]
}]
}

使用

此时目录应该如下

1
2
3
4
5
6
7
8
9
10
webpack-demo
|- /node_modules
|- package.json
|- index.html
|- /dist
|- bundle.js
|- /src
|- index.js
|- main.scss
|- moudle-1.js

使用 import 在 index.js 中导入 main.scss moudle-1.js

1
2
3
4
import x from './moudle-1'
import y from './main.scss'
console.log(3)
x()

再次运行

1
npx webpack --config webpack.config.js

参考

文章中的wenpack-demo
webpack中文网站
babel中文网站

Etag

发表于 2018-08-16
字数统计 189 | 阅读时长 1

MD5

摘要算法,任何相同文件的MD5值都一样,只要改变了这个文件里的内容,它的MD5值就会变

ETag

在服务器里设置响应头

1
2
3
let string = fs.readFileSync('./main.js', 'utf8')
let fileMd5 = md5(string);
response.setHeader('ETag', fileMd5)

这样响应头的ETag中就会有该文件的md5值,浏览器会在请求头里设置if-None-Match,并附上这个md5值。
于是在请求的时候,如果这个md5值和你文件的md5值一样,说明文件没有更新,不需要下载

1
2
3
if(request.header['if-None-Match'] === fileMd5){
response.statusCode = 304;
}

和缓存的区别

缓存根本就不会发请求,而ETag会发请求,并比较md5值是否一样。
所以还是缓存好

Cache-Control(缓存)

发表于 2018-08-16
字数统计 324 | 阅读时长 1

性能优化

想让哪个文件被缓存(如js文件、css文件等),就在服务器里的路由里写上

1
response.setHeader('Cache-Control', 'max-age=30')

这样每次浏览器请求完这个url后的30s内,都不会再请求这个文件,提升了速度。
但只要改变url,文件就会被再请求一次

html不要设置Cache-Control

因为html若设置了缓存,浏览器就不会向服务器发送任何请求,这样用户无法获取到任何更新后的版本。
若是css、js这类文件更新了,可以通过改变url来使用户获取到更新,例如

1
2
3
4
5
6
7
<script src="main.js"></script>  //第一个版本

<script src="main.js?v=2"></script> //第二个版本,改变url,加了个查询参数,于是浏览器就会重新请求文件了

<script src="main.js?v=3"></script> //第三个版本

<script src="main.js?随机数"></script> //以后的版本

Expires(旧版本的缓存)

1
response.setHeader('Expirse', 'Feb 2018 14:04:04.....')

区别:Expires设置的是日期,而且是根据本地时间判断的,若是用户的本地时间有误,就会有bug,所以现在都用Cache-Control,若两个都设置了会优先使用Cache-Control,因为这是新版的

local Storage SessionStorage入门

发表于 2018-08-16
字数统计 183 | 阅读时长 1

localStorage

    • 与cookie不同,请求的时候浏览器不会带上localStorage
      • 而且每个域名localStorage最大存储量5Mb左右,cookie只有4k左右
      • 而且localStorage理论上不会过期,除非清理缓存
      • 所以持续化存东西的时候用localStorage
  1. session是服务器上的hash,localStorage是浏览器上的hash,localStorage里存的东西保存在本地。
  2. 只有相同域名的网页才能互相读取localStorage。
  3. API:

    1
    2
    localStorage.setItem('a',1);
    localStorage.getItem('a'); //1
  4. 用来记录有没有提示过用户等信息,不能用来记录密码之类的

sessionStorage

  1. sessionStorage和session没有关系
  2. sessionStorage和localStorage的1、2、3点是一样的,区别是关掉浏览器后sessionStorage就会被清除

cookie和session

发表于 2018-08-16
字数统计 424 | 阅读时长 2

Cookie

1、服务器通过 Set-Cookie 头给客户端一串字符串
4、客户端每次访问相同域名的网页时 , 必须带上这段字符串
3、客户端要在一段时间内保存这个 Cookie
4、前端不要读写 cookie,用 local sortage

cookie 可以在后台更改保存时间

setMaxAge

1
2
3
cookie.setMaxAge(0);//不记录cookie
cookie.setMaxAge(-1);//会话级cookie,关闭浏览器失效
cookie.setMaxAge(60*60);//过期时间为1小时

过时了的expires

1
2
Set-Cookie: name=Nicholas; expires=Sat, 02 May 2018 23:38:25 GMT
//星期六 5月2号 2010年 23:38:25时过期

Session

1、将SessionID ( 随 机 数 )通过 Cookie 发给客户端
2、客户端访问服务器时,服务器读取SessionID
5、服务器有一块内存(哈希表)保存了所有 session
4、通过 SessionID 我们可以得到对应用户的隐私信息,如 id 、email
5、这块内存(哈希表)就是服务器上的所有 session

cookie和session的区别

1. cookie

  • cookie是由服务器发送给浏览器的响应头里的Set-Cookie:的值构成的。
  • cookie保存在客户端,并且每次都随着请求发送给server。
  • 没有session之前,cookie里保存的是用户信息,由于任何人可以读写,不安全

    2. session

  • session是依附于cookie而存在的
  • 有了session,服务器将用户的信息保存在服务器中的session表里,然后赋予相应的信息一个sessionID,于是将响应头里的Set-Cookie的值改为sessionID
  • 浏览器请求时带上cookie,服务器就通过cookie里的sessionID查找session表里对应的信息
  • 这样暴露给其他人的就只有sessionID,很安全。

知识点小结

发表于 2018-07-21
字数统计 1,531 | 阅读时长 7

一、移动端是怎么做适配的?(回答要点:meta viewport、媒体查询、动态 rem 方案)
1.meta viewport
禁止用户设备缩放

1
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />

2.不同的设备采取不同的样式,实现该方法应采用媒体查询设置条件:
最大宽度不超过500px时采取的CSS样式

1
<link rel="stylesheet" href="./mobile.css" media="(max-width: 500px)">

或

1
2
3
4
5
6
<style>
@media(max-width:500px){
.........
}

</style>

3.动态 rem 方案
(1)使用 JS 动态调整 REM,需要自己计算px到rem
i. 加上meta viewport标签
ii. 设置html 的 font-size(即1rem) 等于十分之一的页面宽度 ,

1
2
3
4
5
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<script>
var pageWidth = window.innerWidth
document.write('<style>html{font-size:'+pageWidth/10+'px;}</style>')
</script>

(2)使用sass 自动转换px为rem

1
2
3
4
5
@function px( $px ){
@return $px/$designWidth**10 + rem;
}

$designWidth : 640; //设计稿宽度

二、什么是闭包,闭包的用途是什么?

1.如果一个函数 使用了 这个函数外的值 那么 (这个函数+这个变量)就是闭包

1
2
3
4
5
6
7
8
9
function foo(){
var local = 1
function bar(){
local++
return local
}
return bar
}
//local 变量和 bar 函数就组成了一个闭包(Closure)

2.一个是可以读取函数内部的变量

1
2
3
4
5
6
7
8
9
10
function f1() {
var n = 999;
function f2() {
alert(n);
}
return f2;
}
var result = f1();
result(); // 999
//f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量,

另一个是让这些变量的值始终保持在内存中。

1
2
3
4
5
6
7
8
9
10
11
12
function f1() {
var n = 1;
function f2() {
alert(n++);
}
return f2;
}
var result = f1();
result(); //1
result(); //2
result(); //3
//原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

三、call、apply、bind 的用法分别是什么?

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
var list={
name:'wang',
age:18,
func:function(){
console.log('名字'+this.name+'年龄'+this.age)
}
}

var list1={
name:'li',
age:30,
}

var list2={
name:'zhao',
age:70,
}
var list3={
name:'wu',
age:2,
}
list.func()//名字wang年龄18
list.func.call(list1)//名字li年龄30
list.func.apply(list2)//名字zhao年龄70
list.func.bind(list3)()//名字wu年龄2

四、HTTP 状态码
200 OK
请求正常处理完毕

204 No Content
请求成功处理,没有实体的主体返回

206 Partial Content
GET范围请求已成功处理

301 Moved Permanently
永久重定向,资源已永久分配新URI

302 Found
临时重定向,资源已临时分配新URI

303 See Other
临时重定向,期望使用GET定向获取

400 Bad Request
请求报文语法错误或参数错误

401 Unauthorized
需要通过HTTP认证,或认证失败

403 Forbidden
请求资源被拒绝

404 Not Found
无法找到请求资源(服务器无理由拒绝)

500 Internal Server Error
服务器故障或Web应用故障

503 Service Unavailable
服务器超负载或停机维护

五、写出一个 HTTP post 请求的内容,包括四部分。
其中第四部分的内容是 username=ff&password=123
第二部分必须含有 Content-Type 字段
请求的路径为 /path

POST /path HTTP/1.1
Host: www.baidu.com
User-Agent: curl/7.59.0
Accept: /
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

username=ff&password=123

六、一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

1.DNS解析
DNS解析的过程就是根据域名查找 IP 地址。
如果浏览器有缓存,直接使用浏览器缓存,否则使用本机缓存,再没有的话就是用host
如果本地没有,就向dns域名服务器查询(当然,中间可能还会经过路由,也有缓存等),查询到对应的IP
2.TCP连接
浏览器根据 IP 地址向服务器发起 TCP 连接,与浏览器建立 TCP 三次握手:
(1)客户端:hello,你是server么?
(2)服务端:hello,我是server,你是client么
(3)客户端:yes,我是client
建立连接成功后,接下来就正式传输数据
3.发送HTTP请求
HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文。
4.服务器处理请求并返回HTTP报文
HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文。
5.浏览器解析渲染页面
浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件生成CSS规则树。
开始构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。
6.关闭TCP连接或继续保持连接
通过四次挥手关闭连接。
(1)主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
(2)被动方:收到通道关闭的信息
(3)被动方:那我也告诉你,我这边向你的主动通道也关闭了
(4)主动方:最后收到数据,之后双方无法通信

七、如何实现数组去重?
假设有数组 array = [1,5,2,3,4,2,3,1,3,4]
你要写一个函数 unique,使得
unique(array) 的值为 [1,5,2,3,4]
也就是把重复的值都去掉,只保留不重复的值。

要求:

不要做多重循环,只能遍历一次
请给出两种方案,一种能在 ES 5 环境中运行,一种能在 ES 6 环境中运行(提示 ES 6 环境多了一个 Set 对象)

1.indexOf()

1
2
3
4
5
6
7
8
9
function unique(array) {
let newArray = []
for (let i = 0; i < array.length; i++) {
if (newArray.indexOf(array[i]) == -1) {
newArray.push(array[i])
}
}
return newArray
}

2.Set对象

1
2
3
function unique(array) {
return [...new Set(array)]
}

123
wwj

wwj

23 日志
12 标签
GitHub
推荐阅读
  • JavaScript教程
  • 张鑫旭
  • Web前端导航
  • 中文参考手册
  • 百度前端技术学院
  • google前端开发基础
© 2019 wwj
由 Hexo 强力驱动
主题 - NexT.Muse
博客全站共20.6k字