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

前沿

置身世外只为暗中察看!!!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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理