共计 29272 个字符,预计需要花费 74 分钟才能阅读完成。
前沿
置身世外只为暗中察看!!!Hello 大家好,我是魔王哪吒!重学坚固你的 Vuejs 常识体系,如果有哪些知识点脱漏,还望在评论中阐明,让我能够及时更新本篇内容常识体系。欢送点赞珍藏!
生命周期
首先:new Vue()
,new
一个 Vue
的实例,Observe data
数据查看,init Events
绑定事件,created
执行 created
办法,判断是否有 el
属性,如果没有,vm.$mount(el)
示意处于未挂载状态,能够手动调用这个办法来挂载。判断是否有 template
属性。
如果有 el
属性,判断是否有 template
属性。
实例化期和加载期
创立期间的生命周期函数:beforeCreate
和 created
,beforeMount
和 mounted
。
beforeCreate
在实例初始化后,数据观测 data observer
和event/watcher
事件配置之前被调用。
更新期
运行期间的生命周期函数:beforeUpdate
和 updated
created
实例曾经创立实现后被调用。
实例已实现以下的配置:数据观测 data observer
,属性和办法的运算,watch/event
事件回调。
挂载阶段还没开始,$el
属性目前不可见。
beforeMount
在挂载开始之前被调用,相干的 render
函数首次被调用。mounted
,vm.$el
曾经挂载在文档内,对已有 dom
节点的操作能够在期间进行。beforeUpdate
数据更新时调用,产生在虚构 dmo
从新渲染和打补丁之前。updated
当这个钩子被调用时,组件 dom
曾经更新,所以你当初能够执行依赖于 dom
的操作。activated
,deactivated
,beforeDestroy
,destroyed
。实例销毁之前调用,vue
实例销毁后调用。
卸载期
销毁期间的生命周期函数:beforeDestroy
和 destroyed
实例生命周期钩子
每个 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
。
<keep-alive>
包裹动静组件时,会缓存不流动的组件实例,而不会销毁它们。和 <transition>
类似,<keep-alive>
是一个形象组件:它本身不会渲染一个 DOM
元素,也不会呈现在父组件链中。
当组件在 <keep-alive>
内被切换,它的 activated
和deactivated
这两个生命周期钩子函数将会被对应指定。
它的应用是因为咱们不心愿组件被从新渲染而影响应用体验,或者是性能,防止屡次渲染升高性能。缓存下来,维持以后得状态。
场景:
- 商品列表页点击商品跳转到商品详情,返回后仍显示原有信息
- 订单列表跳转到订单详情,返回,等等场景。
keep-alive
生命周期:
首次进入时:created > mounted > activated;退出后触发 deactivated
;再次进入:会触发 activated
;事件挂载的办法等,只执行一次的放在mounted
中;组件每次进去执行的办法放在 activated
中。
app.vue
父组件:
<template>
<div>
<button @click="myBtn"> myBtn </button>
<keep-alive>
<range v-if="isShow"></range>
</keep-alive>
</div>
</template>
<script>
import range from './components/range.vue'
export default {data() {
return {
a: 1,
isShow: true
}
},
methods: {myBtn() {this.isShow = !this.isShow}
},
components: {range}
}
</script>
beforeDestroy
和destroyed
beeforeDestroy
类型为function
,具体:实例销毁之前调用,在这一步,实例依然齐全可用。
该钩子在服务器端渲染期间不被调用。
destroyed
类型为 function
,具体:vue
实例销毁后调用,调用后,vue
实例批示的所有货色都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
该钩子在服务器端渲染期间不被调用。
beforeRouteEnter
和beforeRouteLeave
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)
})
}
}
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;}
}
对象的 Object.defindeProperty
中的拜访器属性中的 get
和set
办法
- 把数据转化为
getter
和setter
,建设watcher
并收集依赖。
阐明:
watcher
通过回调函数更新 view
;observer
观测 data
数据,通过 get
告诉 dep
收集 watcher
,dep
通过 notify()
告诉 watcher
数据更新,watcher
通过 addDep()
收集依赖。
Observer
: 用于监听劫持所有 data
属性,dep,watcher,view
,Compile
解析 el
模板中的指令。
按照下图(参考《深入浅出vue.js
》)
首先从初始化 data
数据开始,应用 Observer
监听数据,个体每个数据属性增加 Dep
,并且在Data
,有两个getter
,setter
。在它的getter
过程增加收集依赖操作,在 setter
过程增加告诉依赖的操作。
在解析指令或者给 vue
实例设置 watch 选项或者调用 $watch
时,生成对应的 watcher
并收集依赖。
Data
通过 Observer
转换成了 getter/setter
的模式,来对数据追踪变动。
批改对象的值的时候,会触发对应的 setter
,setter
告诉之前依赖收集失去的 Dep
中的每一个Watcher
,通知它们值扭转了,须要从新渲染视图。
数据双向绑定原理
什么是响应式的原理
- 外围:
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<any>) {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 利用的动态 模块打包 工具。
webpack 是前端模块化打包工具
装置 webpack 须要装置 node.js,node.js 自带有软件包管理工具 npm
全局装置
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 模块以及其它的一些浏览器不能间接运行的拓展语言,将其打包为适合的格局以供浏览器应用。
能够实现代码的转换,文件优化,代码宰割,模块合并,主动刷新,代码校验,主动公布。
装置本地的 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
的写法:
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
spa
(simple age web application
)->vue-router
(前端路由)
.vue
文件封装解决
装置 vue-loader
和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
意识 webpack 的 plugin
plugin
是什么?
plugin
是插件的意思,通常用于对某个现有的架构进行扩大。webpack
中的插件,是对webpack
现有性能的各种扩大。
loader
和plugin
的区别
loader
次要用于转换某些类型的模块,它是一个转换器。plugin
是插件,它是对webpack
自身的扩大,是一个扩展器。
plugin
的应用过程:
- 通过
npm
装置须要应用的plugins
- 在
webpack.config.js
中的plugins
中配置插件
webpack.config.js
的文件:
查看 bundle.js
文件的头部:
Vue Cli 详解
什么是 vue cli
,Command-Line Interface
,命令行界面,俗称脚手架,vue cli
是一个官网公布的我的项目脚手架。应用 vue-cli
能够疾速搭建 vue
开发环境以及对应的 webpack
配置。
vue cli
的应用
装置 vue
脚手架
npm install -g @vue/cli
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
前端模块化:
为什么应用模块化,简略写 js 代码带来的问题,闭包引起代码不可复用,本人实现了简略的模块化,es
中模块化的应用:export
和import
。
npm install @vue/cli -g
npm clean cache -force
vue cli2
初始化:
vue init webpack my-project
vue cli3
初始化我的项目:
vue create my-project
箭头函数的应用和 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
是后端路由。
vue-router
前端路由原理:
前端路由次要模式:hash
模式和 history
模式。
路由的概念来源于服务端,在服务端中路由形容的是 URL 与处理函数之间的映射关系。
前后端渲染之争
url 中的 hash
和html5
的history
前端路由的外围是扭转 url
,然而页面不进行整体的刷新。单页面,其实spa
最重要的特点就是在前后端拆散的根底上加了一层前端路由。就是前端来保护一套路由规定。
url
的hash
url
的 hash
是锚点 #
, 实质上是扭转window.location
的href
属性。间接赋值 location.hash
来扭转href
,然而页面不产生刷新。
html5
的 history
模式:pushState
html5
的 history
模式:replaceState
html5
的 history
模式:go
history.go()
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
的步骤
- 创立路由组件
- 配置路由映射:组件和门路映射关系
- 应用路由:通过
<router-link>
和<router-view>
代码:
组件components
// home
<template>
<div>
<h2> 我是首页 </h2>
</div>
</template>
<script>
export default {name: 'Home'}
</script>
<style scoped>
</style>
<template>
<div>
<h2> 我是对于 </h2>
</div>
</template>
<script>
export default {name: 'Aboout'}
</script>
<style scoped>
</style>
App.vue
<template>
<div id="app">
<router-link to="/home"> 首页 </router-link>
<router-link to="/about"> 对于 </router-link>
<router-view></router-view>
</div>
</div>
<script>
export default {name: 'App'}
</script>
<style>
</style>
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)
})
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
代码
<template>
<div id="app">
<router-link to="/home"> 首页 </router-link>
<router-link to="/about"> 对于 </router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {}}
<router-link>
该标签是一个vue-router
曾经内置的组件,它会被渲染成一个<a>
标签<router-view>
该标签会依据以后的门路,动静渲染出不同的组件。- 网页的其余内容,比方顶部的题目或导航,或者底部的一些版本信息等会和
<router-view>
处于同一个等级。 - 在路由切换时,切换的是
<router-view>
挂载的组件,其余内容不会产生扭转。
路由的默认门路
默认状况下,进入网站的首页,<router-view>
渲染首页的内容,然而默认没有显示首页组件,必须让用户点击才能够。
那么如何让门路默认跳转到首页,并且 <router-view>
渲染首页组件呢,只须要配置一个映射就能够:
const routes = [
{
path: '/',
redirect: '/home'
}
]
配置解析:在 routes
中又配置了一个映射,path
配置的是根门路:/
,redirect
是重定向,就是咱们将根门路重定向到 /home
的门路下。
// main.js
const router = new VueRouter({
// 配置路由和组件之间的利用关系
routes,
mode: 'history'
})
扭转门路的形式:
url
的hash
html5
的history
- 默认状况下,门路的扭转应用的
url
的hash
应用 html5
的history
模式:
// 创立 router 实例
const router = new VueRouter({
routes,
mode: 'history'
})
router-link
,应用了一个属性 :to
,用于指定跳转的门路。tag
能够指定 <router-link>
之后渲染成什么组件。
replace
属性不会留下 history
记录,指定 replace
的状况下,后退键返回不能返回到上一个页面中。
active-class
属性,当 <router-link>
对应的路由匹配胜利时,会主动给以后元素设置一个 router-link-active
的class
,设置 active-class
能够批改默认的名称。
const router = new VueRouter({
routes,
mode: 'history',
linkActiveClass: 'active'
})
路由代码跳转
App.vue
代码:
// app.vue
<template>
<div id="app">
<button @click="linkToHome"> 首页 </button>
<button @click="linkToAbout"> 对于 </button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods: {linkToHome() {this.$router.push('/home')
},
linkToAbout() {this.$router.push('/about')
}
}
}
</script>
<img :src="imgURL" alt="">
<router-link :to="'/uer/' + userId"> 用户 </router-link>
<script>
export default {
name: 'User',
computed: {userId() {return this.$route.params.userId}
}
}
</sript>
const Home = () => import('../components/Home')
const HomeNews = () => import('../components/HomeNews')
const HomeMessage = () => import('../components/HomeMessage')
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: HomeNews
},
{
path: 'news',
component: HomeMessage
}
]
}
<router-link to = "/home/news"> 新闻 </router-link>
<router-link to = "/home/message"> 信息 </router-link>
默认选中:
传递参数的形式
传递参数次要有两种类型,params
和query
params
的类型:
- 配置路由形式:
/router/:id
- 传递的形式:在
path
前面跟着对应的值 - 传递后造成的门路:
/router/123
vue-router
传递参数代码
<router-link :to="{path:'/profile'}"> 用户 </router-link>
对立资源定位符
对立资源定位符,对立资源定位器,对立资源定位地址,Url 地址等,网页地址。如同在网络上的门牌,是因特网上规范的资源的地址。
userClick() {this.$router.push('/user/' + this.userId)
}
btnClick() {
this.$router.push({
path: '/user',
query: {
name: 'web',
age: 12,
height: 1.2
}
})
}
$route
和 $router
是有区别的
获取参数通过 $route
对象获取的,在应用 vue-router
的利用中,路由对象会被注入每个组件中,赋值为this.$route
,并且当路由切换时,路由对象会被更新。
<template>
<div>
<p> {{$route.params}} </p>
</div>
</template>
query
的类型:
- 配置路由格局:
/router
也是一般配置 - 传递形式,对象中应用
query
的key
作为传递形式 - 传递后造成的门路,
router?id=123
,/router?id=abc
$route
和 $router
是有区别的
const router = new VueRouter({
routes,
mode: 'history',
linkActiveClass: 'active'
})
Vue.config.productionTip = false
Vue.prototype.test = function() {console.log('test')
}
Vue.prototype.name = 'web'
$route
和 $router
是有区别的
$router
为VueRouter
实例,想要导航到不同url
,则应用$router.push
办法。$route
为以后router
跳转对象外面能够获取name
,path
,query
,params
等。
vue-router
全局导航
meta: 元数据
router.beforeEach((to,from,next) => {
// from 跳转到 to
document.title = to.matched[0].meta.title
console.log(to);
next()})
// 后置钩子 hook
router.afterEach((to,from) => {console.log();
})
导航守卫:导航示意路由正在产生扭转。
vue-router
提供的导航守卫次要用来通过跳转或勾销的形式守卫导航。有多种机会植入路由导航过程中,全局的,单个路由独享的,或者组件级的。
全局守卫
能够应用router.beforeEach
,注册一个全局前置守卫:
const router = new VueRouter({..})
router.beforeEach((to,from,nex)=>{})
当一个导航触发时,全局前置守卫依照创立顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve
完之前始终处于期待中。
to:Route
,行将要进入的指标路由对象from:Route
,以后导航正要来到的路由next:Function
,肯定要调用该办法来resolve
这个钩子。
vue-router-keep-alive
keep-alive
和vue-router
router-view
是一个组件,如果间接被蕴含在 keep-alive
外面,所有门路匹配到的视图组件都会被缓存。
keep-alive
是 Vue
内置的一个组件,能够使被蕴含的组件保留状态,或防止从新渲染。
属性:
include
字符串或正则表达式,只有匹配的组件会被缓存exclude
字符串或正则表达式,任何匹配的组件都不会被缓存
<keep-alive>
<router-view>
// 所有门路匹配到的视图组件都会被缓存
</router-view>
<keep-alive>
Promise
的应用
es6
的个性Promise
,它是异步编程的一种解决方案。
定时器的异步事件:
setTimeout(function() {
let data = 'web'
console.log(content)
},1000)
new Promise((resolve, reject) => {setTimeout(function(){resolve('web')
reject('error')
},1000)
}).then(data=>{console.log(data)
}).catch(error=> {console.log(error)
})
Promise
三种状态:
pending
期待状态,比方正在进行网络申请,或定时器没有到工夫。fulfill
,满足状态,被动回调resolve
时,并且回调.then()
reject
,回绝状态,回调reject
时,并且回调.catch()
Vuex 详解
vuex
是一个专门为 vue.js
利用程序开发的状态管理模式
它采纳集中式存储管理利用的所有组件的状态,,并以相应的规定保障状态以一种可预测的形式发生变化。
- 状态管理模式
- 集中式存储管理
View components -> actions(dispatch 形式) -> mutations(commit 形式) -> state -> View components
Vuex
外围概念 5 个:
State
,Getters
,Mutation
,Action
,Module
State
繁多状态树,繁多数据源。
Mutation
状态更新
Vuex
的 store
的更新惟一形式,提交Mutation
Mutation
的次要包含两局部:
- 字符串的事件类型
- 一个回调函数,该回调函数的第一个参数就是
state
mutation
的定义:
mutations: {increment(state) {state.count++}
}
通过 mutation
更新
increment: function() {this.$store.commit('increment')
}
参数被称为是 mutation
的载荷payload
Vuex
的 store
中的 state
是响应式的,当 state
中的数据产生扭转时,Vue
组件会自动更新。
- 提前在
store
中初始化好所需的属性 - 给
state
中的对象增加新属性时:应用
- 应用
Vue.set(obj,'newObj',123)
- 用新对象给旧对象赋值
Mutation
常量类型
// mutation-types.js
export const UPDATE_INFO = 'UPDATE_INFO'
import Vuex from 'vuex'
import Vue from 'vue'
import * as types from './mutation-types'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
info: {
name: 'web',
age: 12
}
},
mutations: {[types.UPDATE_INFO](state, payload) {state.info = {...state.info, 'height': payload.height}
}
})
<script>
import {UPDATE_INFO} from './store/mutation-types';
export default{
name: 'App',
components: { },
computed: {info(){return this.$store.state.info}
},
methods: {updateInfo(){this.$store.commit(UPDATE_INFO,{height:1.00})
}
}
}
</script>
留神:不要再 mutation
中进行异步操作,mutation
同步函数,在其中的办法必须时同步办法。
action
的根本定义,如果有异步操作,比方网络申请,
// 不能再 mutation 中应用异步操作, 不能再这里进行异步操作
update(state) {setTimeout(()=>{state.info.name = 'web'},1000)
}
mutations: {
// 办法
[INCREMENT](state){state.counter++}
}
actions: {
// context: 上下文,=》store
<!--aUpdateInfo(context) {-->
<!-- setTimeout(()=>{-->
<!-- state.info.name = 'web'-->
<!-- },1000)-->
<!--}-->
}
actions: {aUpdateInfo(context) {setTimeout(()=>{context.commit('updateInfo')
},1000)
}
}
// xx.vue
updateInfo(){this.$store.dispatch('aUpdateInfo')
}
updateInfo(){<!--this.$store.commit('updateInfo')-->
this.$store.dispatch('aUpdateInfo',{
message: 'web',
success: () => {console.log('web')
}
})
}
aUpdateInfo(context, payload) {return new Promise((resolve, reject) => {...})
}
vuex 中的 modules 应用
modules 时模块的意思
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)
actions
接管一个 context
参数对象,部分状态通过 context.state
裸露进去,根节点状态为context.rootState
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
十分好用。
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
拦截器的应用
// 配置申请和响应拦挡
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
// .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')
})
windows
装置 nginx
,linux
部署,centos
上装置nginx
linux ubuntu
Ubuntu
是一个以桌面利用为主的 Linux
操作系统,其名称来自非洲南部祖鲁语或豪萨语的 “ubuntu"
一词。
操作系统:Window10 + Centos6.5(虚拟机)
yum install nginx
systemtl start nginx.service
systemctl enable nginx.service
通过 Xftp 将 vue 我的项目文件上传至云服务器
应用 Xshell 连贯云服务器
主机就是阿里云上创立的实例的公网 ip
输出登录名和明码,登录名就是购买服务器时输出的登录名和明码。
运行 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
为具名插槽和作用域插槽引入了一个新的对立的语法(即<v-slot>
指令)。它取代了slot
和slot-scope
这两个目前已被废除、尚未移除,仍在文档中的个性。 v-slot
用法, 分为三类:默认插槽、具名插槽以及作用域插槽。
作用域插槽,通过 slot-scope
属性来承受子组件传入的属性汇合
- 默认插槽
代码:
// 子组件
<template>
<div>
<header>
<slot> 默认值 </slot>
</header>
</div>
</template>
任何没有被包裹在带有 v-slot
的<template>
中的内容都会被视为默认插槽的内容。当子组件只有默认插槽时,<v-slot>
标签能够间接用在组件上
// 父组件
<template>
<div>
<child>
内容 1
<template> 内容 2 </template>
内容 3
</child>
<child v-slot="web">
插槽 <br>
插槽 <br>
</child>
</div>
</template>
- 具名插槽:
v-slot
反复定义同样的name
后只会加载最初一个定义的插槽内容
// 子组件
<template>
<div>
<main>
<slot name="main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
- 作用域插槽:
// 子组件
<template>
<div>
<footer>
<slot name="footer" :user="user" :testBtn="testBtn">
{{user.name}}
</slot>
</footer>
</div>
</template>
<script>
exportdefault {
name: 'child',
data () {
return {
user: {
title: 'web',
name: 'web'
}
};
},
methods:{testBtn(){alert('web');
}
}
};
</script>
Vue
如何间接调用 Component
里的办法
<template>
<div>
<b-component ref="BComponent"></b-component>
</div>
</template>
<script>
import BComponent from './BComponent'
export default {
name: 'A',
data () {},
components: {BComponent},
methods: {callACompoentFunction () {this.$refs.BComponent.sayHi()
}
}
}
</script>
<style scoped>
</style>
<template>
<div></div>
</template>
<script>
export default {
name: 'B',
data () {},
methods: {sayHi () {console.log('web!')
}
}
}
</script>
<style scoped>
</style>
最初
我是程序员哆啦 A 梦,蓝瘦子,简书万粉优良创作者,掘金优良作者、CSDN 博客专家,云 + 社区社区沉闷作者,致力于打造一系列可能帮忙程序员进步的优质文章。网站 @http://www.dadaqianduan.cn