关于html:图文并茂点赞收藏哦重学巩固你的Vuejs知识体系下

87次阅读

共计 29272 个字符,预计需要花费 74 分钟才能阅读完成。

前沿

置身世外只为暗中察看!!!Hello 大家好,我是魔王哪吒!重学坚固你的 Vuejs 常识体系,如果有哪些知识点脱漏,还望在评论中阐明,让我能够及时更新本篇内容常识体系。欢送点赞珍藏!

生命周期

首先:new Vue(),new一个 Vue 的实例,Observe data数据查看,init Events绑定事件,created执行 created 办法,判断是否有 el 属性,如果没有,vm.$mount(el)示意处于未挂载状态,能够手动调用这个办法来挂载。判断是否有 template 属性。

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

实例化期和加载期
创立期间的生命周期函数:beforeCreatecreatedbeforeMountmounted

beforeCreate在实例初始化后,数据观测 data observerevent/watcher事件配置之前被调用。

更新期

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

created实例曾经创立实现后被调用。

实例已实现以下的配置:数据观测 data observer,属性和办法的运算,watch/event 事件回调。

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

beforeMount在挂载开始之前被调用,相干的 render 函数首次被调用。mountedvm.$el曾经挂载在文档内,对已有 dom 节点的操作能够在期间进行。beforeUpdate数据更新时调用,产生在虚构 dmo 从新渲染和打补丁之前。updated当这个钩子被调用时,组件 dom 曾经更新,所以你当初能够执行依赖于 dom 的操作。activateddeactivatedbeforeDestroydestroyed。实例销毁之前调用,vue实例销毁后调用。

卸载期

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

实例生命周期钩子

每个 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

activateddeactivated(组件)

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

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

keep-alivevue 的内置组件,能在组件切换过程中将状态保留在内存中,避免反复渲染dom

<keep-alive> 包裹动静组件时,会缓存不流动的组件实例,而不会销毁它们。和 <transition> 类似,<keep-alive>是一个形象组件:它本身不会渲染一个 DOM 元素,也不会呈现在父组件链中。

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

它的应用是因为咱们不心愿组件被从新渲染而影响应用体验,或者是性能,防止屡次渲染升高性能。缓存下来,维持以后得状态。

场景:

  1. 商品列表页点击商品跳转到商品详情,返回后仍显示原有信息
  2. 订单列表跳转到订单详情,返回,等等场景。

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>

beforeDestroydestroyed

beeforeDestroy类型为function,具体:实例销毁之前调用,在这一步,实例依然齐全可用。

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

destroyed类型为 function,具体:vue 实例销毁后调用,调用后,vue实例批示的所有货色都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

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

beforeRouteEnterbeforeRouteLeave

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生命周期函数执行的时候,datamethods 中的数据都没有初始化。在 created 中,datamethods 都曾经被初始化好了,如果要调用 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 树,从新渲染到实在的页面中,实现数据从 dataview的跟新。

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

vue 面试题

谈一谈你对 mvvm 的了解

双向绑定的过程

视图view,路由 - 控制器Controller,数据Model

view->domviewModelModel数据

传统的 mvc 指用户操作会申请服务器端路由,路由会调用对应的控制器来解决,控制器会获取数据,将后果返回给前端,让页面从新渲染。

mvvm,对于传统的前端会将数据手动渲染到页面上,mvvm模式不须要用户收到操作 dom 元素,将数据绑定到 viewModel 层上,会主动将数据渲染到页面中,视图变动会告诉 viewModel 层更新数据。

Vue 响应式原理

  1. vue外部是如何监听 message 数据的扭转
  2. 当数据产生扭转,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 中的拜访器属性中的 getset办法

  • 把数据转化为 gettersetter,建设 watcher 并收集依赖。

阐明:

watcher通过回调函数更新 view;observer 观测 data 数据,通过 get 告诉 dep 收集 watcherdep 通过 notify() 告诉 watcher 数据更新,watcher通过 addDep() 收集依赖。

Observer: 用于监听劫持所有 data 属性,dep,watcher,viewCompile解析 el 模板中的指令。

按照下图(参考《深入浅出vue.js》)

首先从初始化 data 数据开始,应用 Observer 监听数据,个体每个数据属性增加 Dep,并且在Data,有两个gettersetter。在它的getter 过程增加收集依赖操作,在 setter 过程增加告诉依赖的操作。

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

Data通过 Observer 转换成了 getter/setter 的模式,来对数据追踪变动。

批改对象的值的时候,会触发对应的 settersetter 告诉之前依赖收集失去的 Dep 中的每一个Watcher,通知它们值扭转了,须要从新渲染视图。

数据双向绑定原理

什么是响应式的原理

  1. 外围:Object.defineProperty
  2. 默认 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 中式如何检测数组变动

应用 函数劫持 的形式,重写了数组的办法,vuedata 中的数组进行了 原型链的重写 ,指向了本人定义的数组原型办法,这样当调用数组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()顺次调用 watcherupdatequeueWatcherwatcher 去重放到队列中,nextTick(flushSchedulerQueue)异步清空 watcher 队列。

nextTick 实现原理

微工作高于宏工作先执行

nextTick办法次要应用了宏工作和微工作,定义了一个异步办法,屡次调用了 nextTick 会将办法存入到队列中,通过这个异步办法清空以后队列。

nextTick办法是异步办法。

原理:nextTick(cb)调用 nextTick 传入 cbcallbacks.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

loaderwebpack 中一个十分外围的概念

loader应用过程:

  1. 通过 npm 装置须要应用的loader
  2. 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.jswebpacknode 写进去的 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

款式:

  1. style-loader将模块的导出作为款式增加到 dom
  2. css-loader解析 css 文件后,应用 import 加载,并且返回 css 代码
  3. less-loader加载和转译 less 文件
  4. sass-loader加载和转译 sass/scss 文件
  5. postcss-loader应用 PostCSS 加载和转译 css/sss 文件
  6. stylus-loader加载和转译 Stylus 文件

style-loader装置:

npm install style-loader --save-dev

用法:

倡议将 style-loadercss-loader联合应用

component.js

import style from './file.css'
  1. css-loader只负责将 css 文件进行加载
  2. style-loader负责将款式增加到 dom
  3. 应用多个 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
  1. runtime-only代码中,不能够有任何的template
  2. runtime-compiler代码中,能够有 template 因为有 compiler 能够用于编译template

spa(simple age web application)->vue-router(前端路由)

.vue文件封装解决

装置 vue-loadervue-template-compiler

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

意识 webpack 的 plugin

  1. plugin是什么?
  • plugin是插件的意思,通常用于对某个现有的架构进行扩大。
  • webpack中的插件,是对 webpack 现有性能的各种扩大。
  1. loaderplugin 的区别
  • loader次要用于转换某些类型的模块,它是一个转换器。
  • plugin是插件,它是对 webpack 自身的扩大,是一个扩展器。
  1. plugin的应用过程:
  • 通过 npm 装置须要应用的plugins
  • webpack.config.js 中的 plugins 中配置插件

webpack.config.js的文件:

查看 bundle.js 文件的头部:

Vue Cli 详解

什么是 vue cliCommand-Line Interface,命令行界面,俗称脚手架,vue cli 是一个官网公布的我的项目脚手架。应用 vue-cli 能够疾速搭建 vue 开发环境以及对应的 webpack 配置。

vue cli的应用

装置 vue 脚手架

npm install -g @vue/cli

vuecli2 初始化过程

代码:

vue init webpack vuecli2test
  1. 依据名称创立一个文件夹,寄存之后我的项目的内容,该名称会作为默认的项目名称,然而不能蕴含大写字母等
  2. Project name 项目名称,不能蕴含大写
  3. Project description我的项目形容
  4. Author作者信息
  5. Vue build`runtime`
  6. Install vue-router`no` 是否装置等

目录构造详解

build`configwebpack相干配置,node_modules 是依赖的 node 相干的模块,src是写代码中央。.babelrc是 es 代码相干转换配置,.editorconfig我的项目文本相干配置,.gitignore`git仓库疏忽的文件夹配置,.postcssrc.jscss 相干转化的配置。

.editorconfig

前端模块化:

为什么应用模块化,简略写 js 代码带来的问题,闭包引起代码不可复用,本人实现了简略的模块化,es中模块化的应用:exportimport

npm install @vue/cli -g
npm clean cache -force

vue cli2初始化:

vue init webpack my-project

vue cli3初始化我的项目:

vue create my-project

箭头函数的应用和 this

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

  1. 定义函数的形式:function
const a = function(){}
  1. 对象字面量中定义函数
const obj = {b: function() { },
    b() {}
}
  1. 箭头函数
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-routerkoa-router 的区别:

vue-router是前端路由,koa-router是后端路由。

vue-router前端路由原理:

前端路由次要模式:hash模式和 history 模式。

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

前后端渲染之争

url 中的 hashhtml5history

前端路由的外围是扭转 url,然而页面不进行整体的刷新。单页面,其实spa 最重要的特点就是在前后端拆散的根底上加了一层前端路由。就是前端来保护一套路由规定。

urlhash

urlhash 是锚点 #, 实质上是扭转window.locationhref属性。间接赋值 location.hash 来扭转href,然而页面不产生刷新。

html5history 模式:pushState

html5history 模式:replaceState

html5history 模式:go

history.go()

history.back()等价于history.go(-1)

history.forward()等价于history.go(1)

装置vue-router

npm install vue-router --save
  1. 导入路由对象,并且调用Vue.use(VueRouter)
  2. 创立路由实例,并且传入路由映射配置
  3. 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 的步骤

  1. 创立路由组件
  2. 配置路由映射:组件和门路映射关系
  3. 应用路由:通过 <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: {}}
  1. <router-link>该标签是一个 vue-router 曾经内置的组件,它会被渲染成一个 <a> 标签
  2. <router-view>该标签会依据以后的门路,动静渲染出不同的组件。
  3. 网页的其余内容,比方顶部的题目或导航,或者底部的一些版本信息等会和 <router-view> 处于同一个等级。
  4. 在路由切换时,切换的是 <router-view> 挂载的组件,其余内容不会产生扭转。

路由的默认门路

默认状况下,进入网站的首页,<router-view>渲染首页的内容,然而默认没有显示首页组件,必须让用户点击才能够。

那么如何让门路默认跳转到首页,并且 <router-view> 渲染首页组件呢,只须要配置一个映射就能够:

const routes = [
 {
     path: '/',
     redirect: '/home'
 }
]

配置解析:在 routes 中又配置了一个映射,path配置的是根门路:/redirect是重定向,就是咱们将根门路重定向到 /home 的门路下。

// main.js
const router = new VueRouter({
 // 配置路由和组件之间的利用关系
 routes,
 mode: 'history'
})

扭转门路的形式:

  1. urlhash
  2. html5history
  3. 默认状况下,门路的扭转应用的 urlhash

应用 html5history模式:

// 创立 router 实例
const router = new VueRouter({
 routes,
 mode: 'history'
})

router-link,应用了一个属性 :to,用于指定跳转的门路。tag 能够指定 <router-link> 之后渲染成什么组件。

replace属性不会留下 history 记录,指定 replace 的状况下,后退键返回不能返回到上一个页面中。

active-class属性,当 <router-link> 对应的路由匹配胜利时,会主动给以后元素设置一个 router-link-activeclass,设置 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>

默认选中:

传递参数的形式

传递参数次要有两种类型,paramsquery

params的类型:

  1. 配置路由形式:/router/:id
  2. 传递的形式:在 path 前面跟着对应的值
  3. 传递后造成的门路:/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的类型:

  1. 配置路由格局:/router也是一般配置
  2. 传递形式,对象中应用 querykey作为传递形式
  3. 传递后造成的门路,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 是有区别的

  1. $routerVueRouter 实例,想要导航到不同 url,则应用$router.push 办法。
  2. $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 完之前始终处于期待中。

  1. to:Route,行将要进入的指标路由对象
  2. from:Route,以后导航正要来到的路由
  3. next:Function,肯定要调用该办法来 resolve 这个钩子。

vue-router-keep-alive

keep-alivevue-router

router-view是一个组件,如果间接被蕴含在 keep-alive 外面,所有门路匹配到的视图组件都会被缓存。

keep-aliveVue 内置的一个组件,能够使被蕴含的组件保留状态,或防止从新渲染。

属性:

  1. include字符串或正则表达式,只有匹配的组件会被缓存
  2. 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三种状态:

  1. pending期待状态,比方正在进行网络申请,或定时器没有到工夫。
  2. fulfill,满足状态,被动回调 resolve 时,并且回调.then()
  3. reject,回绝状态,回调 reject 时,并且回调.catch()

Vuex 详解

vuex是一个专门为 vue.js 利用程序开发的状态管理模式

它采纳集中式存储管理利用的所有组件的状态,,并以相应的规定保障状态以一种可预测的形式发生变化。

  1. 状态管理模式
  2. 集中式存储管理

View components -> actions(dispatch 形式) -> mutations(commit 形式) -> state -> View components

Vuex外围概念 5 个:

StateGettersMutationActionModule

State繁多状态树,繁多数据源。

Mutation状态更新

Vuexstore 的更新惟一形式,提交Mutation

Mutation的次要包含两局部:

  1. 字符串的事件类型
  2. 一个回调函数,该回调函数的第一个参数就是state

mutation的定义:

mutations: {increment(state) {state.count++}
}

通过 mutation 更新

increment: function() {this.$store.commit('increment')
}

参数被称为是 mutation 的载荷payload

Vuexstore 中的 state 是响应式的,当 state 中的数据产生扭转时,Vue组件会自动更新。

  1. 提前在 store 中初始化好所需的属性
  2. 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装置 nginxlinux 部署,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 回车进行解压操作。

小结:

  1. 计算属性在屡次应用时,只会调用一次,因为它是有缓存额
  2. 修饰符:stopprevent.enter.once.native等,lazynumbertrim等。
  3. 模板的分类写法:scripttemplate
  4. 父子组件的通信:父传子,props,子传父,$emit
  5. 我的项目,npm installnpm run serve
  6. webStorm开发 vuePlugins装置插件vue.js
  7. 2.6.0 版本中,Vue为具名插槽和作用域插槽引入了一个新的对立的语法(即 <v-slot> 指令)。它取代了 slotslot-scope 这两个目前已被废除、尚未移除,仍在文档中的个性。
  8. 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

正文完
 0