【图文并茂,点赞收藏哦!】重学巩固你的Vuejs知识体系(下)
前沿
置身世外只为暗中观察!!!Hello大家好,我是魔王哪吒!重学巩固你的Vuejs知识体系,如果有哪些知识点遗漏,还望在评论中说明,让我可以及时更新本篇内容知识体系。欢迎点赞收藏!
生命周期
首先:new Vue()
,new
一个Vue
的实例,Observe data
数据查看,init Events
绑定事件,created
执行created
方法,判断是否有el
属性,如果没有,vm.$mount(el)
表示处于未挂载状态,可以手动调用这个方法来挂载。判断是否有template
属性。
如果有el
属性,判断是否有template
属性。
![](https://filescdn.proginn.com/1fd076f47280b1f255bc230232ce244c/dcdc7a520f857d3984b4837df72c7c4d.webp)
实例化期和加载期
创建期间的生命周期函数:beforeCreate
和 created
,beforeMount
和 mounted
。
![](https://filescdn.proginn.com/f92d485556d4429f3aec592658f1c281/8ae05dd97eadac32d1f6617ad9cfd165.webp)
beforeCreate
在实例初始化后,数据观测data observer
和event/watcher
事件配置之前被调用。
更新期
运行期间的生命周期函数:beforeUpdate
和 updated
![](https://filescdn.proginn.com/59641a70d5a380c6a401a411de71fc64/1683dc3facdda1a3f064599f9728d876.webp)
created
实例已经创建完成后被调用。
实例已完成以下的配置:数据观测data observer
,属性和方法的运算,watch/event
事件回调。
挂载阶段还没开始,$el
属性目前不可见。
beforeMount
在挂载开始之前被调用,相关的render
函数首次被调用。mounted
,vm.$el
已经挂载在文档内,对已有dom
节点的操作可以在期间进行。beforeUpdate
数据更新时调用,发生在虚拟dmo
重新渲染和打补丁之前。updated
当这个钩子被调用时,组件dom
已经更新,所以你现在可以执行依赖于dom
的操作。activated
,deactivated
,beforeDestroy
,destroyed
。实例销毁之前调用,vue
实例销毁后调用。
卸载期
销毁期间的生命周期函数:beforeDestroy
和 destroyed
![](https://filescdn.proginn.com/bc9e58f77b505fe823450e5aa4a10c57/5ebeade50a1abbbfdac17775a7885417.webp)
实例生命周期钩子
每个vue实例在被创建时都要经过一系列的初始化过程,需要设置数据监听,编译模板,将实例挂载到dom
并在数据变化时更新dom
等,同时在这个过程中也会运行一些叫做生命周期钩子的函数。
用于给用户在不同阶段添加自己代码的机会。
beforeCreate
,此时的data
是不可见的
data() {
return {
a: 1
}
},
beforeCreate() {
// red
console.log(this.a); // 看不见
}
created
实例已经创建完成后被调用,这个时候你看不见你页面的内容,实例已完成表示:数据观测data observer
,属性和方法的运算,watch/event
事件回调。
这个时候挂载阶段还没开始,$el
属性目前不可见。
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不可见
}
}
beforeMount
在挂载开始之前被调用,相关的render
函数首次被调用。
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); // 不可见
}
}
mounted
:
export default {
data() {
return {
a: 1
}
},
mounted() {
console.log(this.$el); // 此时$el 可见
}
}
beforeUpdate
钩子,dom
更新之前调用:
beforeUpdate() {
console.log(this.a);
}
// document.getElementById("web").innerHTML
updated
钩子,dom
更新之后调用:
updated() {
console.log(this.a);
}
// document.getElementById("web").innerHTML
activated
和deactivated
(组件)
activated() {
console.log("组件使用了");
},
deactivated() {
console.log("组件停用了");
Data to Drag},
keep-alive
是vue
的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染dom
。
包裹动态组件时,会缓存不活动的组件实例,而不会销毁它们。和
相似,
是一个抽象组件:它自身不会渲染一个DOM
元素,也不会出现在父组件链中。
当组件在
内被切换,它的activated
和deactivated
这两个生命周期钩子函数将会被对应指定。
它的使用是因为我们不希望组件被重新渲染而影响使用体验,或者是性能,避免多次渲染降低性能。缓存下来,维持当前得状态。
场景:
商品列表页点击商品跳转到商品详情,返回后仍显示原有信息 订单列表跳转到订单详情,返回,等等场景。
keep-alive
生命周期:
初次进入时:created > mounted > activated;退出后触发 deactivated
;再次进入:会触发activated
;事件挂载的方法等,只执行一次的放在mounted
中;组件每次进去执行的方法放在 activated
中。
app.vue
父组件:
"isShow">
beforeDestroy
和destroyed
beeforeDestroy
类型为function
,详细:实例销毁之前调用,在这一步,实例仍然完全可用。
该钩子在服务器端渲染期间不被调用。
destroyed
类型为function
,详细:vue
实例销毁后调用,调用后,vue
实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
该钩子在服务器端渲染期间不被调用。
beforeRouteEnter
和beforeRouteLeave
beforeRouteEnter() {
console.log('beforeRouteEnter')
},
beforeRouteLeave() {
console.log('beforeRouteLeave')
}
vue路由使用的,路由进去和路由离开的时候添加的。
![](https://filescdn.proginn.com/1eb119d20698de0c2edff6de4915515e/7333852dec44820315b6ee959a7f30f4.webp)
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)
})
}
}
var vm=new Vue({})
表示开始创建一个Vue
的实例对象,init events&liftcycle
表示刚初始化了一个vue
空的实例对象,这个时候,对象身上,只有默认的一些生命周期函数和默认事件,其他东西都没有创建,beforeCreate
生命周期函数执行的时候,data
和methods
中的数据都没有初始化。在created
中,data
和methods
都已经被初始化好了,如果要调用methods
中的方法,或者操作data
中的数据,只能在created
中操作。然后vue
开始编辑模板,把vue
代码中的那些指令进行执行,最终在内存中生成一个编译好的最终模板字符串,渲染为内存中的dom
,此时只是在内存中,渲染好了模板,并没有把模板挂载到真正的页面中去。beforeMount
函数执行的时候,模板已经在内存中编译好了,但是尚未挂载到页面中去。create vm.$el and replace 'el' with it
这一步是将内存中编译好的模板,真实的替换到浏览器的页面中去。mounted
,只要执行完了mounted
,就表示整个vue
实例已经初始化完了。此时,组件从创建阶段进入到了运行阶段。
beforeUpdate
执行的时候,页面中显示的数据还旧的,而data
数据是最新的,页面尚未和最新的数据保持同步。updated
事件执行的时候,页面和data
数据已经保持同步了,都是新的。virtual dom re-render and patch
执行,先根据data
中最新的数据,在内存中,重新渲染出一份最新的内存dom
树,当最新的内存dom
树被更新之后,会把最新的内存dom
树,重新渲染到真实的页面中,完成数据从data
到view
的跟新。
beforeDestroy
钩子函数执行时,vue
实例就从运行阶段,进入到了销毁阶段。此时的实例还是可用的阶段,没有真正执行销毁过程。destroyed
函数执行时,组件已经被完全销毁了,都不可用了。
vue面试题
谈一谈你对mvvm
的理解
双向绑定的过程
视图view
,路由-控制器Controller
,数据Model
view
->dom
,viewModel
,Model
数据
传统的mvc
指用户操作会请求服务器端路由,路由会调用对应的控制器来处理,控制器会获取数据,将结果返回给前端,让页面重新渲染。
mvvm
,对于传统的前端会将数据手动渲染到页面上,mvvm
模式不需要用户收到操作dom
元素,将数据绑定到viewModel
层上,会自动将数据渲染到页面中,视图变化会通知viewModel
层更新数据。
Vue响应式原理
vue
内部是如何监听message
数据的改变当数据发生改变, vue
是如何知道要通知哪些人,界面发生刷新
核心:
Object.defineProperty
,监听对象属性的改变发布订阅者模式
代码:
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;
}
}
![](https://filescdn.proginn.com/fffc83b23d5e9ba8884756f3ed6a3e24/9b4214c42e8d935df7af2b07ee78d1b2.webp)
![](https://filescdn.proginn.com/88f24297f540d8d35714cada70488562/0adc90af88d97c60e3d74929a4d7ed9e.webp)
对象的Object.defindeProperty
中的访问器属性中的get
和set
方法
![](https://filescdn.proginn.com/e787d59bc8c3aa649ca109468625cd85/312ab8a8f064399dbc19b8a44dc0e89a.webp)
把数据转化为 getter
和setter
,建立watcher
并收集依赖。
说明:
watcher
通过回调函数更新view
;observer
观测data
数据,通过get
通知dep
收集watcher
,dep
通过notify()
通知watcher
数据更新,watcher
通过addDep()
收集依赖。
Observer
:用于监听劫持所有data
属性,dep,watcher,view
,Compile
解析el
模板中的指令。
依照下图(参考《深入浅出vue.js
》)
![](https://filescdn.proginn.com/92a1a5e52b997cb375b5715f1c858bcb/5b2cbec0eeeefc30f200bc3391a4525b.webp)
首先从初始化data
数据开始,使用Observer
监听数据,个体每个数据属性添加Dep
,并且在Data
,有两个getter
,setter
。在它的getter
过程添加收集依赖操作,在setter
过程添加通知依赖的操作。
在解析指令或者给vue
实例设置watch选项或者调用$watch
时,生成对应的watcher
并收集依赖。
Data
通过Observer
转换成了getter/setter
的形式,来对数据追踪变化。
修改对象的值的时候,会触发对应的setter
,setter
通知之前依赖收集得到的 Dep
中的每一个Watcher
,告诉它们值改变了,需要重新渲染视图。
![](https://filescdn.proginn.com/d54ffa4011a80662461c02ed181ab290/9f9da5dc2cba930328fcac9373ae83ae.webp)
数据双向绑定原理
![](https://filescdn.proginn.com/a45b2a9735d77bafb4d155d2b213bbc7/7c8c44b0a9f8132b1ce6aa03564f1932.webp)
什么是响应式的原理
核心: Object.defineProperty
默认 vue
在初始化数据时,会给data
中的属性使用Object.defineProperty
重新定义所有属性,当页面取到对应属性时,会进行依赖收集,如果属性发生变化会通知相关依赖进行更新操作。
initData
初始化用户传入的data
数据,new Observer
将数据进行观测,this.walk(value)
进行对象的处理,defineReactive
循环对象属性定义响应式变化,Object.defineProperty
,使用Object.defineProperty
重新定义数据。
使用使用Object.defineProperty
重新定义数据的每一项。
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中式如何检测数组变化
使用函数劫持的方式,重写了数组的方法,vue
将data
中的数组进行了原型链的重写,指向了自己定义的数组原型方法,这样当调用数组api
时,可以通知依赖跟新,如果数组中包含着引用类型,会对数组中的引用类型再次进行监控。
initData
初始化用户传入的data
数据,new Observer
将数据进行观测,protoAugment(value,arrayMethods)
将数据的原型方法指向重写的原型。
对数组的原型方法进行重写 observerArray
深度观察数组中的每一项
代码:
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采用异步渲染
如果不采用异步更新,每次更新数据都会对当前组件进行重新渲染,为了性能考虑。
dep.notify()
通知watcher
进行更新操作,subs[i].update()
依次调用watcher
的update
,queueWatcher
将watcher
去重放到队列中,nextTick(flushSchedulerQueue)
异步清空watcher
队列。
nextTick实现原理
微任务高于宏任务先执行
nextTick
方法主要使用了宏任务和微任务,定义了一个异步方法,多次调用了nextTick
会将方法存入到队列中,通过这个异步方法清空当前队列。
nextTick
方法是异步方法。
原理:nextTick(cb)
调用nextTick
传入cb
,callbacks.push(cb)
将回调存入数组中,timerFunc()
调用timerFunc
,返回promise
支持promise
的写法。
webpack
什么是webpack,webpack是一个现代的JavaScript应用的静态模块打包工具。
![](https://filescdn.proginn.com/d5a9d7c7e3fba95ad467ba79efd2b57e/85154136e147473fb26d5c18b2b5ffee.webp)
webpack是前端模块化打包工具
安装webpack需要安装node.js,node.js自带有软件包管理工具npm
![](https://filescdn.proginn.com/d3e27e1f3ba9d4148a211dd7382ed152/162ceaff1b38a56e4c2c3bf1d1681659.webp)
全局安装
npm install webpack@3.6.0 -g
局部安装
npm install webpack@3.6.0 --save-dev
webpack.config.js
固定名文件:
const path = require("path")
module.exports = {
entry: './src/main.js',
output: {
patch: './dist',
filename: ''
},
}
package.json
{
"name": 'meetwebpack',
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo ..."
},
"author": "",
"license": "ISC"
}
什么是loader
loader
是webpack
中一个非常核心的概念
loader
使用过程:
通过 npm
安装需要使用的loader
在 webpack.config.js
中的moudules
关键字下进行配置
package.json
中定义启动
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.6.0"
}
}
webpack
的介绍
webpack
可以看做是模块打包机,它可以分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言,将其打包为合适的格式以供浏览器使用。
![](https://filescdn.proginn.com/5527ad2b493d9390658f438afc9332ea/a9f67bd264a2f8d3c4c7c87d2f48d382.webp)
可以实现代码的转换,文件优化,代码分割,模块合并,自动刷新,代码校验,自动发布。
![](https://filescdn.proginn.com/54993ed52bce9c93f169786f20f8c840/84fb14777d95df91e846babe026a644e.webp)
安装本地的webpack
webpack webpack-cli -D
初始化:
yarn init -y
yarn add webpack webpack-cli -D
webpack可以进行0配置,它是一个打包工具,可以输出后的结果(Js模块),打包(支持js的模块化)
运行webpack命令打包
npx webpack
webpack.config.js
,webpack
是node
写出来的node
的写法:
![](https://filescdn.proginn.com/db2e9a732ae0a878f3a7c6e60ed7a005/11c0b94341854430479a7dec54409a1f.webp)
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'),
// 把相对路径改写为绝对路径
}
}
自定义,webpack.config.my.js
使用命令:
npx webpack --config webpack.config.my.js
package.json
:
{
"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
样式:
style-loader
将模块的导出作为样式添加到dom
中css-loader
解析css
文件后,使用import
加载,并且返回css
代码less-loader
加载和转译less
文件sass-loader
加载和转译sass/scss
文件postcss-loader
使用PostCSS
加载和转译css/sss
文件stylus-loader
加载和转译Stylus
文件
style-loader
安装:
npm install style-loader --save-dev
用法:
建议将style-loader
与css-loader
结合使用
component.js
import style from './file.css'
css-loader
只负责将css文件进行加载style-loader
负责将样式添加到dom
中使用多个 loader
时,是从右到左
代码:
// webpack.config.js
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
css
文件处理:style-loader
安装style-loader
npm install --save-dev style-loader
style-loader
需要放在css-loader
的前面,webpack
在读取使用的loader
的过程中,是按照从右向左的顺序读取的。
webpack.config.js
的配置如下:
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
示例:
将css-loader
,style-loader
,less-loader
链式调用,可以把所有样式立即应用于dom
。
// webpack.config.js
module.exports = {
...
rules: [{
test: /\.less$/,
use: [{
loader: 'style-loader'
},{
loader: 'css-loader'
},{
loader: 'less-loader'
}]
}]
}
图片文件处理
css normal
代码:
body {
background: url("../img/test.jpg")
}
url-loader
npm install --save-dev url-loader
用法
url-loader
功能类似于file-loader
,但是在文件大小低于指定的限制时,可以返回一个DataURL
import img from './image.png'
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
}
img
,文件要打包到的文件夹
name
,获取图片原来的名字,放在该位置
hash:8
,为了防止图片名称冲突,依然使用hash
,但是我们只保留8位
ext
,使用图片原来的扩展名
es6转es5的babel
如果希望es6转成es5,那么就需要使用babel
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js
文件:
{
test: /\.m?js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
使用vue
如何在我们的webpack
环境中集成vue.js
代码:
npm install vue --save
runtime-only
代码中,不可以有任何的template
runtime-compiler
代码中,可以有template
因为有compiler
可以用于编译template
![](https://filescdn.proginn.com/3eeddc86087aeb594262387677304f8d/8168d8bdbe8af7e054dd1a49387d951d.webp)
spa
(simple age web application
)->vue-router
(前端路由)
![](https://filescdn.proginn.com/f5d60ead023c72a8da6b9d4a1335c691/0f5c08d27bbae8a07df2f89a7f959c1d.webp)
.vue
文件封装处理
安装vue-loader
和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
![](https://filescdn.proginn.com/d8643cc27dfe16e542ed751f11ce4d6a/435b8a8966b63dda3417ab237dc4065c.webp)
![](https://filescdn.proginn.com/93e5c4cd395d8736b04de6fa715bed1d/6686912e929301634c6b3332b98d12a3.webp)
认识webpack的plugin
plugin
是什么?
plugin
是插件的意思,通常用于对某个现有的架构进行扩展。webpack
中的插件,是对webpack
现有功能的各种扩展。
loader
和plugin
的区别
loader
主要用于转换某些类型的模块,它是一个转换器。plugin
是插件,它是对webpack
本身的扩展,是一个扩展器。
plugin
的使用过程:
通过 npm
安装需要使用的plugins
在 webpack.config.js
中的plugins
中配置插件
webpack.config.js
的文件:
![](https://filescdn.proginn.com/554508f3cfc89e16b5c7ce47ecd68ff9/3d9b3765a491fe82e91407bbb27a3855.webp)
查看bundle.js
文件的头部:
![](https://filescdn.proginn.com/2f74b6162be9754ccd3f4c9152048e4c/2933d9f2128e0826dd1f41426df7176a.webp)
Vue Cli详解
什么是vue cli
,Command-Line Interface
,命令行界面,俗称脚手架,vue cli
是一个官方发布的项目脚手架。使用vue-cli
可以快速搭建vue
开发环境以及对应的webpack
配置。
vue cli
的使用
安装vue
脚手架
npm install -g @vue/cli
![](https://filescdn.proginn.com/f7412086ed5dfcf67e34ad8a2966a57d/59a50b40bb9c6f4082605656b93a1d44.webp)
![](https://filescdn.proginn.com/706b5443bf61002e944fee51196ac3cb/7903e48142823dd77c8ce67ca24c7c31.webp)
![](https://filescdn.proginn.com/d8b66d76f608203712c320782d99e0b0/82e8a1dbd8870c3a6c9ac7c4602c989d.webp)
vuecli2初始化过程
代码:
vue init webpack vuecli2test
根据名称创建一个文件夹,存放之后项目的内容,该名称会作为默认的项目名称,但是不能包含大写字母等 Project name
项目名称,不能包含大写Project description
项目描述Author
作者信息Vue build``runtime
Install vue-router``no
是否安装等
目录结构详解
build``config
是 webpack
相关配置,node_modules
是依赖的node
相关的模块,src
是写代码地方。.babelrc
是es代码相关转换配置,.editorconfig
项目文本相关配置,.gitignore``git
仓库忽略的文件夹配置,.postcssrc.js
为css
相关转化的配置。
.editorconfig
![](https://filescdn.proginn.com/3370d2ad76b29fcf6e64c67168483aaf/b18e4b74db12da6b68d6bd7dfdacac5c.webp)
![](https://filescdn.proginn.com/6212f42c487fc6e3dfb76c5a0ecba89f/a9bab88c05a192c21ba8d01cb458e148.webp)
![](https://filescdn.proginn.com/4e100dec2fa5c0779c288a41df052288/e6ea9a7f47c36040f103f3a55f0055cd.webp)
前端模块化:
为什么使用模块化,简单写js代码带来的问题,闭包引起代码不可复用,自己实现了简单的模块化,es
中模块化的使用:export
和import
。
npm install @vue/cli -g
npm clean cache -force
![](https://filescdn.proginn.com/107127adfe589ed5a2dc7c0ad060ffc9/6b21752499dccf365de72fec56efaf8d.webp)
![](https://filescdn.proginn.com/efd774c4f06eb2020d56ab675d1fcd5c/44742b2d657bf70ad1d232c6663f3731.webp)
vue cli2
初始化:
vue init webpack my-project
vue cli3
初始化项目:
vue create my-project
![](https://filescdn.proginn.com/9f5df40b943054c68cfa0c4707ef414b/b1ad9d5869f54c2e2f4e00459824625c.webp)
箭头函数的使用和this
箭头函数,是一种定义函数的方式
定义函数的方式: function
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对象
})
}
}
路由,,vue-router
基本使用,vue-router
嵌套路由,vue-router
参数传递,vue-router
导航守卫。
路由是一个网络工程里面的术语,路由就是通过互联的网络把信息从源地址传输到目的地址的活动。
路由器提供了两种机制:路由和转送。路由是决定数据包从来源到目的地的路径,转送将输入端的数据转移到合适的输出端。路由中有一个非常重要的概念叫路由表。路由表本质上就是一个映射表,决定了数据包的指向。
后端路由:后端处理url和页面之间的映射关系。
前端路由和后端路由,前端渲染和后端渲染
vue-router
和koa-router
的区别:
vue-router
是前端路由,koa-router
是后端路由。
![](https://filescdn.proginn.com/4d2b594a5eee2de7ecc27688bcdb216f/2d9bc305f35a2aabaa843d0d9090dbbf.webp)
vue-router
前端路由原理:
前端路由主要模式:hash
模式和history
模式。
![](https://filescdn.proginn.com/a492f4767f855cc94b5f0eab68ad7b98/29016f7ea51bc67a9ab4343aa3fbc30a.webp)
路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。
![](https://filescdn.proginn.com/e0c6c0c8678b057d083b4853329af5af/642a11ec5ab5be853bc4080f1dd51ab5.webp)
前后端渲染之争
![](https://filescdn.proginn.com/898022b86f3994704692f1bbc3860610/7732f140abd8ed5605b8921c182b0c3e.webp)
![](https://filescdn.proginn.com/0d7de513fec649cdd1ac8a5601a930d5/9972a8682f1e47717077405362260587.webp)
![](https://filescdn.proginn.com/e1e7b244aa5b9fe5e2c71c819025934d/fc06e7331fbe6409e75873812aeb0a02.webp)
![](https://filescdn.proginn.com/cdb5d28b70ab1b349e38559e78d8a015/e45a265c3f6d9c131cdd480100050039.webp)
![](https://filescdn.proginn.com/ddbac38009febf8aa28ae57fa3b559ee/edac51eddca7f589f79481ca5d7659f7.webp)
url中的hash
和html5
的history
前端路由的核心是改变url
,但是页面不进行整体的刷新。单页面,其实spa
最重要的特点就是在前后端分离的基础上加了一层前端路由。就是前端来维护一套路由规则。
url
的hash
url
的hash
是锚点#
,本质上是改变window.location
的href
属性。直接赋值location.hash
来改变href
,但是页面不发生刷新。
![](https://filescdn.proginn.com/1ef6a2b5261e3a4b097d0c74627dd80d/b3ce84c7b549f98773bf7f63655677e5.webp)
![](https://filescdn.proginn.com/a618e6f2e200be5d3fe145776851c9f9/6d62a4eb511ec039cd19cebb1449b108.webp)
html5
的history
模式:pushState
![](https://filescdn.proginn.com/1760a0a8ef4c22c5b849286cb11c5408/2b55119c366242ed2df8b86ae66f4cf0.webp)
![](https://filescdn.proginn.com/c0bda8e0b11da58b8f07d9a616a6e930/5291aa03c0cf6fed5b53c6454312c2e5.webp)
![](https://filescdn.proginn.com/ba4132fc36f9b84cf23f238a1e63c15c/118999dc47536e1b5410bba04c88530c.webp)
![](https://filescdn.proginn.com/c43ae271428cdc60d136ffda7e2bf619/86713057940f8f84f2fdc32bdcefd68e.webp)
html5
的history
模式:replaceState
![](https://filescdn.proginn.com/c17ca8584d0eb6e955988222693b6f11/a84ea88689a953a4e46fe0311b710e5f.webp)
html5
的history
模式:go
history.go()
![](https://filescdn.proginn.com/2f9db255fd2ebc3b0b9b9fac82327dad/5786ba5151b5a1462cbc6c9dd55b62f3.webp)
history.back()
等价于history.go(-1)
history.forward()
等价于history.go(1)
安装vue-router
npm install vue-router --save
导入路由对象,并且调用 Vue.use(VueRouter)
创建路由实例,并且传入路由映射配置 在 Vue
实例中挂载创建的路由实例
代码:
// 配置路由相关的信息
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
main.js
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)
})
使用vue-router
的步骤
创建路由组件 配置路由映射:组件和路径映射关系 使用路由:通过
和
代码:
组件components
// home
我是首页
我是关于
App.vue
"app">
"/home">首页
"/about">关于
main.js
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)
})
路由的偶然值和修改为
history
模式
创建router
实例
代码:
router->index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
// 注入插件
Vue.use(VueRouter)
// 定义路由
const routes = []
// 创建router实例
const router = new VueRouter({
routes
})
// 导出router实例
export default router
main.js
代码:
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({
el: '#app',
router,
render: h=>h(App)
})
![](https://filescdn.proginn.com/846700b279afebc50d35cbe347db0dc1/3b0178e7f9e231122c33b217fb3a154a.webp)
router->index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../components/home'
import About from '../components/about'
// 注入插件
Vue.use(VueRouter)
// 定义路由
const routes = [
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
使用App.vue
代码
"app">
"/home">首页
"/about">关于
![](https://filescdn.proginn.com/9c88f605a29b0c1cff77c657a92df6dc/fdb0f318d76a3eaf34c52b6ef6cadc7a.webp)
![](https://filescdn.proginn.com/34168643d7c51e9cfcc45e0701160400/f88aacbe9bb445176318a28e55d81488.webp)
![](https://filescdn.proginn.com/c7c5a416946df97b3cf65a2bec5a07bc/24db8fb5d45c1554c3c335212eba17c3.webp)
![](https://filescdn.proginn.com/3544e76c2452e9411e1fb6968277d7dc/f1466749b3e3935abae9abc8203b1f0d.webp)
"imgURL" alt="">
"'/uer/' + userId"> 用户
注意:不要再mutation
中进行异步操作,mutation
同步函数,在其中的方法必须时同步方法。
action
的基本定义,如果有异步操作,比如网络请求,
// 不能再mutation中使用异步操作,不能再这里进行异步操作
update(state) {
setTimeout(()=>{
state.info.name = 'web'
},1000)
}
mutations: {
// 方法
[INCREMENT](state){
state.counter++
}
}
actions: {
// context:上下文,=》store
}
actions: {
aUpdateInfo(context) {
setTimeout(()=>{
context.commit('updateInfo')
},1000)
}
}
// xx.vue
updateInfo(){
this.$store.dispatch('aUpdateInfo')
}
![](https://filescdn.proginn.com/cb3183306c5794720119e22060e9161b/0fe4f71093b57acff6fe4b5cb1286c90.webp)
updateInfo(){
this.$store.dispatch('aUpdateInfo',{
message: 'web',
success: () => {
console.log('web')
}
})
}
aUpdateInfo(context, payload) {
return new Promise((resolve, reject) => {...})
}
vuex中的modules使用
modules时模块的意思
![](https://filescdn.proginn.com/eadc81fa64603542c1abaea0f62554e2/912f86c627b62beb27d36ca9df32d077.webp)
![](https://filescdn.proginn.com/bb96e0f9c24bd6d68bb6181bc024cca1/99b010882f094cc1992c550dc412b577.webp)
getters: {
stu(){
},
stuLength(state, getters) {
return getters.stu.length
}
}
使用根数据:
getters: {
fullName(state) {
return state.name + '1'
},
fullName1(state, getters) {
return getters.fullName + '2'
},
fullName3(state, getters, rootState) {
return getters.fullName2+rootState.counter
}
}
在模块中actions
打印console.log(context)
![](https://filescdn.proginn.com/1a1cb0a8dd8c161528153026b6b5c9dd/54c744ef929bb1089961682fb24f217d.webp)
actions
接收一个context
参数对象,局部状态通过context.state
暴露出来,根节点状态为context.rootState
![](https://filescdn.proginn.com/0b0d6c2cd5ae934ee8aac5288307d067/9c56c8eea4267f0cb06fd1a95f615fb6.webp)
![](https://filescdn.proginn.com/a3e8e74044da9d32d18370fdf9348e61/606931f92c13cdc5df98cdf087cc4f28.webp)
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
const state = {
}
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
a: moduleA
}
})
export default store
网络封装
axios网络模块的封装
ajax
是基于XMLHttpRequest(XHR)
;jQuery-Ajax
相对于传统的ajax
非常好用。
![](https://filescdn.proginn.com/e6ceb2d4f0c4a92d57d24fe50b48b82f/07908ea4920c6f780e16afa1c89040b7.webp)
![](https://filescdn.proginn.com/e723005d53d8ef10694395596c840c6a/41cf7a7b1ccaa7a1555e0d07f120d7e2.webp)
![](https://filescdn.proginn.com/4efd69c70fc9189be1643eb137b2de6c/6d67cf6804aa9d65a6585181d662f7e1.webp)
axios
特点:
在浏览器中发送 XMLHttpRequests
请求在 node.js
中发送http
请求支持 Promise API
拦截请求和响应 转换请求和响应数据
axios
请求方式:
axios(config)
axios.request(config)
axios.get()
axios.delete()
axios.head()
axios.post()
axios.put()
axios.patch()
安装
npm install axios --save
axios({
// 默认get
url: '',
method: 'get'
}).then(res=>{
console.log(res)
})
// import request from "../utils/request.js"
import {request} from './network'
export function getHome() {
return request({
url: '/home/xxx'
})
}
export function getXX(type, page) {
return request({
url: '/home/xx',
params: {
type,
page
}
})
}
并发请求
代码:
axios.all([axios({
url: ''
}), axios({
url: '',
params: {
type: '',
page: 1,
}
})]).then(results => {
})
// then(axios.spread((res1,res2)=>{...}))
全局配置
axios.defaults.baseURL=''
axios.all ..{
url: '/home'
}
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.baseURL = global.HOST;
request.js
import axios from 'axios'
export function request(config,success,failure){
// 创建axios实例
const instance = axios.create({
baseURL: '',
timeout: 5000
})
// 发送网络请求
instance(config)
.then(res=>{
success(res)
})
.catch(err=>{
failure(err)
})
}
main.js
import {request} from './xx/request'
request({
url: ''
},res=>{
),err=>{
}
也可以使用promise
方法,不过本身返回的就是promise
import axios from 'axios'
export function request(config) {
const instance = axios.create({
baseURL: '',
timeout: 2000
})
return instance(config)
}
axios
拦截器的使用
![](https://filescdn.proginn.com/94d31fcfab01d2729192641a6bb6af17/15b776d373f42b6b66894565133aed4b.webp)
![](https://filescdn.proginn.com/96dbbff4c138e8999677fd778d4d3aab/030a2eaf186c48d986f5b366bdb6f06c.webp)
// 配置请求和响应拦截
instance.interceptors.request.use(config => {
console.log('request拦截success中')
return config
},err => {
console.log('request拦截failure中')
return err
})
instance.interceptors.response.use(response => {
console.log('response拦截success中')
return response.data
},err => {
console.log('response拦截failure中')
return err
})
封装axios
// request.js
import axios from 'axios'
cosnt service = axios.create({
baseURL: process.env.BASE_API,
timeout: 2000
})
service.interceptors.request.use(config=>{
//发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等
config.data=JSON.stringify(config.data);
config.headers = {
'Content-Type':'application/x-www-form-urlencoded'
}
return config
},error=>{
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(response => {
return response
}, error => {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '错误请求'
break;
case 401:
error.message = '未授权,请重新登录'
break;
case 403:
error.message = '拒绝访问'
break;
case 404:
error.message = '请求错误,未找到该资源'
window.location.href = "/NotFound"
break;
case 405:
error.message = '请求方法未允许'
break;
case 408:
error.message = '请求超时'
break;
case 500:
error.message = '服务器端出错'
break;
case 501:
error.message = '网络未实现'
break;
case 502:
error.message = '网络错误'
break;
case 503:
error.message = '服务不可用'
break;
case 504:
error.message = '网络超时'
break;
case 505:
error.message = 'http版本不支持该请求'
break;
default:
error.message = `连接错误${error.response.status}`
}
} else {
if (JSON.stringify(error).includes('timeout')) {
Message.error('服务器响应超时,请刷新当前页')
}
error.message('连接服务器失败')
}
Message.error(err.message)
return Promise.resolve(error.response)
})
// 导入文件
export default service
封装请求http.js
import request from './request'
const http ={
/**
* methods: 请求
* @param url 请求地址
* @param params 请求参数
*/
get(url,params){
const config = {
methods: 'get',
url:url
}
if(params){
config.params = params
}
return request(config)
},
post(url,params){
const config = {
methods: 'post',
url:url
}
if(params){
config.data = params
}
return request(config)
},
put(url,params){
const config = {
methods: 'put',
url:url
}
if(params){
config.params = params
}
return request(config)
},
delete(url,params){
const config = {
methods: 'delete',
url:url
}
if(params) {
config.params = params
}
return request(config)
}
}
export default http
// api.js
import http from '../utils/http'
let resquest = "/xx/request/"
// get请求
export function getListAPI(params){
return http.get(`${resquest}/getList.json`,params)
}
// js
//创建新的axios实例,
const service = axios.create({
baseURL: process.env.BASE_API,
timeout: 3 * 1000
})
项目
创建项目:
vue create webMall
npm run serve
![](https://filescdn.proginn.com/502b9c66d0ef73d32ca0d94eaf354314/c052cccdf8662df72a1f122260fa10fb.webp)
// .editorconfig
root = true
[*]
charset = utf-8
indent_style=space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
项目在
window
下部署
main.js
代码:
import store from './store'
import FastClick from 'fastclick'
import VueLazyLoad from 'vue-lazyload'
import toast from 'components/common/toast'
Vue.config.productionTip = false
// 添加事件总线对象
Vue.prototype.$bus = new Vue()
// 安装toast插件
Vue.use(toast)
// 解决移动端300ms延迟
FastClick.attach(document.body)
// 使用懒加载的插件
Vue.use(VueLazyLoad,{
loading: require('./xx.png')
})
![](https://filescdn.proginn.com/f7979e21b4e71540f2e03da02e4da8cb/7f1b38858a6120b83b15d87de68b2d28.webp)
windows
安装nginx
,linux
部署,centos
上安装nginx
![](https://filescdn.proginn.com/cea9f0778f518ff3f03a98c572891db5/ac0c41c72a98a3d81f16fcb5d92e5c6c.webp)
![](https://filescdn.proginn.com/7115fc6aba42928a1a7657ea2c5919da/a4b056b824719f9a3efa309046e38dc9.webp)
linux ubuntu
Ubuntu
是一个以桌面应用为主的Linux
操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu"
一词。
![](https://filescdn.proginn.com/a458048dcef8f38fa0d169c234d0a00e/0bbf8e63f184829d2819a0732e0f755f.webp)
![](https://filescdn.proginn.com/a3b8a912c8a2a7d122a2251c631e77c1/521789afd3d298a1a5f87746cd8d7caf.webp)
操作系统:Window10 + Centos6.5(虚拟机)
yum install nginx
systemtl start nginx.service
systemctl enable nginx.service
通过Xftp将vue项目文件上传至云服务器
使用Xshell连接云服务器
![](https://filescdn.proginn.com/a4400ef8df20db3103b16e82c7abcb0c/d6d5c4204ff765b0ce86cd122055292a.webp)
主机就是阿里云上创建的实例的公网ip
输入登录名和密码,登录名就是购买服务器时输入的登录名和密码。
![](https://filescdn.proginn.com/d931f5e1b2f5583c52bca1e79b0c0768/e4bc4001af129f3e0c23144b315c499f.webp)
运行npm run build
命令,有一个dist文件夹,这就是vue项目打包后的文件。
nginx安装配置
在Xshell
终端输入命令yum install nginx
,当需要确认时输入”y“
回车。
安装完成后,输入service nginx start
启动nginx
服务。
通过命令nginx -t
查看nginx
所在的安装目录。
在命令行输入命令cd/etc/nginx
切换到nginx
目录下,再输入cat nginx.conf
可查看当前nginx
配置文件。
输入命令 wget https://nodejs.org/dist/v10.8.0/node-v10.8.0-linux-x64.tar.xz
回车,等待安装。
输入命令tar xvf node-v10.8.0-linux-x64.tar.xz
回车进行解压操作。
小结:
计算属性在多次使用时,只会调用一次,因为它是有缓存额 修饰符: stop
,prevent
,.enter
,.once
,.native
等,lazy
,number
,trim
等。模板的分类写法: script
,template
父子组件的通信:父传子, props
,子传父,$emit
项目, npm install
,npm run serve
webStorm
开发vue
在Plugins
安装插件vue.js
在 2.6.0
版本中,Vue
为具名插槽和作用域插槽引入了一个新的统一的语法 (即
指令)。它取代了slot
和slot-scope
这两个目前已被废弃、尚未移除,仍在文档中的特性。v-slot
用法,分为三类:默认插槽、具名插槽以及作用域插槽。
作用域插槽,通过 slot-scope
属性来接受子组件传入的属性集合
默认插槽
代码:
// 子组件
默认值
任何没有被包裹在带有v-slot
的中的内容都会被视为默认插槽的内容。当子组件只有默认插槽时,
标签可以直接用在组件上
// 父组件
内容1
内容2
内容3
"web">
插槽
插槽
具名插槽: v-slot
重复定义同样的name
后只会加载最后一个定义的插槽内容
// 子组件
"main">
作用域插槽:
// 子组件
Vue
如何直接调用Component
里的方法
"BComponent">
最后
我是程序员哆啦A梦,蓝胖子,简书万粉优秀创作者,掘金优秀作者、CSDN博客专家,云+社区社区活跃作者,致力于打造一系列能够帮助程序员提高的优质文章。网站@http://www.dadaqianduan.cn
扫码关注公众号,订阅更多精彩内容。
![](https://filescdn.proginn.com/ffbbc50d03a29033e7d1745fc703bd69/5074dea665e8235c6ff57a1993999e29.webp)