Bootstrap

【图文并茂,点赞收藏哦!】重学巩固你的Vuejs知识体系

哪吒人生信条:如果你所学的东西 处于喜欢 才会有强大的动力支撑。



每天学习编程,让你离梦想更新一步,感谢不负每一份热爱编程的程序员,不论知识点多么奇葩,和我一起,让那一颗像四处流荡的心定下来,一直走下去,加油,加油!欢迎关注,欢迎点赞、收藏和评论



不要害怕做梦,但是呢,也不要光做梦,要做一个实干家,而不是空谈家,求真力行。前沿

置身世外只为暗中观察!!!Hello大家好,我是魔王哪吒!重学巩固你的Vuejs知识体系,如果有哪些知识点遗漏,还望在评论中说明,让我可以及时更新本篇内容知识体系。欢迎点赞收藏!

谈谈你对MVC、MVP和MVVM的理解?

https://github.com/webVueBlog/interview-answe/issues/156

转角遇到Vuejs

目录:

起步

组件化开发:

什么是组件化,Vue组件化开发思想

组件化高级语法:

Vue Cli

网络封装

axios的使用

vuejs原理相关:响应式原理,源码。

vue.js是什么

  • vue是一套用于构建用户界面的渐进式框架。

  • 从自底向上逐层应用,核心库是只关注图层。

  • 易于学习,便于与第三方库或既有项目整合。

Vue基础语法

对于基础知识需要掌握,简单写写✍

vue.js安装

直接CDN引入:

代码:

代码:

代码:

# 最新稳定版
$ npm install vue

vue响应式初体验

声明式编程:

代码:




	
		
		
		
		
	
	
		
{{ a }}

小案例-计算器

代码:

当前计数{{counter}}

Vue中的MVVM

MVVM的思想

它们之间是如何工作的呢?

  • :类型:

  • 作用:决定之后Vue实例会管理哪一个

  • :类型:

  • 作用:Vue实例对应的数据对象

  • :类型:

  • 作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。

什么是Vue的生命周期

生命周期:☞ 事物从诞生到消亡的整个过程

  • 稳定版本

  • 版本

指令的使用

{{message}}

{{message}}

当我们从服务器请求到的数据本身就是一个HTML代码时

的作用和比较相似,独使用于将数据显示在界面中,一般情况下,接受一个类型。

{{message}}

用于跳过这个元素和它子元素的编译过程,用于显示原本的语法。

{{message}}

斗篷的意思。

hello{{name}}

v-bind的介绍

用于绑定一个或多个属性值,或者向另一个组件传递值。



绑定有两种方式:

对象语法:

用法一:直接通过{}绑定一个类

hello

用法二,传入多个值

hello

用法三:

用法四: 可以放在一个methods或者computed中

hello

动态绑定class,数组语法

{{mesg}}

{{mesg}}

动态绑定style

对象语法和数组语法两种绑定。

绑定方法:对象语法:

:style="{ color: currentColor, fontSize: fontSize + 'px' }"

后面跟的是一个对象类型,对象的是属性名称,对象的是具体赋的值,值可以来自于中的属性。

绑定方法:数组语法:

后面跟的是一个数组的类型,多个值,分割即可。

计算属性的基本属性

计算属性,写在实例的选项中:

{{firstName}}{{lastName}}

{{fullName}}

计算属性的缓存:

为什么使用计算属性这个东西?

原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次。

setter和getter

每个计算属性都包含一个getter和一个setter

{{fullName}}
{{firstName}}
{{lastName}}

computed: {
    fullName: function() {
        return this.firstName+" "+this.lastName
    }
    
    // 计算属性一般是没有set方法,只读属性。
    fullName: {
        get: function() {
            return this.firstName + " " + this.lastName
        }
    }
}

const的使用

const的使用,在JavaScript中使用const修饰的标识符为常量,不可以再次赋值。

在es6开发中,优先使用const,只有需要改变一个标识符的时候才使用let。

在使用cost定义标识符,必须进行赋值。

常量的含义是指向的对象不能修改,但是可以改变对象内部的属性。

什么时候使用const呢?

当我们修饰的标识符不会被再次赋值时,就可以使用const来保证数据的安全性。

const的使用:

const a=20;
a = 10; // 错误:不可以修改

const name; // 错误,const修饰的标识符必须赋值

let和var

块级作用域:

JS中使用var来声明一个变量,变量的作用域主要是和函数的定义有关。

对于其他块定义来说是没有作用域的,比如if/for等,开发中往往会引发一些问题。

// 监听按钮的点击
var btns = document.getElementsByTagName('button');
for(var i=0; i

let btns = document.getElementsByTagName('button');
for(let i=0;i

块级作用域

变量作用域:变量在什么范围内是可用的。

var func;
if(true) {
    var name = 'web';
    func = function() {
        console.log(name); // web
    }
    
    func(); // web
}

// name = 'it'
func(); // web -> it
console.log(name); // web -> it

没有块级作用域引起的问题,for的块级

var btns = document.getElementsByTagName('button');
for(var i=0; i

闭包:

var btns = document.getElementsByTagName('button');
for(var i=0; i

为什么闭包可以解决问题,因为函数是一个作用域。

对象的增强写法

属性初始化简写和方法的简写:

// 属性的简写
// es6前
let name = 'web'
let age = 12
let obj1 = {
    name: name,
    age: age,
}
console.log(obj1);
// es6后
let obj2 = {
    name, age
}
console.log(obj2)

// 方法的简写
// es6之前
let obj1 = {
    test: function() {
        console.log('obj1')
    }
}
obj1.test();

// es6后
let obj2 = {
    test() {
        console.log('obj2')
    }
}
obj2.test();

v-on基础

点击次数:{{counter}}

let app = new Vue({ el: '#app', data: { counter: 0 }, methods: { btnClick(){ this.counter++ } } })

v-on修饰符的使用

web

Vue提供了一些修饰符:

.stop 调用event.stopPropagation()

.prevent 调用event.preventDefault()

.native 监听组件根元素的原生事件

.once 只触发一次回调

// 停止冒泡


// 阻止默认行为


// 阻止默认行为,没有表达式
// 串联修饰符 // 键修饰符,键别名 // 键修饰符,键代码 // 点击回调智慧触发一次

v-if,v-else-if,v-else

简单使用:

优秀

良好

及格

不及格

登录切换:

v-for遍历对象

  • {{value}}-{{key}}-{{index}}

组件的Key属性

使用v-for时,给对应的元素或组件添加上一个属性。

key的作用主要是为了高效的更新虚拟dom。

数组中哪些方法是响应式的

push()
pop() 删除数组中的最后一个元素
shift() 删除数组中的第一个元素
unshift() 在数组最前面添加元素

splice()
sort()
reverse()

购物车

书籍名称 出版日期 价格 购买数量 操作
{{value}}

表单绑定v-model

vue中使用v-model指令来实现表单元素和数据的双向绑定。

{{message}}

reduce作用对数组中所有的内容进行汇总。

JavaScript reduce() 方法

var numbers = [65, 44, 12, 4];
 
function getSum(total, num) {
    return total + num;
}
function myFunction(item) {
    document.getElementById("demo").innerHTML = numbers.reduce(getSum);
}

定义和用法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

reduce() 可以作为一个高阶函数,用于函数的 compose。

注意: 对于空数组是不会执行回调函数的。

语法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

v-model的使用以及原理



是语法糖,本质:

代码:



v-model:checkbox

复选框分为两种情况,单个勾选框和多个勾选框。

单个勾选框:

即为布尔值。的并不影响的值。

多个复选框:

当是多个复选框时,对应的中属性是一个数组。

当选中某一个时,就会将的添加到数组中。

v-model:select

分单选和多选两种情况

单选:只能选中一个值,多选:可以选择多个值。

v-model结合select类型

和一样,分单选和多选两种情况。

单选,只能选择一个值,绑定的是一个值。当我们选中中的一个时,会将它对应的赋值到中。

多选,可以选中多个值。绑定的是一个数组。当选中多个值时,就会将选中的对应的添加到数组中。

// 选择一个值

您最喜欢的{{mySelect}}

// 选择多个值

您最喜欢的{{mySelects}}

input中的值绑定

修饰符

修饰符:

修饰符:

修饰符:

示例:

{{message}}

什么是组件化

注册组件的基本步骤:

示例:

调用Vue.extend()方法创建组件构造器
调用Vue.component()方法,注册组件
在Vue实例的作用范围内使用组件

组件示例:

全局组件和局部组件

示例:

组件标题

示例:

父组件和子组件

组件树

示例:

// 注册局部组件的语法糖 const app = new Vue({ el: '#app', data: { message: 'web' }, components: { 'cpn2': { template: `

web

` } } })

简化了注册组件的方式,提供了注册的语法糖。

组件模板抽离的写法

提供了两种定义模块内容:

示例:

标签


// 注册一个全局组件
Vue.component('cpn', {
 template: '#cpn'
})

组件可以访问vue实例数据吗

组件是一个单独的功能模块封装,有属于自己的模板和自己的数据。

组件对象有一个属性,属性,这个属性必须是一个函数,函数返回一个对象,对象内部保存着数据。

在 中,父子组件的关系

向下传递,事件向上传递。

父组件通过 给子组件下发数据,子组件通过事件给父组件发送消息。

支持的数据类型:

String

Number

Boolean

Array

Object

Date

Function

Symbol

示例:

Vue.component('my-component',{
 props: {
     // 基础的类型检查
     propA: Number,
     // 多个可能的类型
     propB: [String, Number],
     // propC: {
         type: String,
         required: true
     },
     // 带有默认值的数字
     propD: {
         type: Number,
         default: 100
     },
     // 带有默认值的对象
     propE: {
         type: Object,
          default: function(){
              return {message: 'web'}
          }
     },
     // 自定义验证函数
     propF: {
         vfunc: function(value) {
             return value > 1
         }
     }
 }
})

子传父

代码:

this.$emit('item-click',item)

用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。

自定义事件:

自定义事件代码:

点击次数

let app = new Vue({ el: '#app', data: { total: 0 }, methods: { changeTotal(counter) { this.total = counter } }, components: { 'child-cpn': { template: '#childCpn', data(){ return{ counter: 0 } }, methods: { increment(){ this.counter++; this.$emit('increment', this.counter) }, decrement(){ this.counter--; this.$emit('decrement',this.counter) } } } } })

父子组件的访问方式:$children

有时候需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问父组件。

对于的访问:

示例:

// 父组件template // 子组件 // 子组件 Vue.component('parent-cpn',{ template: '#parentCpn', methods: { showChildCpn(){ for(let i=0; i

父子组件的访问方式:$parent

子组件中直接访问父组件,可以通过

父子组件的访问方式

的缺陷:

的使用:

示例:





show() {
    console.log(this.$refs.child1.message);
    console.log(this.$refs.child2.message);
}

看看一个文件项目





三层部分:

slot插槽的使用

中的代码是什么呢,它叫插槽,元素作为组件模板之中的内容分发插槽,传入内容后元素自身将被替换。

用法:

默认插槽

子组件:

// 子组件

基本使用

子组件定义一个插槽:

示例:

web

使用具名插槽

示例:

// 没有任何内容 // 传入某个内容 left left center right

编译作用域

实例属性:

父组件模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在子级作用域内编译。

父组件替换插槽的标签,但是内容由子组件来提供。

模块化开发

什么是模块化,将一组模块以正确的顺序拼接到一个文件中的过程,模块是实现特定功能的一组属性和方法的封装。

利用构造函数封装对象

function web() {
    var arr = [];
    this.add = function(val) {
        arr.push(var)
    }
    this.toString = function() {
        return arr.join('')
    }
}
var a = new web();
a.add(1); // [1]
a.toString(); // "1"
a.arr // undefined

示例:

var ModuleA = (function(){
    // 定义一个对象
    var obj = {}
    // 在对象内部添加变量和方法
    obj.flag = true
    obj.myFunc = function(info) {
        console.log(info)
    };
    // 将对象返回
    return obj
}

if(ModuleA.flag) {
    console.log('web')
}

ModuleA.myFunc('webweb')

常见的模块化规范:

,,,中的

什么是,异步模块定义,它是在浏览器端实现模块化开发的规范,但是该规范不是原生支持的,使用规范进行开发的时候需要引入第三方的库函数,就是。

解决了多个文件可能有依赖的关系,被依赖的文件需要早于依赖它的文件加载到浏览器;加载的时候浏览器会停止页面渲染,加载文件越多,页面就会失去响应时间越长。

是什么,它是通用模块定义,解决的问题和一样,不过在模块定义方式和模块加载时机上不同,需要额外的引入第三方的库文件。

JavaScript模块化编程

那么什么是模块化呢

将一个项目按照功能划分,理论上一个功能一个模块,互不影响,在需要的时候载入,尽量遵循高内聚低耦合。

了解

CommonJS 是一种思想,本质上是可复用的JavaScript,它导出特定的对象,提供其它程序使用。

使用和来导出对象,并在需要它的程序中使用加载。

模块化的核心就是:导入和导出

导出:

module.exports = {
    flag: true,
    test(a,b) {
        return a+b
    },
    demo(a,b) {
        return a*b
    }
}

导入:

// CommonJS模块
let {test, demo, flag} = require('moduleA');

// =>
let ma = require('moduleA');
let test = ma.test;
let demo = ma.demo;
let flag = ma.flag;

因为网站开发越来越复杂,js文件又很多,就会出现一些问题:

,定义模块,一个单独的文件就是一个模块,每个模块都有自己单独的作用域,在该模块内部定义的变量,无法被其他模块读取,除了定义为对象的属性。

模块的导出:和

模块的导入:

es模块的导入和导出

export function add(num1, num2) {
    return num1 + num2
}

export function accString(param) {
	if (param == 0) {
		return '关'
	}else if(param == 1) {
		return '开'
	}
}

import {
		accString
	} from '../../utils'

const name = 'web'

export default name

一个模块中包含某个功能,如果不希望给功能命名,可以让导入者自己来定:

export default function(){
    console.log('web')
}

使用:

import myFunc from '../web.js'

myFunc()

在同一个模块中,不允许同时存在多个

使用

指令导出了模块对外提供的接口

指令用于导入模块中的内容

import {name, age} from './web.js'

通过可以导入模块中所有所有的变量

import * as web from './web.js'

console.log(web.name);

生命周期

首先:,一个的实例,数据查看,绑定事件,执行方法,判断是否有属性,如果没有,表示处于未挂载状态,可以手动调用这个方法来挂载。判断是否有属性。

如果有属性,判断是否有属性。

实例化期和加载期

创建期间的生命周期函数: 和 , 和 。

在实例初始化后,数据观测和事件配置之前被调用。

更新期

运行期间的生命周期函数: 和

实例已经创建完成后被调用。

实例已完成以下的配置:数据观测,属性和方法的运算,事件回调。

挂载阶段还没开始,属性目前不可见。

在挂载开始之前被调用,相关的函数首次被调用。,已经挂载在文档内,对已有节点的操作可以在期间进行。数据更新时调用,发生在虚拟重新渲染和打补丁之前。当这个钩子被调用时,组件已经更新,所以你现在可以执行依赖于的操作。,,,。实例销毁之前调用,实例销毁后调用。

卸载期

销毁期间的生命周期函数: 和

实例生命周期钩子

每个vue实例在被创建时都要经过一系列的初始化过程,需要设置数据监听,编译模板,将实例挂载到并在数据变化时更新等,同时在这个过程中也会运行一些叫做生命周期钩子的函数。

用于给用户在不同阶段添加自己代码的机会。

,此时的是不可见的

data() {
    return {
        a: 1
    }
},
beforeCreate() {
    // red
    console.log(this.a); // 看不见
}

实例已经创建完成后被调用,这个时候你看不见你页面的内容,实例已完成表示:数据观测,属性和方法的运算,事件回调。

这个时候挂载阶段还没开始,属性目前不可见。

export default {
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a);
    },
    created() {
        // red
        console.log(this.a);
        console.log(this.$el);
        // 此时data数据里面的a可见,this.$el不可见
    }
}

在挂载开始之前被调用,相关的函数首次被调用。

export default{
    data() {
        return {
            a: 1
        }
    },
    beforeCreate() {
        console.log(this.a); // 不可见
    },
    created() {
        console.log(this.a);
        console.log(this.$el); // 不可见
    },
    beforeMount() {
        console.log(this.$el); // 不可见
    }
}

export default {
    data() {
        return {
            a: 1
        }
    },
    mounted() {
        console.log(this.$el); // 此时$el 可见
    }
}

钩子,更新之前调用:

beforeUpdate() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML

钩子,更新之后调用:

updated() {
    console.log(this.a);
}

// document.getElementById("web").innerHTML

和(组件)

activated() {
    console.log("组件使用了");
},

deactivated() {
    console.log("组件停用了");
Data to Drag},

是的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染。

包裹动态组件时,会缓存不活动的组件实例,而不会销毁它们。和相似,是一个抽象组件:它自身不会渲染一个元素,也不会出现在父组件链中。

当组件在内被切换,它的和这两个生命周期钩子函数将会被对应指定。

它的使用是因为我们不希望组件被重新渲染而影响使用体验,或者是性能,避免多次渲染降低性能。缓存下来,维持当前得状态。

场景:

生命周期:

初次进入时:;再次进入:会触发;事件挂载的方法等,只执行一次的放在中;组件每次进去执行的方法放在 中。

父组件:



类型为,详细:实例销毁之前调用,在这一步,实例仍然完全可用。

该钩子在服务器端渲染期间不被调用。

类型为,详细:实例销毁后调用,调用后,实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

该钩子在服务器端渲染期间不被调用。

beforeRouteEnter() {
    console.log('beforeRouteEnter')
},

beforeRouteLeave() {
    console.log('beforeRouteLeave')
}

vue路由使用的,路由进去和路由离开的时候添加的。

created() {
    console.log('开始执行created钩子函数')
    // 获取data数据
    console.log('获取created属性'+this.value)
    // 获取页面元素
    console.log(this.$refs['example'])
    this.$nextTick(()=>{
        console.log('执行created创建的this.$nextTick()函数')
    })
},

mounted() {
    console.log('开始执行mounted钩子函数')
    // 获取挂载数据
    console.log('获取挂载数据--'+this.$refs['example'].innerText)
    this.$nextTick(()=>{
        console.log('执行mounted创建的this.$nextTick()函数')
    })
},

methods: {
    // 更新数据
    updateDate(){
        
    },
    get(){
        this.value='更新data内的value属性值'
        // 获取页面元素数据
        console.log(this.$refs['example').innerText)
        this.$nextTick(()=>{
          console.log(this.$refs['example'].innerText)  
        })
    }
}

表示开始创建一个的实例对象,表示刚初始化了一个空的实例对象,这个时候,对象身上,只有默认的一些生命周期函数和默认事件,其他东西都没有创建,生命周期函数执行的时候,和中的数据都没有初始化。在中,和都已经被初始化好了,如果要调用中的方法,或者操作中的数据,只能在中操作。然后开始编辑模板,把代码中的那些指令进行执行,最终在内存中生成一个编译好的最终模板字符串,渲染为内存中的,此时只是在内存中,渲染好了模板,并没有把模板挂载到真正的页面中去。函数执行的时候,模板已经在内存中编译好了,但是尚未挂载到页面中去。这一步是将内存中编译好的模板,真实的替换到浏览器的页面中去。,只要执行完了,就表示整个实例已经初始化完了。此时,组件从创建阶段进入到了运行阶段。

执行的时候,页面中显示的数据还旧的,而数据是最新的,页面尚未和最新的数据保持同步。事件执行的时候,页面和数据已经保持同步了,都是新的。执行,先根据中最新的数据,在内存中,重新渲染出一份最新的内存树,当最新的内存树被更新之后,会把最新的内存树,重新渲染到真实的页面中,完成数据从到的跟新。

钩子函数执行时,实例就从运行阶段,进入到了销毁阶段。此时的实例还是可用的阶段,没有真正执行销毁过程。函数执行时,组件已经被完全销毁了,都不可用了。

vue面试题

谈一谈你mvvm的理解

双向绑定的过程

视图,路由-控制器,数据

->,,数据

传统的指用户操作会请求服务器端路由,路由会调用对应的控制器来处理,控制器会获取数据,将结果返回给前端,让页面重新渲染。

,对于传统的前端会将数据手动渲染到页面上,模式不需要用户收到操作元素,将数据绑定到层上,会自动将数据渲染到页面中,视图变化会通知层更新数据。

Vue响应式原理

核心:

  • ,监听对象属性的改变

  • 发布订阅者模式

代码:

Object.keys(obj).forEach(key => {
 let value = obj[key]
 
 Object.defineProperty(obj, key, {
    set(newValue) {
        // 监听改变
        value = newValue
    },
    get() {
        return value
    }
 })
})

obj.name = 'web'

发布者订阅者

class Dep {
    constructor() {
        this.subs = []
    }
}

class Watcher {
    constructor(name) {
        this.name = name;
    }
}

对象的中的访问器属性中的和方法

  • 把数据转化为和,建立并收集依赖。

说明:

通过回调函数更新;观测数据,通过通知收集,通过通知数据更新,通过收集依赖。

:用于监听劫持所有属性,,解析模板中的指令。

依照下图(参考《深入浅出》)

首先从初始化数据开始,使用监听数据,个体每个数据属性添加,并且在,有两个,。在它的过程添加收集依赖操作,在过程添加通知依赖的操作。

在解析指令或者给实例设置watch选项或者调用时,生成对应的并收集依赖。

通过转换成了的形式,来对数据追踪变化。

修改对象的值的时候,会触发对应的,通知之前依赖收集得到的 中的每一个,告诉它们值改变了,需要重新渲染视图。

数据双向绑定原理

什么是响应式的原理

初始化用户传入的数据,将数据进行观测,进行对象的处理,循环对象属性定义响应式变化,,使用重新定义数据。

使用使用重新定义数据的每一项。

Object.defineProperty(obj,key,{
 enumerable: true,
 configurable: true,
 get: function reactiveGetter(){
     const value=getter?getter.call(obj):val
     if(Dep.target){
         dep.depend()
         if(childOb){
             childOb.dep.depend()
             if(Array.isArray(value)){
                 dependArray(value)
             }
         }
     }
     return value
 },
 set: function reactiveSetter(newVal) {
     const value=getter?getter.call(obj).val
     if(newVal === value || (newVal !== newVal && value !==value)){
         return
     }
     if(process.env.NODE_ENV !== 'production' && customSetter){
         customSetter()
     }
     val = newVal
     childOb = !shallow && observe(newVal)
     dep.notify()
 }
})

vue中式如何检测数组变化

使用函数劫持的方式,重写了数组的方法,将中的数组进行了原型链的重写,指向了自己定义的数组原型方法,这样当调用数组时,可以通知依赖跟新,如果数组中包含着引用类型,会对数组中的引用类型再次进行监控

初始化用户传入的数据,将数据进行观测,将数据的原型方法指向重写的原型。

  • 对数组的原型方法进行重写

  • 深度观察数组中的每一项

代码:

if(Array.isArray(value)){
    // 判断数组
    if(hasProto){
        protoAugment(value, arrayMethods)// 改写数组原型方法
    }else{
        copyAugment(value,arrayMethods,arrayKeys)
    }
    this.observeArray(value)
    //深度观察数组中的每一项
}else{
    this.walk(value) 
    // 重新定义对象类型数据
}

function protoAugment(target, src: Object){
    target.__proto__ = src
}

export const arrayMethods = Object.create(arrayProto)
const methodsToPatch=[
 'push',
 'pop',
 'shift',
 'unshift',
 'splice',
 'sort',
 'reverse'
]

methodsToPatch.forEach(function (method){
    const original = arrayProto[method]
    def(arrayMethods, method, function mutator(...args){
        const result = original.apply(this.args)
        const ob = this.__ob__
        let inserted
        switch(method) {
            case 'push':
            case 'unshift':
            inserted = args
            break
            case 'splice':
            inserted = args.slice(2)
            break
        }
        if(inserted) ob.observerArray(inserted)
        // 对插入的数据再次进行观测
        ob.dep.notify()
        // 通知视图更新
        return result
    }
}

observeArray(items: Array) {
    for(let i=0, l = items.length; i<1; i++) {
        observe(item[i])
        // 观测数组中的每一项
    }
}

为什么vue采用异步渲染

如果不采用异步更新,每次更新数据都会对当前组件进行重新渲染,为了性能考虑。

通知进行更新操作,依次调用的,将去重放到队列中,异步清空队列。

nextTick实现原理

微任务高于宏任务先执行

方法主要使用了宏任务和微任务,定义了一个异步方法,多次调用了会将方法存入到队列中,通过这个异步方法清空当前队列。

方法是异步方法。

原理:调用传入,将回调存入数组中,调用,返回支持的写法。

webpack

什么是webpack,webpack是一个现代的JavaScript应用的静态模块打包工具。

webpack是前端模块化打包工具

安装webpack需要安装node.js,node.js自带有软件包管理工具npm

全局安装

npm install webpack@3.6.0 -g

局部安装

npm install webpack@3.6.0 --save-dev

固定名文件:

const path = require("path")
module.exports = {
    entry: './src/main.js',
    output: {
        patch: './dist',
        filename: ''
    },
}

{
    "name": 'meetwebpack',
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo ..."
    },
    "author": "",
    "license": "ISC"
}

什么是

是中一个非常核心的概念

使用过程:

中定义启动

{
    "name": "meetwebpack",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "build": "webpack"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "webpack": "^3.6.0"
    }
}

webpack的介绍

可以看做是模块打包机,它可以分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言,将其打包为合适的格式以供浏览器使用。

可以实现代码的转换,文件优化,代码分割,模块合并,自动刷新,代码校验,自动发布。

安装本地的webpack

webpack webpack-cli -D

初始化:

yarn init -y

yarn add webpack webpack-cli -D

webpack可以进行0配置,它是一个打包工具,可以输出后的结果(Js模块),打包(支持js的模块化)

运行webpack命令打包

npx webpack

,是写出来的的写法:

let path = require('path')
console.log(path.resolve('dist');

module.exports = {
    mode: 'development',
    // 模式,默认两种,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包后的文件名
        path: path.resolve(__dirname, 'build'),
        // 把相对路径改写为绝对路径
    }
}

自定义,

使用命令:

npx webpack --config webpack.config.my.js

:

{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js"  
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}

使用命令:

npm run build

// npm run build -- --config webpack.config.my.js

开发服务器的配置

代码:

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
console.log(path.resolve('dist');

module.exports = {
    devServer: {
      // 开发服务器的配置  
      port: 3000,
      // 看到进度条
      progress: true,
      contentBase: "./build",
      compress: true
    },
    mode: 'development',
    // 模式,默认两种,production,development
    entry: '' // 入口
    output: {
        filename: 'bundle.js',
        // 打包后的文件名
        path: path.resolve(__dirname, 'build'),
        // 把相对路径改写为绝对路径
    },
    plugins: [
        // 数组,所有的webpack插件
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            minify:{
                removeAttributeQuotes: true,//删除“”
                collapseWhitespace: true, // 变成一行
               
            },
             hash: true
        })
    ],
    module: {
        // 模块
        rules: [
            // 规则
            {test: /\.css$/, use: [{
                loader: 'style-loader',
                options: {
                    insertAt: 'top'
                }
            },'css-loader'] },
        ]
    }
}

output: {
    filename: 'bundle.[hash:8].js',// 打包文件名后只显示8位
}

{
    "name": 'webpack-dev-1',
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
      "build": "webpack --config webpack.config.my.js",
      "dev": "webpack-dev-server"
    },
    "devDependencies": {
        "webpack": "^4.28.3",
        "webpack-cli": "^3.2.0"
    }
}

yarn add css-loader style-loader -D

样式:

安装:

npm install style-loader --save-dev

用法:

建议将与结合使用

import style from './file.css'

代码:

// webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        }
    ]
}

文件处理:

安装

npm install --save-dev style-loader

需要放在的前面,在读取使用的的过程中,是按照从右向左的顺序读取的。

的配置如下:

const path = require('path')

module.exports = {
    // 入口:可以是字符串/数组/对象,这里我们入口只有一个,所以写一个字符串即可。
    entry: './src/main.js',
    // 出口:通常是一个对象,里面至少包含两个重要属性,path和filename
    output:{
        path: path.resolve(__dirname, 'dist'), // 注意:path通常是一个绝对路径
        filename: 'bundle.js'
    },
    module: {
        rules: {
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            }
        }
    }
}

webpack less文件处理

安装:

npm install --save-dev less-loader less

示例:

将,,链式调用,可以把所有样式立即应用于。

// webpack.config.js
module.exports = {
    ...
    rules: [{
        test: /\.less$/,
        use: [{
            loader: 'style-loader'
        },{
            loader: 'css-loader'
        },{
            loader: 'less-loader'
        }]
    }]
}

图片文件处理

代码:

body {
    background: url("../img/test.jpg")
}

npm install --save-dev url-loader

用法

功能类似于,但是在文件大小低于指定的限制时,可以返回一个

import img from './image.png'

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }
                ]
            }
        ]
    }
}

,文件要打包到的文件夹

,获取图片原来的名字,放在该位置

,为了防止图片名称冲突,依然使用,但是我们只保留8位

,使用图片原来的扩展名

es6转es5的babel

如果希望es6转成es5,那么就需要使用

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

配置文件:

{
    test: /\.m?js$/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['es2015']
        }
    }
}

使用vue

如何在我们的环境中集成

代码:

npm install vue --save

()->(前端路由)

文件封装处理

安装和

npm install vue-loader vue-template-compiler --save-dev

认识webpack的plugin

  • 是插件的意思,通常用于对某个现有的架构进行扩展。

  • 中的插件,是对现有功能的各种扩展。

  • 主要用于转换某些类型的模块,它是一个转换器。

  • 是插件,它是对本身的扩展,是一个扩展器。

  • 通过安装需要使用的

  • 在中的中配置插件

的文件:

查看文件的头部:

Vue Cli详解

什么是,,命令行界面,俗称脚手架,是一个官方发布的项目脚手架。使用可以快速搭建开发环境以及对应的配置。

的使用

安装脚手架

npm install -g @vue/cli

vuecli2初始化过程

代码:

vue init webpack vuecli2test

目录结构详解

是 相关配置, 是依赖的相关的模块,是写代码地方。 是es代码相关转换配置,项目文本相关配置,仓库忽略的文件夹配置,为相关转化的配置。

前端模块化:

为什么使用模块化,简单写js代码带来的问题,闭包引起代码不可复用,自己实现了简单的模块化,中模块化的使用:和。

npm install @vue/cli -g

npm clean cache -force

初始化:

vue init webpack my-project

初始化项目:

vue create my-project

箭头函数的使用和this

箭头函数,是一种定义函数的方式

const a = function(){
    
}

const obj = {
    b: function() {
        
    },
    b() {
        
    }
}

const c = (参数列表) => {
    
}
const c = () => {
    
}

箭头函数参数和返回值

代码:

const sum = (num1, num2) => {
    return num1 + num2
}

const power = (num) => {
    return num * num
}

const num = (num1,num2) => num1 + num2

const obj = {
    a() {
        setTimeout(function() {
            console.log(this); // window
        })
        setTimeout(()=>{
          console.log(this); // obj对象 
        })
    }
}

路由,,基本使用,嵌套路由,参数传递,导航守卫。

路由是一个网络工程里面的术语,路由就是通过互联的网络把信息从源地址传输到目的地址的活动。

路由器提供了两种机制:路由和转送。路由是决定数据包从来源到目的地的路径,转送将输入端的数据转移到合适的输出端。路由中有一个非常重要的概念叫路由表。路由表本质上就是一个映射表,决定了数据包的指向。

后端路由:后端处理url和页面之间的映射关系。

前端路由和后端路由,前端渲染和后端渲染

和的区别:

是前端路由,是后端路由。

前端路由原理:

前端路由主要模式:模式和模式。

路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。

前后端渲染之争

url中的hash和html5的history

前端路由的核心是改变,但是页面不进行整体的刷新。单页面,其实最重要的特点就是在前后端分离的基础上加了一层前端路由。就是前端来维护一套路由规则。

的是锚点,本质上是改变的属性。直接赋值来改变,但是页面不发生刷新。

的模式:

的模式:

的模式:

等价于

等价于

安装

npm install vue-router --save

代码:

// 配置路由相关的信息
import VueRouter from 'vue-router'
import vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'

// 通过Vue.use(插件),安装插件
Vue.use(VueRouter)

// 配置路由和组件之间的应用关系
const routes = [
 {
     path: '/home',
     component: Home
 },
 {
     path: '/about',
     component: About
 }
]

// 创建VueRouter对象
const router = new VueRouter({
 routes
})

// 将router对象传入到`Vue`实例
export default router

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

new Vue({
 el: '#app',
 router,
 render: h => h(App)
})

使用的步骤

代码:

组件

// home