每个vue实例在被创建时候都要经历一系列的初始化过程,
设置数据监听,编译模板,将实例挂载到DOM并在数据变化时更新DOM,
同时这个过程会运行一些生命周期函数钩子,
created:实例被创建
mouted,updated,destroyed.
计算属性的使用:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var vm = new Vue({
el:"example",
data:{
message:"hello
},
computed:{
vm.reverseMessage依赖于message,所以message一旦变化 reverseMessage就会变化
reverseMessage:function() {
return this.message.split('').reverse().join('');
},
fullName:{
//get和set方法
get:function(){
return this.firstName
}
set:function(newValue){
this.firstName = "ckq"
}
}
}
})
计算属性是基于它们的响应式依赖进行缓存的,只有相关响应式发生了变化,才会重新求值。
message没变化,多次访问reverseMessage。计算属性还是返回之前计算的结果。
而不必再次执行函数。
侦听属性,利用watch:1
2
3
4
5watch:{
firstName:function(val){
this.fullName = val + this.lastName;
}
}
通过class和style绑定属性的时候,可以通过对象或者是数组1
<div v-bind:class = "{active:isActive}"></div>
active这个class是否加载决定于isActive属性是否为true1
2
3
4
5
6data:{
classObj:{
active:true,
'text-danger':false
}
}
数组的方法1
<div v-bind:class = "[active,error]">
内联样式的绑定1
<div v-bind:style = "{color:active}"></div>
v-if用于条件渲染
v-if与v-else联合使用 v-else-if联合使用1
2
3
4<template v-if = "ok">
<h1>title</h1>
<p>p1</p>
</template>
v-if与v-show的区别
v-if是真正的条件渲染,当为false时会删除dom
而v-show是是会修改其css属性来展现与否。
当不存在的时候,v-if是从dom中移除,v-show为隐藏,不从dom中移除。
v-for的使用1
2
3
4<li v-for = "(item,index) in items">
<li v-for = "(value,name,index) in object">
{{index}} --{{item.message}}
</li>
当vue正在更新使用v-for渲染的元素列表时,使用”就地跟新”原则,
如果数据项的顺序被改变,vue将不会移动dom元素来匹配数据项的顺序,而是就地跟新每个元素,并且确保在每个索引位置都被
正确的渲染。类似于vue 1.x中的track-by = “$index”
可以使用key进行绑定1
2<div v-for = "item in items" v-bind:key = "item.id">
</div>
利用响应式
Vue.set(vm.items,indexOfItems,value);
当处于同一个节点时,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中,当你只想为部分项渲染节点时,这种优先级机制十分有用。1
<li is = "todo-item" v-for = "(todo,index) in todos">
的 is=”todo-item” 属性。这种做法在使用 DOM 模板时是十分必要,这么做实现的效果与1
<todo-item>
相同。
但是可以避开一些潜在的浏览器解析错误。
v-on:click.stop = “doThis”
v-on:submit.prevent = “on
v-on:keyup.13 = “submit”
@click.ctrl = “onclick”
v-model在表单input,textarea以及select上创建数据的双向绑定
v-model本质上还是语法糖,负责监听用户的输入事件并且更新数据。并对一些极端场景进行一些特殊处理。
会忽略所有表单的check,value,select值。
总是将vue实例的数据作为数据来源。应该通过js在组件中data选项声明初始值。
vue自定义组件1
2
3
4
5
6
7
8
9//vue自定义组件
Vue.component('button-counter',{
data:function () {
return{
count:0
}
},
template:'<button v-on:click = "count++">'
})
与new Vue接收相同的选项 例如data,computed,watch,methods等以及生命周期函数钩子
data必须是一个函数。而不是一个对象,因此每个实例可以维护一份被返回对象的独立的拷贝1
2
3
4
5data:function(){
return{
count:0
}
}
Vue.component是全局注册的
通过props向子组件传递数据
一个值传递给props,就变成了组件实例的一个属性1
2
3
4Vue.component('blog',{
props:['title'],
template:'<h3>{{title}}</h3>'
})
就像访问data中的数据是一样的1
<blog-post :key = 'post.id' :title = 'post.title'>
每个组件必须要有一个根元素,可以将模板的内容包裹在一个根元素内。1
2
3
4<div>
<h3>{{title}}</h3>
<div v-html = "content"></div>
</div>
component的is属性来切换组件1
<component v-bind:is="currentTabComponent"></component>
vue组件注册通过1
2
3
4
5vue.component('my-comment-name',{
})
//使用时候
<my-component-name></my-component-name>
全局注册往往不理想,局部注册1
2
3
4
5
6
7
8var ComponentA = {};
new Vue({
el:"#app",
components:{
'component-a':ComponentA,
}
});
导入组件1
2
3
4
5
6import ComponentA from './ComponentA';
export default{
components:{
ComponentA
}
}
props传递对应的值类型1
2
3
4props:{
title:String,
likes:Number
}
提供了类型检测 在使用时。
任何类型的值都可以传递给props1
2
3
4
5
6
7
8
9<blog-post v-bind:likes = "42"></blog-post>
<blog-post v-bind:is-publish = "false"></blog-post>
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>
props都是单向数据流的传递 父级props的跟新会向下流动到子组件中,但是反过来是不会的。
这样可以阻止子组件意外改变父组件的状态
每次父组件发送变化,子组件props都会刷新为最新的值
注意:js中对象和数组都是通过引用传入的,所以对于一个数组或者对象类型的props,在子组件中改变这个对象或数组本身将会影响在父组件中的状态。
注意prop会在一个组件实例创建之前进行验证,所有实例的属性,例如data,computed等在函数中是不可用的。
事件名:事件名不存在任何自动化的大小写转换。而是触发的事件名必须匹配这个事件所用的名称
触发事件1
this.$emit("myEvent")
随后在组件上绑定事件1
<my-component v-on:my-event = "doSomthing">
自定义事件重点看
自定义指令,在页面打开后,应该自动聚焦到输入框上1
2
3
4
5Vue.directive('focus',{
inserted:function(el){
el.focus();
}
})
指令的钩子函数
bind:只调用一次,指令第一次绑定到元素时调用,在这里可进行一次性的初始化操作。
inserted:被绑定元素插入到父节点时调用,(仅保证父节点存在,但不一定已被插入到文档中)
updated:所有组件的VNode更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的VNode及其子VNode全部跟新后调用
unbind:只调用一次,指令与元素解绑时调用。
尝试使用render函数来做渲染1
2
3
4
5
6
7
8
9
10
11
12
13
14Vue.component('anchor',{
render:function(createElement){
return createElement(
'h' + this.level, //标签名称
this.$slots.default//子节点数组
)
},
props:{
level:{
type:Number,
}
}
})
createElement返回的是createNodeDescription,因为它所包含的信息会告诉vue页面上需要渲染什么节点。包括其子节点的描述信息。
插件的使用
通过全局的方法Vue.use()来加载使用插件
需要在new Vue()之前使用1
2
3var Vue = require('vue');
var vueRouter = require('vue-router');
Vue.use(vueRouter);
过滤器
双括号插值1
2
3
4
5
6
7
8
9{{message | capitalize}}
filters:{
capitalize:function(value){
if(!value)
return '';
value = value.toString();
return value.charAt(0);
}
}
过滤器的连续使用1
{{message | filterA | filterB}}
将过滤器A执行完的结果传递给过滤器B
vue单文件的预处理器1
2
3
4
5
6
7
8
9
10
11
12
13
14<template lang = "jade">
<div>
ccc
</div>
<script>
export default{
data() {
}.
components:{
otherComponents
}
}
</script>
vue进行异步跟新DOM的情况,一些依赖DOM更新结果的断言必须在
vue.nextTick中回调中进行。1
2
3
4
5
6Vue.nextTick(() => {
expect(vm.$el.textContent).toBe('foo');
done();
});
process.env.NODE_ENV
vue源码根据process.env.NODE_ENV决定是否启用生产环境模式,默认为开发环境模式。
服务端渲染
通过nuxt.js搭建服务端渲染。nuxt是一个基于vue生态的更高层的框架,为开发服务端渲染的 Vue 应用提供了极其便利的开发体验。更酷的是,你甚至可以用它来做为静态站生成器。推荐尝试。
this.$nextTick保证元素被挂载到dom中才触发1
2
3
4
5mounted: function () {
this.$nextTick(function () {
// 代码保证 this.$el 在 document 中
})
}
vue中slot的使用
vue中slot的使用1
2
3
4
5
6
7
8
9
10
11
12<div id = "app">
<child>
<span>1111</span>
</child>
</div>
<script>
Vue.component("child",{
template:"<div>这是一个div标签</div>"
});
new Vue({
el:"#app"
})
child内部的span等标签会被div等所有的覆盖掉 没有slot的情况1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<div id = "app">
<computer>
<div slot = "CPU">ddd</div>
<div slot = "GPU">GPU</div>
</computer>
</div>
<script>
Vue.component("computer",{
template:`<div>
<slot name = "CPU">CPU插槽</slot>
<slot name = "GPU">GPU插槽</slot>
</div>
`,
});
new Vue({
el:"#app"
})
根据name进行绑定 将slot具体渲染成对应组件
单个slot的情况
简单来说,使用slot标签,可以将1111放到子组件中想让他显示的地方1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<div id = "app">
<child>
<span>1111</span>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})
子组件内部的slot标签会被渲染成1111所以可以将父组件中的传过来
有多个标签的时候也会被插入,被当成一个slot来看待
具名slot(有名称的slot)
将放在子组件里的不同html标签放在不同的位置
父组件在要分发的标签里面添加slot = “name名”的属性
子组件在对应的分发位置的slot标签里面,添加name = “name”属性,
然后会将对应的标签放在位置里1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<div id = "app">
<child>
<span slot = "one">one</span>
<span slot = "two">two</span>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot name = "two"></slot>
一个div
<br>
这是<slot name = "one"></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})
将父标签里的two渲染到子组件里的第一个,将父标签里的one渲染到子组件李的第二个
没有slot的话,将会显示默认的值。
也就是没有将父组件中的slot插入到子组件中1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<div id = "app">
<child>
<span slot = "one">one</span>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot name = "two">no two</slot>
一个div
<br>
这是<slot name = "one"></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})
slot = two 没有标签,因此显示内部的no two
作用域插槽是一种特殊类型的插槽,用作一个(能被传递数据的)可重用模板,来代替已经渲染好的元素,
在子组件中,只需要将数据传递到插槽,就想你将prop传递给组件一样,
在父级中,具有特殊属性slot-scope的template的元素必须存在,表明它是作用域插槽的模板。
slot-scope的值被用作一个临时变量,此变量收集从子组件传递过来的props1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<div id = "app">
<child>
<template slot-scope = "props">
<p>hello from parent</p>
<p>{{props.tt}}</p>
</template>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
<slot tt = "hello from child"></slot>
</div>
`,
});
new Vue({
el:"#app"
})
将子组件的传递到父组件中,如下示例,当子组件循环的时候,某一部分dom结构由外部传递进来,
使用作用域插槽,子组件可以向父组件插槽传递数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<div id = "root">
<child>
<template slot-scope = "props">
<p>{{props.item}}</p>
</template>
</child>
</div>
<script>
Vue.component('child',{
data:function () {
return{
list:[1,2,3,4,5]
}
},
template:`
<div>
<slot v-for='item of list' :item = item></slot>
`
})
var vm = new Vue({
el:"#root"
})
作用域插槽,统一为渲染的模板。为不同的渲染添加值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<div id="components-demo">
<my-list title="caokaiqiang" :items="shapes">
<div slot-scope="vv">{{vv.name}}<small>({{vv.sides}}条边)</small></div>
</my-list>
<my-list title="颜色" :items="colors">
<div slot-scope="ad">
<div class="colorbox" :style="{background:ad.hex}">{{ad.name}}</div>
</div>
</my-list>
</div>
<script>
Vue.component('my-list', {
props:["title","items"],
template: `
<div class="my-list">
<h3 class="title">{{title}}</h3>
<div class="list">
<slot v-bind="item" v-for="item in items"></slot>
</div>
</div>
`
})
new Vue({
el: '#components-demo',
data:{
shapes:[{ name:'正方形', sides:4},{ name:'六边形', sides:6},{ name:'三角形', sides:3}],
colors:[{ name: '黄色', hex: '#f4d03f' },{ name: '绿色', hex: '#229954' },{ name: '紫色', hex: '#9b59b6' }]
}
})
两个组件中相同的slot的for循环放到子组件中slot来代替,随后通过slot-scope和绑定:item来从父组件中传递数据到子组件中
vue子组件向父组件中传递值,通过触发事件1
this.$emit('parent-show');
在组件中绑定事件
1
2
3
4
5
6<component1 @parent-show = 'show'>
methods:{
show:function() {
console.log("父组件中的方法");
}
}
在vue中,通过ref属性获取DOM元素的值1
2<h3 id = "myH3" ref = "myTitle"></h3>
console.log(this.$refs.myTitle.innerText);
vuex使用笔记
state是统一状态的管理,对state的改变只能通过action来改变1
2
3
4
5
6
7
8
9var store = {
debug:true,
state:{
message:"hello"
},
setMessage(newValue){
this.state.message = newValue;
}
}
组件不允许直接修改属于store实例的state,而应该执行action来分发(dispatch)事件通知store去改变,我们最终也达成了flux架构,这样约定的好处,我们能够记录所有store中发生的state改变,同时实现能做到记录变更(mutation),保存状态快照,历史回滚等。
应用遇到多个组件共享状态时,需要多个组件依赖同一个状态,或是来自不同视图的行为来修改同一个状态。
vuex是一个专门为vue.js开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方法发生变化,对vue中多个组件的共享状态进行集中式的管理
全局拥有一个state存放数据,组件修改state中的数据时,必须通过mutation进行,mutation同时提供了订阅者模式提供外部插件调用来获取state数据的更新,当所有的异步操作结束后,常见于action操作后,action通过mutation来修改state的数据,最后state通过渲染再呈现到html上。
dispatch:操作行为触发方法,唯一执行action的方法
action:操作行为处理模块,组件中的$store.dispatch(‘action’,detail)来触发
然后通过commit交给mutation,mutation通过同步操作来修改state中的值。
store.js文件的创建,里面来存储相应的state,mutation,action和getter函数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
40import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//创建store
const store = new Vuex.Store({
state:{
count:0
},
//mutation来修改store
mutations:{
INCREMENT(state){
state.count = state.count + 1;
},
DECREMENT(state){
state.count = state.count - 1;
}
},
getters:{
//通过读取属性自动调用并返回属性值
evenOrOdd(state){
return state.count % 2 == 0 ? "偶数" : "奇数";
}
},
actions:{
//包含了多个异步操作 包含了多个直接更新state函数的对象
incrementIfOdd({commit,state}){
if(state.count % 2 === 1)
commit('INCREMENT');
},
incrementAsync({commit}){
setInterval(() => {
commit('INCREMENT')
},2000);
}
}
})
//导出
export default store;
习惯于mutation中的函数名称是大写的,而action中是小写的。
随后在main.js中使用创建好的store.js文件1
2
3
4
5import store from './store';
new Vue({
render: h => h(App),
store,
}).$mount('#app')
在helloWorld.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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40<template>
<div class="hello">
<p>click{{count}} times,count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">increment if odd-</button>
<button @click="incrementAsync">increment async-</button>
</div>
</template>
<script>
export default {
name:"HelloWorld",
computed:{
count(){
return this.$store.state.count;
},
evenOrOdd(){
//计算型属性来计算值 通过state来获取
return this.$store.getters.evenOrOdd;
}
},
methods:{
//同步加载
increment(){
this.$store.commit('INCREMENT');
},
decrement(){
this.$store.commit("DECREMENT");
},
incrementIfOdd(){
//通过dispatch触发action
this.$store.dispatch('incrementIfOdd');
},
incrementAsync(){
this.$store.dispatch('incrementAsync');
}
}
}
</script>
如果想直接使用mutation,通过this.$store.commit(“INCREMENT”)来直接使用,
如果想通过异步,则通过dispatch触发action,再通过action来触发mutation
this.$store.dispatch(“incrementAsync”);
通过简便的方法来缩写action,mutation,getter和state1
2
3
4
5
6
7
8
9
10import { mapActions, mapGetters, mapState, mapMutations } from "vuex";
...
computed: {
...mapState(["count"]),
...mapGetters(["evenOrOdd"])
}
methods: {
...mapActions(["incrementIfOdd", "incrementAsync"]),
...mapMutations(["increment", "decrement"])
}
注意的是mapMutation中的和methods中的方法名称必须保持一致。
getters可以看做在获取数据前对数据进行的进一步加工
action和mutation的区别,action是异步跟新,mutation是同步跟新
同步的意义在于每一个mutation的跟新都对应一个新的状态,可以看到mutation是如何改变的。
mutation传递参数1
2
3
4
5this.$store.commit('INCREMENT',2);
随后在mutation中添加
INCREMENT(state,n){
state.count = state.count + n;
},
vue直播课
provide & inject 类似react中的上下文
provide在父组件中注入,在子组件中就可以进行获取
inject:[‘title’] 祖先元素提供的 不需要通过props 来一个个传值
但是provider和inject不是响应式的,如果子孙元素想要通知祖先,就需要hack一下,vue1中有dispatch和boardcast2个方法,但是vue2中被干掉了。我们可以自己模拟一下。
原理就是可以通过this.parent和boradcast获取子元素,this.children来获取父组件和子组件,我们自己递归一下即可。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
49dispatch(eventName,data){
let parent = this.$parent;
parent = parent.$parent;
borardcast.call(child,eventName,data);
}
//全局挂载的方法
Vue.prototype.$dispatch = function(eventName,data){
//向上传递 一直不停的获取$parent
let parent = this.$parent;
while(parent){
parent.$emit(eventName,data);
parent = parent.$parent;
}
}
//子元素
Vue.prototype.$boardcast = function(eventName.data){
//通知递归所有子元素
boardcast.call(eventName,data);
}
function boardcast(eventName,data){
this.$children.forEach(child => {
child.$emit(eventName,data);
if(child.$children.length){
boardcast.call(child,eventName,data);
}
})
}
this.$on("boardcast",msg => {
console.log();//通过监听
})
eventBus全局实现
class Bus{
constructor(){
this.callBacks ={
}
//监听 触发
$on(name,fn){
this.callBacks[name] = this.callBacks[name] || [];
this.callBacks[name].push(fn);
}
$emit(name,args){
if(this.callbacks[name]){
this.callbacks[name].forEach(cb => cb(args));
}
}
}
}
Vue.prototype.$bus = new Vue();
$bus触发所有的事件
自定义input监听on和input事件即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<input :type = "type" :value = "value" @input = "onInput">
methods:{
onInput(e){
this.$emit("input",e.target.value);
this.$parent.$emit("validate");
}
}
v-model的语法糖
k-form-item 负责显示label 执行校验,和显示校验结果 插槽作组件扩展
form进行全局校验
能够获取全部的规则
inject:["form"];
models:{"username":"","password":""},
rules:{
username:[
{required:true,message:"请输入用户名"}
]
};
schema来做校验
import Schema from 'async-validator'
每个item都有validate方法
单元测试:站在外层来进行测试,期望获取的结果是想要的
vue router在实现前端应用时,使用hash模式和history模式
默认hash模式:使用URL的hash来模拟一个完整的URL,于是当URL改变时,页面不会重新加载。
hash(#)是URL中的锚点,代表的是网页中的位置,单改变#后面的值,不会重新加载网页,只会滚动到相应的位置。
hash出现在URL中,但不会出现在http中,不会对后端请求发生影响。
同时改变hash,会在浏览器访问历史中增加一个记录,使用后退按钮,就会回到上一个位置。
history模式:url像正常的url,例如http://www.baidu.com/user/id;
不过这种模式要弄好,还需要后台配置支持。因为我们的应用是SPA,如果后台没有正确的配置,用户访问时就会出现404,
要在服务端增加一个覆盖所有情况的候选资源,如果URL匹配不到任何静态资源,则应该返回同一个index.html的页面。
属性,事件和插槽3个vue基础概念。
属性:自定义属性props,原生属性attrs,特殊属性class,style。
props:称为静态数据,vue是单向数据流,数据传递时不能改变数据类型,而且不允许子组件中直接操作。
.sync实现双向绑定1
2
3
4
5
6
7
8
9
10
11
12<demo :show.sync = "show" :msg.sync = "msg" :arr = "arr>
props: {
msg: {
type: String
},
show: {
type: Boolean
},
arr: {
type: Array //在子组件中改变传递过来数组将会影响到父组件的状态
}
},
通过props从父组件传递到子组件中
vue中是由数据驱动的,是指视图是由数据驱动生成的。
对视图的修改,不是直接操作DOM,而是修改对应数据。
用户执行某个操作 -> 反馈到VM处理(可以导致model变动) -> VM层改变,通过绑定关系直接更新页面对应位置的数据。
.lazy事件,以往通常是input中一旦键入键盘就触发change事件,现在可以转变为当输入完所有内容后,光标离开才跟新视图的场景。
render和template都定义,执行render
Vue.use函数 插件和事情
plugin.install 是方法.
plugin.install.apply(plugin,args);
plugin都会执行
vuex刷新就没了 localStorage还存储在数据中
强类型 typescript
vuex源码!!!typescript和docker1
2
3
4
5
6
7
8
9
10
11
12
13<script lang = "ts">
export default Vue.extend({
})
</script>
import Hello form "./components/Hello.vue
@Component({
components:{
HelloWorld,Hello
}
})
export default class App extends Vue{};
1.vue-cli
2.数据mock,跨域,假数据
3.工作流 githook eslint
4.webpack 模块化原理
5.vuex源码
6.router 看了源码
7.jwt中的具体操作
登录 网络拦截器 token 路由权限 addRoutes
token是一段加密字符串 加密函数(用户id + 随机数 + 过期时间)
解密token token放在header之上 token 1.注销登录 2.过期了 对称加密
npm run build dist包
线上机器有一个nginx目录
1.前端有一个部署机jekins 跑build copy代码,上线
2.push之后,jekins点按钮,打包ssh到机器上 解压
3.push之后,github或者gitlab的webhook 重新发布docker.
devops自动运维。
SSR服务端渲染,后端把vue或者react解析成DOM标签,首屏就能直接渲染dom.
nuxt就是SSR的最佳实践框架。
cloc ./ 看代码有几行
nginx和proxy区别,本地使用webpack-dev-serve的proxy做转发
线上没有webpack,有nginx,由nginx做转发。
vuex存储的变量什么时候销毁
缓存策略 LRU last recent use
队列:谁用得多留下来 谁用得少慢慢销毁
权限 网络拦截 性能优化 热重载 扩展 原理
编译 模板 -> render函数 runtime
源码顺序
package.json
main 和 module
版本 不同方式引入
core -> instance -> init.js
initState,$mount 虚拟dom _render,_update,
整个的入口
web/entry-runtime-with-compiler.js
compiler 将template 编译成render函数 返回虚拟dom createElement
如果没有compile模块 文件变小,但只支持render
core 核心
platforms 平台 web weex
server 服务端渲染相关
sfc .vue文件解析 单页面解析 script style template
shared 公用的方法和常量
new Vue({
template:
})
编译成
render:h => {
return h(‘div’,{attrs:{id:app}},this.name);
}
每一个依赖放到watcher里面
watcher放到dep里面 dep放到defineReactive里面去收集
observer观察dep
解析dom内容 k-model事件
this.$compile = new Compile()
vue vuex vue-router全家桶代码
node 最佳实践 eggjs 1.1mvc分层 约定大于配置 nginx+docker部署
mixin 是自己的 extend给儿子了 是继承
react推荐用umi 脚手架
auth2第三方登录 微信 微博登录
虚拟dom就是object对象123 createElement({div,id:app,123}),大的object对象,模拟树形结构
{
type:div,
props:{id:div},
children[
{type:组件}
]
}
ast抽象语法树 super-tiny-compiler 前端编译
codegen
vue的生命周期函数
在newVue后 首先初始化事件event和生命周期lifecycle等
实际就是往上面挂载一些函数
这里到达的是beforeCreate
随后是初始化provide和inject中的一些实例
这里data和props都已经加载完毕 可以调用
随后将el元素挂载上去,如果有模板编译的话,首先执行模板编译生成render函数 这里是挂在前beforeMount
随后根据render函数产生虚拟dom,真正的渲染到dom上,触发mouted,在update的时候,根据不同情况产生不同的虚拟dom进行对比,利用patch算法进行对比和渲染,到真正的dom上。在销毁的时候触发beforeDestroy方法。将监听组件等全部取出,随后触发destroy方法
生命周期链接
生命周期最好的回答
性能优化
文件更快加载 文件执行次数更少
很多dom都是可以重用的 整个dom的元素就这么多
整个3屏 整个的dom元素是不会增加的,上面去除的拿到下面来添加上 上面的屏幕都放到下面来 骨架屏
SSR 服务端渲染