title: Vue学习笔记
date: 2020-7-1
tags: [vue2.0]
categories: 前端技术
toc: true
cover: https://gitee.com/hyj12704338...


Vue 2.0前言

Vue的官网文档可能是我见过的最好的开发文档了,所以如果是学习Vue倡议还是浏览官网文档吧。在这里仅仅是基于我本人的了解对于Vue2.0常识的整顿,便于梳理知识结构

1. 网站交互方式

1.1 单页利用SPA

  • 多页面

    • 点击跳转刷新,用户体验不好
    • 有利于SEO搜索引擎搜寻
  • 单页面利用(Single Page Application,简称SPA)

    • 开发方式好,前后端拆散,开发效率高,可维护性好

      • 服务端不关怀页面,只关怀数据处理
      • 客户端不关怀数据库操作,只通过接口和服务器交互数据
    • 用户体验好,就像原生客户端软件一样应用
    • 只须要加载渲染部分视图即可,不须要整页刷新
    • 单页利用开发技术简单,所以诞生了一堆开发框架

      • AngularJS

        • google开发
        • 为前端带来了MVVM开发模式
        • MVVM(Model-View-ViewModel):数据驱动视图

      • ReactJS

        • facebook
        • 提出组件化
      • VueJS

        • Vue借鉴了前两种,舍短取长
    • 单页面技术曾经很成熟,然而大部分不兼容低版本游览器
    • 单页利用因为数据都是异步加载过去的,不利于SEO( 当初有基于Vue的服务端渲染框架nuxt )

1.2 单页利用SPA实现原理

前后端拆散+前端路由

  • 后端Nodejs,应用Express监督对应申请

    app=express()app.get("/",function(request,response){    //解决    //而后把后果增加到response中    response.json()})
  • 前端工作(以下例子应用原生 js 实现,然而在Vue框架中用vue-router插件更加简略)

    • 前台申请数据,并渲染页面

      <!--引入资源--><script  src="模板引擎地位"> </script><script  src="jquer地位"> </script><!--页面--><script is="tp1" type="text/template">      {{each student_front}}      <li> {{value.name}}</li>      {{/each}}</script><!--申请数据,并渲染到页面--><script>      $.get("接口,如http://127.0.0.1:3000/student",function(data){          template("tp1,{                   student_front:data                   }")  })      <!-- $("#id名")能够获取dom元素-->  </script>
    • 前端路由不同url装载不同页面

      find-music,my-music,friend多个页面,在其页面向服务端取数据进行渲染,而后放入index的容器<div id="container">中显示

      留神:下载jquery;sublime装置sublimeServer实现启动本地服务器(不装置就是间接关上本地文件,不反对跨域找下载的jquery.js文件)

      <!--index.html--><!DOCTYPE html><html><head>    <title>音乐</title>    <mata charset="utf-8"></head><body>    <div class="top">头部</div>    <div class="aside">        <ul>            <!--a标签会跳转刷新,用锚点不会刷新,点击敌人,url扭转浏览器显示:"网址#/friend"。用window.onhashchange,同一个a标签点击屡次,只有第一次触发-->            <!--通过 #/friend 变动,渲染-->                        <li><a href="#/">发现音乐</a></li>            <li><a href="#/my-music">我的音乐</a></li>            <li><a href="#/friend">敌人</a></li>        </ul>        <div id="container">            <!--把 其余页面 渲染进来-->        </div>        <script>            window.onhashchange=function(){                //location中的hash字段蕴含 锚点标识#/friend                //substr(1)标识从string的1地位向后截取                 var hash=window.location.hash.substr(1)                                            if(hash==="/"){                    $.get("./find-music.html",function(data){                        $("#container").html(data)                    })                }else if(hash==="/my-music"){                    $.get("./my-music.html",function(data){                        console.log(data)                        $("#container").html(data)                    })                }else if(hash==="/friend"){                    $.get("./friend.html",function(data){                        $("#container").html(data)                    })                }            }        </script>    </div>    <!--装置jquery 命令 npm install jquery-->    <script src="node_modules/jquery/dist/jquery.js"></script></body></html>
      <!--find-music.html--><div>查找音乐</div><!--my-music--><div>我的音乐</div><!--friend--><div>敌人</div>
    • 以上的形式构建单页面利用太简单,所以呈现了Vue等框架

2.初识Vue

官网:https://cn.vuejs.org/

装置:npm install vue

Vue是什么?

  • 优良的前端js开发框架
  • 能够轻松构建SPA单页面利用
  • 通过指令扩大了HTML,通过表达式绑定数据到HTML
  • 极大水平解放DOM操作

2.1 Vue的特点

Vue是为了克服 HTML 在构建利用上的有余而设计的。其外围特点:

  • MVVM
  • 双向数据绑定
  • 组件化
  • 渐进式

2.2 HelloWorld

  • 相似于模板引擎,有{{ 变量名 }}语法
  • 不同于模板引擎的是 能够通过 app1这个变量间接操作DOM元素,不用再$(#id名)来获取DOM元素了

<!DOCTYPE html><html><head>    <title></title></head><body>    <div id="app">        <h1>{{1+1}}</h1>        <h1>{{"hello"+"world"}}</h1>        <h1>{{message}}</h1>    </div>    <script src="node_modules/vue/dist/vue.js"></script>    <script>        const app1=new Vue({            el:"#app",//el通知vue治理模板的入口,div中的{{  }}的模板语法都会被渲染,el不能是body和html            data:{//绑定的成员数据,这种数据被称为响应式数据。                //什么是响应式数据?数据驱动视图,当数据发生变化时,所有绑定该数据的DOM都会跟着扭转                message:"Hello vue.js"            }        })    </script></body></html><!--后果:2helloworldHello vue.js-->

2.3 双向数据绑定

什么是双向数据绑定?

当数据发生变化时,DOM元素会自动更新数据

当表单发生变化时,数据也会自动更新

v-model指令

<!DOCTYPE html><html><head>    <title></title></head><body>    <div id="app">        <h1>{{message}}</h1>        <input type="text" v-model="message">        <!--v-model 是Vue提供的一个非凡属性,在Vue中称为指令            它的作用是:双向绑定表单控件        -->    </div>    <script src="node_modules/vue/dist/vue.js"></script>    <script>        const app1=new Vue({            el:"#app",            data:{                message:"Hello vue.js"            }        })    </script></body></html>

3.Vue的基本知识

  • 在html页面,通过script形式引入的vue.js

    <!DOCTYPE html><html><head>    <title></title></head><body>    <!--Vue管制的div-->     <div id="app"></div>        <!--通过CDN引入vue.js-->    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    <!--通过npm下载vue.js到本地,依据vue.js所在目录引入-->    <script src="node_modules/vue/dist/vue.js"></script>    <script>        new Vue({          el: '#app',          data: {            selected: ''          }        })            </script></body></html>
  • 应用vue-cli工具,构建更加简单的Vue我的项目,能够在我的项目中应用.vue单文件进行vue代码的编写(在大型项目中应用这种形式)

    <template>    <!--留神template标签下,只能有一个根标签-->      <div id="app">        <span>1</span>        <span>2</span>    </div></template><script>    //在以后vue页面,引入其余js包或者其余vue页面自定义的组件    import XX from "XXX.js"    import YY from "YY.vue"            //    export default {        //绑定的数据        data(){            return{                msg1:"xx",                msg2:"yy"            }        },        //在这路引入YYY.vue组件        componemts:{            YY        }        //生命周期函数        created(){                    },        methods:{            fun1(){},            fun2(){}        }        //watch,computed等    }</script><!--lang指定预编译语言,scoped指定style中的款式只能在以后.vue文件中起作用--><style lang="less" scoped></style>

3.1 Vue实例

把Vue实例,看成一个函数Vue(),这个函数的参数是一个对象Vue({}),而el,data,created,methods,computed,watch看成是对象的属性

new Vue({    //el通知vue治理模板的入口,div中的{{  }}的模板语法都会被渲染,el不能是body和html    el: '#app',        //绑定的成员数据,这种数据被称为响应式数据。(什么是响应式数据?数据驱动视图,当数据发生变化时,所有绑定该数据的DOM都会跟着扭转)    data: {        msg: ''    },   //生命周期函数,前面会介绍。本来应该是对象的属性模式created:function(){},然而个别简写成以下模式   created(){        },       //vue实例中的办法全副写在外面,通过v-on将办法绑定在Dom元素上触发   methods:{       fun1(){            //vue中能够通过this.msg获取data中变量的值              //也能够通过this.fun2()拜访到methods中的函数        }    },        //计算属性,与绑定函数不同的是,计算属性优先从缓存加载。a是变量名,且不必再data中申明,间接用于 {{a}} 之中    computed:{       a:function(){           //肯定有return,return的值放到a中,通过{{ a }}应用       }    },    //侦听属性,用来监听data中变量的变动    watch:{        msg:function(newMessage,oldMessage){            //默认参数是:扭转前的值,扭转后的值        }             }})        

属性data

data的值是一个对象,对象中的变量只有发生变化,则视图就会马上相应,视图中的数据就会变成新的值。

留神:

  • 只有data中的变量才是响应式的
  • 应用 Object.freeze(),这会阻止批改data中的对象类型的变量,也意味着响应零碎无奈再追踪变动。

    var obj = {  name:"张三",  age:18}Object.freeze(obj)new Vue({  el: '#app',  data:{      stu:obj  }})

生命周期函数(待深入分析)

<template>  <div>  </div></template><script>import OtherComponent from '@/components/OtherComponent'export default {  name: 'MyName',  components: {    OtherComponent  },  directives: {},  filters: {},  extends: {},  mixins: {},  props: {},  data () {    return {    }  },  computed: {},  watch: {},  beforeCreate () {    // 生命周期钩子:组件实例刚被创立,组件属性计算之前,如 data 属性等  },  created () {    // 生命周期钩子:组件实例创立实现,属性已绑定,但 DOM 还未生成,el 属性还不存在    // 初始化渲染页面  },  beforeMount () {    // 生命周期钩子:模板编译/挂载之前  },  mounted () {    // 生命周期钩子:模板编译、挂载之后(此时不保障已在 document 中)  },  beforeUpdate () {    // 生命周期钩子:组件更新之前  },  updated () {    // 生命周期钩子:组件更新之后  },  activated () {    // 生命周期钩子:keep-alive 组件激活时调用  },  deactivated () {    // 生命周期钩子:keep-alive 组件停用时调用  },  beforeDestroy () {    // 生命周期钩子:实例销毁前调用  },  destroyed () {    // 生命周期钩子:实例销毁后调用  },  errorCaptured (err, vm, info) {    // 生命周期钩子:当捕捉一个来自子孙组件的谬误时被调用。此钩子会收到三个参数:谬误对象、产生谬误的组件实例以及一个蕴含谬误起源信息的字符串。    console.log(err, vm, info)  },  methods: {}}</script><style lang="scss" scoped></style>
var vm=new Vue({  data: {    a: 1  },      ////生命周期函数      //属性写法  created: function () {    // this 指向 vm 实例    console.log('a is: ' + this.a)  },      //简写模式  mounted(){      },})

留神:不要再Vue实例的属性上应用箭头函数,否则会报错。因为箭头函数中this的指向和上下文无关,并不一定会指向Vue的实例化后的对象

//都会报错created: () => console.log(this.a),vm.$watch('a', (oldValue,newValue) =>{ })

Vue生命周期详解

beforeCreate=>创立以后页面vue实例|=>|created=>data,method,watch,computed可用|=>调用render函数,生成虚构Dom|beforeMount=>虚构Dom创立实现|=>调用patch函数,创立实在Dom|mounted =>实在Dom创立实现,并渲染到页面

如果数据变动,不肯定会触发beforeUpdate,updated函数,只有绑定在视图上的数据变动才会触发

=>绑定视图的数据产生变动,依据实在的Dom,生成一个虚构Dom,将虚构Dom上对应节点的数据进行同样变动|beforeUpdate|=>调用patch函数(应用diff算法),将虚构Dom的改变更新到实在Dom上|updated

响应式原理(数据变动如何触发视图更新)

diff算法

计算属性 computed

{{ }}或者是v-bind绑定的数据,中有简单的计算时,能够写在计算属性中。

咱们须要数据B,然而数据B依赖了数据A,一旦数据A发生变化,B也会发生变化----->数据B改成计算属性

计算属性感知的是函数体外部data数据的变动

计算属性,与绑定函数不同的是,计算属性优先从缓存加,当数据A未发生变化时,拜访计算属性B会立刻返回之前的计算结果,而不用再次执行函数。只有依赖的数据A产生扭转时,它才会从新求值。

B是变量名,且不必再data中申明,可间接用于 {{ }} 之中

计算属性B的 getter:

computed: {      B: function () {          //函数体,肯定有return,return的值放到B中,通过{{ B }}应用        return '扭转后'+this.A               //简写      B(){          //函数体肯定有return,return的值放到B中,通过{{ B }}应用         return '扭转后'+this.A      }}

计算属性默认只有 getter,不过在须要时你也能够提供一个 setter:

computed: {  fullName: {    // getter    get: function () {      return this.firstName + ' ' + this.lastName    },    // setter    set: function (newValue) {//newValue是fullName变动后的新值      var names = newValue.split(' ')      this.firstName = names[0]      this.lastName = names[names.length - 1]    }  }}

助记: getter是函数外部变量变动触发,fullName失去return的值.setter是fullName变动触发,外部执行操作

侦听器 watch

当须要在数据变动时执行异步或开销较大的操作时,通常应用watch

监听的数据是data中的值

watch监听变量对应的函数,不能应用箭头函数

<template>  <div>  </div></template><script>export default {  data () {    return {            question:null    }  },  watch: {    question: function (newValue, oldValue) {//不能应用箭头函数      //监测到question变动了,进行的操作      }  }}</script><style lang="scss" scoped></style>

留神:

如果监听的是一个对象

student: {  name: "",  score: {    math: 32,    english: 80,  },  selectedCourse: ["操作系统", "数据结构"],}

须要采纳上面的办法,只有student外面的任何内容变动,就会触发

watch: {     student: {         handler: function() {            //监测到question变动了,进行的操作           },         deep: true     }}

如果只是监听对象的某个键,下面的办法太节约性能了

watch: {  "student.name": {    handler:function () {      console.log("触发执行");    }  }},

或者

watch: {  "student.name":function () {      console.log("触发执行");  }},

计算属性和监听器

留神:

watch是监听data中的数据,数据变动,触发function中

compute是function外部数据变动,返回给里面的值(默认的getter,也能够设置setter)

3.2 Vue指令

1.html中绑定data数据

应用{{ }}

  • 文本

    应用“Mustache”语法 (双大括号) ,会将双大括号中的值当作变量,把在data中的具体数据渲染进去

    <span>{{ msg }}</span>

    双大括号之间还能够做简略的js运算(简单的运算,个别会放到computed中)

    <span>{{ num++ }}</span><span>{{ arr.split('').reverse().join('') }}</span>

    通过应用 v-once 指令,你也能执行一次性地插值,当数据扭转时,插值处的内容不会更新

    <span v-once> {{ msg }}</span>
  • v-text

    <span v-text="msg"></span><!-- 和上面的一样 --><span>{{msg}}</span>
  • v-html 若message是html代码,不必这个属性只会间接把html代码当成字符串显示
  • v-pre 跳过这个元素和它的子元素的编译过程。间接显示{{ message }}

2.标签属性绑定data数据

不应用{{ }},间接写变量名即可

有一些指定绑定时须要参数,放在指令名称之后的冒号前面

url是data中的变量

<a v-bind:href="url">...</a>//简写<a :href="url">...</a>

3.属性绑定v-bind

根本用法

绑定属性

v-bind:管制html标签的属性值,将属性变量绑定。

//绑定属性disabled<button v-bind:disabled="isButtonDisabled">Button</button>//简写 <button :disabled="isButtonDisabled">Button</button>
//绑定属性href<a v-bind:href="url">...</a>//简写<a :href="url">...</a>

动静参数

[ ]中是变量attributeName,能够动静的指定绑定的属性是什么,比方:href

<a :[attributeName]="url"> ... </a>

留神:

  • 当某个属性值是布尔值时,间接disable="true"相当于,把一个字符串赋值给属性。用绑定赋值,会把字符串ture转变为布尔值

    <button :disable="true"></button>//true是不可点击
  • 绑定的属性的值是对象

    对象的属性值是true,则保留该属性;属性值是flase,则去除该属性;

    <div :class="obj"></div>
    data: {    obj:{        active: true,         text-danger: false     }}

    对应的理论的成果是

    <div  class="active"></div>
  • 绑定的属性的值是数组

    <div :class="arr"></div>
    data: {    arr:['active','text-danger']}

    对应的理论的成果是

    <div class="active text-danger"></div>

用于绑定class

对象语法:动静切换class,只能切换该属性是否存在,对象属性值为真,则该属性存在,都则不存在

  • 对象中传入一个字段(定义的class名,要用引号引起来)

    <div v-bind:class="{ "active": isActive }"></div>

    下面的语法示意 active 这个 class 存在与否将取决于数据 property isActive 的 truthiness。

  • 对象中传入更多字段来动静切换多个 class。此外,v-bind:class 指令也能够与一般的 class 属性共存

    <div  class="static"  v-bind:class="{ "active": isActive, "text-danger": hasError }"></div>

    和如下 data:

    data: {  isActive: true,  hasError: false}

    后果渲染为:

    <div class="static active"></div>
  • 绑定的数据对象不用内联定义在模板里:

    <div class="static" v-bind:class="classObject"></div>
    data: {  classObject: {    active: true,    'text-danger': false  }}

    渲染的后果和下面一样。

  • 咱们也能够在这里绑定一个返回对象的计算属性。这是一个罕用且弱小的模式:

    <div v-bind:class="classObject"></div>
    data: {  isActive: true,  error: null},computed: {  classObject() {    return {      active: this.isActive && !this.error,      'text-danger': this.error && this.error.type === 'fatal'    }  }}

数组语法:切换class属性,能够搁置三元表达式,切换两个不同属性,而对象是切换class某个属性是否存在

  • 根底用法

    <div v-bind:class="['active', 'text-danger']"></div>

    渲染为:

    <div class="active text-danger"></div>
  • 咱们能够把一个数组元素替换为变量

    <div v-bind:class="[activeClass, errorClass]"></div>data:{  activeClass: 'active',  errorClass: 'text-danger'}

    渲染为:

    <div class="active text-danger"></div>
  • 如果你也想依据条件切换列表中的 class,能够用三元表达式:

    <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

    这样写将始终增加 errorClass,然而只有在 isActive 是 truthy时才增加 activeClass

  • 三元表达式有些繁琐。所以在数组语法中也能够应用对象语法:

    <div v-bind:class="[{ active: isActive }, errorClass]"></div>

用于绑定style

对象语法

v-bind:style 的对象语法非常直观——看着十分像 CSS,但其实是一个 JavaScript 对象。CSS属性名能够用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>data: {  activeColor: 'red',  fontSize: 30}

间接绑定到一个款式对象通常更好,这会让模板更清晰:

<div v-bind:style="styleObject"></div>data: {  styleObject: {    color: 'red',    fontSize: '13px'  }}

同样的,对象语法经常联合返回对象的计算属性应用。

数组语法

v-bind:style 的数组语法能够将多个款式对象利用到同一个元素上:

<div v-bind:style="[baseStyles, overridingStyles]"></div>

主动增加前缀

v-bind:style 应用须要增加浏览器引擎前缀的 CSS property 时,如 transform,Vue.js 会主动侦测并增加相应的前缀。

4.事件绑定v-on

v-on:绑定处理事件=“处理函数”,v-on:简写@

  • 绑定办法

    v-on:管制html标签的办法,将办法函数绑定。

    <button v-on:click="addNum"></button> //addNum是methods中定义的办法<!--简写--><button @click="addNum"></button>
  • 动静参数

    [ ]中是变量attributeName,能够动静的指定绑定的办法,比方:click

    <button @[attributeName]="url"> ... </buttom>
  • 绑定的办法能够传递参数

    <!--绑定click办法,触发add()函数,add()不须要传入参数时能够省略括号--><div id="example">  <button v-on:click="add">点击了{{count}}次</button></div>
    <script>    var example = new Vue({      el: '#example',      data: {        count: 0      },      methods: {        add: function () {          // `this` 在办法里指向以后 Vue 实例          this.count++;        }      }    })</script>

    也能够用 JavaScript 间接调用办法 example.add()

    有时候绑定的函数须要拜访原始的 DOM 事件,能够用非凡变量 $event 把它作为参数传入办法

    <button v-on:click="warn('正告', $event)">点击</button>
    // ...methods: {  warn: function (message, event) {//第个参数接管到“正告”字符串,第二个参数是$event    // 当初咱们能够拜访原生事件对象    if (event) {      event.preventDefault()    }    alert(message)  }}

    在事件处理程序中调用 event.preventDefault() 【阻止Dom元素默认行为】或 event.stopPropagation() 【阻止冒泡传递】是十分常见的需要。只管咱们能够在办法中轻松实现这点,但更好的形式是:办法只有纯正的数据逻辑,而不是去解决 DOM 事件细节。为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符按键修饰符

    事件修饰符

    • .stop
    • .prevent
    • .capture
    • .self
    • .once
    • .passive
    <!-- 阻止单击事件持续流传 --><a v-on:click.stop="doThis"></a><!-- 提交事件不再重载页面 --><form v-on:submit.prevent="onSubmit"></form><!-- 修饰符能够串联 --><a v-on:click.stop.prevent="doThat"></a><!-- 只有修饰符 --><form v-on:submit.prevent></form><!-- 增加事件监听器时应用事件捕捉模式 --><!-- 即外部元素触发的事件先在此解决,而后才交由外部元素进行解决 --><div v-on:click.capture="doThis">...</div><!-- 只当在 event.target 是以后元素本身时触发处理函数 --><!-- 即事件不是从外部元素触发的 --><div v-on:click.self="doThat">...</div><!-- 点击事件将只会触发一次 --><a v-on:click.once="doThis"></a><!-- 滚动事件的默认行为 (即滚动行为) 将会立刻触发 --><!-- 而不会期待 `onScroll` 实现  --><div v-on:scroll.passive="onScroll">...</div>

    留神:

    • 修饰符能够串联,然而应用修饰符时,程序很重要;相应的代码会以同样的程序产生。因而,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素本身的点击。
    • 不要把 .passive.prevent 一起应用,因为 .prevent 将会被疏忽,同时浏览器可能会向你展现一个正告。请记住,.passive 会通知浏览器你不想阻止事件的默认行为

    按键修饰符

    <!-- 只有按下的键是 `Enter` ,开释按键时,调用 `submit()`函数 --><input v-on:keyup.enter="submit"><!-- 只有按下的键是 `PageDown` ,开释按键时,调用 `onPageDown()`函数 --><input v-on:keyup.page-down="onPageDown">
  • 内联解决

    <div id="example">  <button v-on:click="count++">点击了{{count}}次</button></div>
    <script>    var example= new Vue({      el: '#example',      data: {        count: 0      }    })</script>

5.表单绑定v-model

v-model 指令在表单<input><textarea><select> 元素上创立双向数据绑定。

v-model实质上是v-bind绑定元素属性和v-on绑定元素事件的组合

  • text 和 textarea 元素应用 value 属性 和 input 事件;
  • checkbox 和 radio 应用 checked 属性 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

举例:

  • 文本框

    输入框显示的是message绑定的值

    <input v-model="message" placeholder="edit me">
  • 多行文本

    <textarea v-model="message" placeholder="add multiple lines"></textarea>

    留神:在文本区域插值 (<textarea>{{text}}</textarea>) 并不会失效

  • 复选框

    • 单个复选框。这外面的v-modle是布尔值,复选框选中时checked变量是true,反之是flase

      <input type="checkbox" id="checkbox" v-model="checked">
    • 多个复选框。这外面的v-modle值是空数组,复选框选中时,会把对应的value值按选中的程序push到空数组中;勾销选中,会间接把数组中对应的value值删除

      <div id='example'>      <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">  <label for="jack">Jack</label>      <input type="checkbox" id="john" value="John" v-model="checkedNames">  <label for="john">John</label>    <br>  <span>Checked names: {{ checkedNames }}</span></div>
      new Vue({  el: '#example',  data: {    checkedNames: [] //因为是多选,所以是数组  }})
    • 单选按钮。这外面的v-modle值,选中时是对应的value值

      <div id="example">      <input type="radio" id="one" value="One" v-model="picked">  <label for="one">One</label>  <br>  <input type="radio" id="two" value="Two" v-model="picked">  <label for="two">Two</label>  <br>  <span>Picked: {{ picked }}</span></div>
      new Vue({  el: '#example',  data: {    picked: ''  }})
  • 下拉抉择框。选中时v-model值是对应<option>中的值,增加value属性,则是对用option中value的值

    <div id="example">  <select v-model="selected">      //第一个是默认选项,要设置成disable    <option disabled value="">请抉择</option>    <option>A</option>    <option>B</option>    <option>C</option>  </select>  <span>Selected: {{ selected }}</span></div>
    new Vue({  el: '#example',  data: {    selected: ''  }})

    v-for 渲染 下拉抉择框。v-model的值是选中option的value值

    <select v-model="selected">  <option v-for="option in options" v-bind:value="option.value">    {{ option.text }}  </option></select><span>Selected: {{ selected }}</span>
    new Vue({  el: '...',  data: {    selected: 'A',    options: [      { text: 'One', value: 'A' },      { text: 'Two', value: 'B' },      { text: 'Three', value: 'C' }    ]  }})
  • 修饰符: .lazy .number .trim

    //输出实现后失去焦点后,才渲染数据,不是只有输出变动,就始终从新渲染<input v-model.lazy="msg" >//转成数字<input v-model.number="age" type="number">//去掉空白字符<input v-model.trim="msg">

6.条件渲染v-if

  • v-ifv-else

    //能够管制 html元素和 <template>//变量只能是布尔值,能够管制元素是否可见<h1 v-if="awesome">Vue is awesome!</h1><h1 v-else-if>1</h1><h1 v-else>2</h1>
  • v-showv-if不同的是,html会被保留,只是暗藏了。

    <h1 v-show="ok">Hello!</h1>
  • 用 key治理可复用的元素

    Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染Dom元素。这么做使 Vue 变得十分快

    <template v-if="loginType">  <label>用户名</label>  <input placeholder="请输出用户名"></template><template v-else>  <label>邮箱</label>  <input placeholder="请输出邮箱"></template>

    留神:通过管制loginType的虚实,来管制显示哪局部。Vue只是替换label和input的内容,并不会从新渲染Dom元素,所以一旦在输入框中输出数据,即便切换loginType的值,数据也不会被革除,依然会被显示在输入框. 比方 loginType为真时,输出用户名A,loginType为假时,输出用户名B,相互切换 loginType的值,input输入框会保留对应的数据

    强制更新组件的方法(还能够通过扭转key值,可一让同一个组件每次key变动就会从新渲染Dom元素):通过给元素增加惟一的key,该元素就会被从新渲染。以下代码,label未应用惟一的key,所以依然不会被从新渲染Dom,仅仅是替换内容

    <template v-if="loginType">  <label>用户名</label>  <input placeholder="请输出用户名" key="username"></template><template v-else>  <label>邮箱</label>  <input placeholder="请输出邮箱" key="email"></template>

    新旧 children 中的节点只有程序是不同的时候,最佳的操作应该是通过挪动元素的地位来达到更新的目标。

    须要在新旧 children 的节点中保留映射关系,以便可能在旧 children 的节点中找到可复用的节点。key 也就是 children 中节点的惟一标识。

    留神:key要是字符串或者数值类型

7.列表渲染v-for

  • 遍历数组v-for="item in items"

    <!--还有第二个参数,即索引item,v-for="(item, index) in items"--><ul id="example-1">  <li v-for="item in items">    {{ item.message }}  </li></ul>
    var example1 = new Vue({  el: '#example-1',  data: {    items: [      { message: 'Foo' },      { message: 'Bar' }    ]  }})

    你也能够用 of 代替 in 作为分隔符,因为它更靠近 JavaScript 迭代器的语法:

    <div v-for="item of items"></div>
  • 遍历对象

    <!--还有第二个参数,即对象中的key值,v-for="(value, name) in object--><!--还有第三个参数,即索引index,v-for="(value, name, index) in object"--><ul id="example2" class="demo">  <li v-for="value in object">    {{ value }}<!--是对象的值-->  </li></ul>
    new Vue({  el: '#v-for-object',  data: {    object: {      title: 'How to do lists in Vue',      author: 'Jane Doe',      publishedAt: '2016-04-10'    }  }})
  • 当 Vue 正在更新应用 v-for 渲染的元素列表时,它默认应用“就地更新”的策略,即渲染元素变动 ,对应地位的Dom间接更新。所以,如果数据项的程序被扭转,Vue 不会挪动 DOM 元素的程序来匹配数据项的程序的扭转,而是就地更新每个元素,并且确保它们在每个索引地位正确渲染。

    这个默认的模式是高效的,然而只实用于不依赖子组件状态或长期 DOM 状态 (例如:表单输出值) 的列表渲染输入

    为了给 Vue 一个提醒,以便它能跟踪每个节点的身份,从而复用和从新排序现有元素,你须要为每项提供一个惟一 key

    <div v-for="item in items" v-bind:key="item.id">  <!-- 内容 --></div>

    留神:key要是字符串或者数值类型

6.自定义指令

定义自定义指令

  • 全局

    // 注册一个全局自定义指令 `v-focus`Vue.directive('focus', {//定义的指令名,不要加v-  // 当被绑定的元素插入到 DOM 中时……  inserted: function (el) {//el指的是该自定义指令的调用者,即增加该指令的dom元素(有点像函数中的形参)    //写具体性能: 对聚焦元素    el.focus()  }})new Vue()
  • 部分定义

    成果:页面一载入,input就会主动取得焦点(默认须要本人点击input获取焦点)

    <template>  <div id="app">    <input v-focus>  </div></template><script>export default {  name: 'App',  data() {    return {};  },  directives: {    focus: {      inserted(el) {//el是增加指令的元素         el.focus(); //focus是dom的办法       },    },  },};</script>

应用自定义指令

<input type="text" v-focus>

3.3 过滤器

Vue2.x版本没有内置过滤器

用于对文本格式化解决

过滤器能够用在两个中央:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始反对)。过滤器应该被增加在 JavaScript 表达式的尾部,由“管道”符号“|”批示:

定义过滤器

  • 在Vue选项中定义部分过滤器

    filters: {  capitalize: function (value) {    if (!value) return ''    value = value.toString()    return value.charAt(0).toUpperCase() + value.slice(1)  }}
  • 全局过滤器(在new Vue之前)

    Vue.filter('capitalize', function (value) {  if (!value) return ''  value = value.toString()  return value.charAt(0).toUpperCase() + value.slice(1)})new Vue({  // ...})

过滤器的应用

<!——"|"前是变量名,"|"后是过滤器名。     变量绑定的值作为过滤器的第一个参数     ——><!-- 在双花括号中 -->{{ message | capitalize }}{{ message | filterA | filterB }}<!--filterA的return作为filterB的一个参数-->{{ message | filterA('arg1', arg2) }}<!--filter的参数是message 和本人传的参数arg1 arg2-->           <!-- 在 `v-bind` 中 --><div v-bind:id="rawId | formatId"></div>
  • 后果:把输出值的第一个字符大写

3.4 Vue组件

组件特点

  • 组件是一种封装
  • 是一种非凡的Vue实例
  • 组件能够复用,每用一次组件就会有一个新的实例被创立 ,实例间互不影响
理论开发中,应用第三方组件

定义及应用组件

留神:命名组件名倡议应用' abc-xyz '模式(小写字母用 - 连贯)
  • 注册全局组件( 写在new Vue({ }) 之前 )

    <!DOCTYPE html><html>    <head>        <title></title>        <!--通过CDN引入vue.js-->        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    </head>    <body>        <div id="app">            <!--应用自定义的组件-->            <button-counter></button-counter>        </div>        <script>            // 定义一个名为 button-counter 的新组件            Vue.component('button-counter', {                data() { //data必须是函数                    return {                        count: 0                    }                },                template: '<button v-on:click="changeCount">You clicked me {{ count }} times.</button>',                methods: {                    changeCount() {                        this.count++;                    }                }            })            new Vue({                el: "#app",                data: {                }            })        </script>    </body></html>
  • 注册部分组件(写在Vue选项中)

    <!DOCTYPE html><html>    <head>        <title></title>        <!--通过CDN引入vue.js-->        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    </head>    <body>        <div id="app">            <!--应用自定义的组件-->            <button-counter></button-counter>        </div>        <script>            new Vue({                el: '#app',                data: {                },                //部分组件                components: {                    "button-counter": { //组件名                        data() { //data必须是函数                            return {                                count: 0                            }                        },                        template: '<button v-on:click="changeCount">You clicked me {{ count }} times.</button>',                        methods: {                            changeCount() {                                this.count++;                            }                        }                    }                }            })        </script>    </body></html>
  • 模块化零碎中的部分注册

    有些时候,咱们将封装的一个通用组件放在一个独自的.vue文件中,能够通过以下形式引入到以后.vue文件中,在vue实例的components字段援用

组件模板的定义

好文

即template字段内定义的组件模板

  • html文件里,在组件内抉择 template 字段选项,间接在字段前面写
  • X-Template

    html文件里,这种形式是在一个 <script> 元素中,并为其带上 text/x-template 的类型,而后通过一个 id 将模板援用过来。

      <!DOCTYPE html>  <html>      <head>          <title></title>          <!--通过CDN引入vue.js-->          <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>      </head>          <body>          <div id="app">              <!--应用自定义的组件-->              <button-counter></button-counter>          </div>          <script type="text/x-template" id="hello-world-template">                <p>Hello hello hello</p>          </script>          <script>              new Vue({                  el: '#app',                  data: {                    },                  //部分组件                  components: {                      "button-counter": { //组件名                          data() { //data必须是函数                              return {                                  count: 0                              }                          },                          template: '#hello-world-template',                          methods: {                              changeCount() {                                  this.count++;                              }                            }                      }                  }              })          </script>        </body>  </html>                                  
  • .vue 文件里的一个 <template> 元素来定义模板。

每个组件实例互不影响

组件嵌套

无论是全局还是部分组件,都能够间接嵌套,即在定义时,template字段中能够写别的组件

组件通信

官网文档—拜访元素&组件

组件通信总结+原理剖析

父组件向子组件传递数据

props是自定义组件时的一个字段,参数是一个数组,每个数组元素都是一个组件的属性,通过props你能够在自定义的组件上注册一些自定义属性。应用自定义组件时,能够把值通过自定义的属性,传递给template中的子组件。留神:每个实例化的组件,传递参数互不影响

<!--把参数通过title属性,传递到组件中的template中的{{title}}--><div id="app">    <blog-post title="第一章"></blog-post>    <blog-post title="第二章"></blog-post></div>
<script>        Vue.component('blog-post', {            props: ['title'],            template: '<h3>{{ title }}</h3>'        })        new Vue({              el: '#app',              data: {                message:200              }                 })        </script>    

循环渲染自定义组件,并把值通过自定义属性title,传递到template中

<blog-post  v-for="post in posts"  v-bind:key="post.id"  v-bind:title="post.title"></blog-post>
<script>    Vue.component('blog-post', {                props: ['title'],                template: '<h3>{{ title }}</h3>'    })        new Vue({      el: '#app',      data: {        posts: [          { id: 1, title: '第一章' },          { id: 2, title: '第二章' },          { id: 3, title: '第三章' }        ]      }    })</script>

留神:HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你应用 DOM 中的模板时,应用驼峰命名法的 prop 名,在应用该属性时,须要用等价的 kebab-case (短横线分隔命名)。【如果你应用字符串模板,那么这个限度就不存在了。即单vue页面,html代码写在<template>标签中】

<blog-post post-title="hello!"></blog-post><!--props中的属性如果应用驼峰命名,应用时改成kebab-case模式-->
<script>    Vue.component('blog-post', {      props: ['postTitle'],//这里应用的驼峰命名法      template: '<h3>{{ postTitle }}</h3>'    })</script>

子组件向父组件传递数据<span id="子组件向父组件传递数据"></span>

<div id="app">    <!--两个子组件的count值也是独立的,不会相互影响的-->    <button-counter @clicknow="clicknow"></button-counter>    <button-counter @clicknow="clicknow"></button-counter></div>
<script>     //第一子组件    Vue.component('button-counter', {      data(){        return {          count: 0        }      },      template: '<button v-on:click="add">点击了 {{ count }} 次</button>',      methods:{            add(){               this.count++;                //子组件触发的add办法,通过this.$emit,把count的值放入clicknow函数之中,并在父组件调用,就会把子组件的数据传输到父级组件               this.$emit('clicknow',this.count);            }      }    })        //实例化Vue对象    new Vue({        el:"#app",        data:{},        methods:{            clicknow(e){                //这里的e就是子组件的count                console.log(e);            }        }            })</script>

兄弟组件通信

Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue

Vuex

跨级组件通信

Vuex

$attrs、$listeners

Provide、inject

插槽

在自定义组件的template字段中,增加<slot></slot>,那么应用子组件时就会将子组件开闭标签间的内容填充到template中<slot></slot>所在的地位

<!DOCTYPE html><html>    <head>        <title></title>        <!--通过CDN引入vue.js-->        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>    </head>    <body>        <div id="app">            <button-counter @clicknow="clicknow">这里是插槽</button-counter>            <button-counter @clicknow="clicknow"></button-counter>        </div>        <script>            //第一子组件            Vue.component('button-counter', {                data() {                    return {                        count: 0                    }                },                template: '<div style="border: solid red 1px; margin-bottom: 10px;"> <slot></slot> <button v-on:click="add">点击了 {{ count }} 次</button></div>',                methods: {                    add() {                        this.count++;                        //子组件触发的add办法,通过this.$emit,把count的值放入clicknow函数之中,并在父组件调用,就会把子组件的数据传输到父级组件                        this.$emit('clicknow', this.count);                    }                }            })            //实例化Vue对象            new Vue({                el: "#app",                data: {},                methods: {                    clicknow(e) {                        //这里的e就是子组件的count                        console.log(e);                    }                }            })        </script>    </body></html>

组件上反对v-model

这样解决自定义组件,就能够反对v-model了

<script>    Vue.component('custom-input', {      props: ['value'],      template: `        <input          v-bind:value="value"          v-on:input="$emit('input', $event.target.value)"        >      `    })</script>
<custom-input v-model="searchText"></custom-input>

动静组件

点击不同的按钮,上面对应就会显示不同的组件

上述内容能够通过 Vue 的 <component> 元素加一个非凡的 is 属性来实现:

即,点击不同按钮时,更改currentTabComponent的值为对应组件名,就能够把component标签变成对应的自定义标签

<component v-bind:is="currentTabComponent"></component>

官网给出的示例代码

<!DOCTYPE html><html>  <head>    <title>Dynamic Components Example</title>    <script src="https://unpkg.com/vue"></script>    <style>      .tab-button {        padding: 6px 10px;        border-top-left-radius: 3px;        border-top-right-radius: 3px;        border: 1px solid #ccc;        cursor: pointer;        background: #f0f0f0;        margin-bottom: -1px;        margin-right: -1px;      }      .tab-button:hover {        background: #e0e0e0;      }      .tab-button.active {        background: #e0e0e0;      }      .tab {        border: 1px solid #ccc;        padding: 10px;      }    </style>  </head>  <body>    <div id="dynamic-component-demo" class="demo">      <button        v-for="tab in tabs"        v-bind:key="tab"        v-bind:class="['tab-button', { active: currentTab === tab }]"        v-on:click="currentTab = tab"      >        {{ tab }}      </button>      <component v-bind:is="currentTabComponent" class="tab"></component>    </div>    <script>      Vue.component("tab-home", {        template: "<div>Home component</div>"      });      Vue.component("tab-posts", {        template: "<div>Posts component</div>"      });      Vue.component("tab-archive", {        template: "<div>Archive component</div>"      });      new Vue({        el: "#dynamic-component-demo",        data: {          currentTab: "Home",          tabs: ["Home", "Posts", "Archive"]        },        //currentTab变动触发,返回给component元素的is属性,渲染出对应的组件标签          computed: {          currentTabComponent: function() {            return "tab-" + this.currentTab.toLowerCase();          }        }      });    </script>  </body></html>

在动静组件上应用keep-alive

在下面例子中,但在这些组件之间切换的时候,你有时会想放弃这些组件的状态,以防止重复重渲染导致的性能问题。(比方,在一个组件中选中某个checkbox,然而切换到另一个组件,再切换回来,选中状态就会隐没,keep-alive能够放弃状态)

<!-- 失活的组件将会被缓存!--><keep-alive>  <component v-bind:is="currentTabComponent"></component></keep-alive>

异步组件(待补充)

文档-异步组件

在大型利用中,咱们可能须要将利用宰割成小一些的代码块,并且只在须要的时候才从服务器加载一个模块。为了简化,Vue 容许你以一个工厂函数的形式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件须要被渲染的时候才会触发该工厂函数,且会把后果缓存起来供将来重渲染。

3.5 非凡个性

Vue 实例裸露了一些有用的实例属性和办法。它们都有前缀 $,以便与用户定义的属性辨别开来。

var data = { a: 1 }var vm = new Vue({  el: '#example',  data: data})vm.$data === data // => truevm.$el === document.getElementById('example') // => true// $watch 是一个实例办法vm.$watch('a', function (newValue, oldValue) {  // 这个回调将在 `vm.a` 扭转后调用})

还有$refs$emit()

1. ref操作dom元素

<div id="app">        <input ref="a1"  v-model="message">          <p ref="a2">咱们</p></div>
new Vue({          el: '#app',          data: {            message:''          },          mounted(){              //生命周期函数,加载结束              console.log(this.$refs)//能够依据ref值来获取对用的dom元素              this.$refs.a1.focus()//让ref=a1的input获取焦点          }        })        

2.emit定义事件

程序化的事件侦听器

emit用法查看这里

$emit 的定义一个事件,通过事件还能够传递参数,它能够被 v-on 侦听,然而 Vue 实例同时在其事件接口中提供了其它的办法。咱们能够(eventHandler是侦听到事件后,的处理函数):

  • 通过 $on(eventName, eventHandler) 侦听一个事件
  • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
  • 通过 $off(eventName, eventHandler) 进行侦听一个事件

你通常不会用到这些,然而当你须要在一个组件实例上手动侦听事件时,它们是派得上用场的。

4.过渡和动画(待补充)

列表适度

动画过渡

点击按钮后,文字缓缓淡出淡入

<div id="demo">  <button v-on:click="show = !show">    Toggle  </button>  <transition name="fade">    <p v-if="show">hello</p>  </transition></div>
new Vue({  el: '#demo',  data: {    show: true  }})
.fade-enter-active, .fade-leave-active {  transition: opacity .5s;}.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {  opacity: 0;}

5.Vue发送网络申请

接口服务器

这里咱们不搭建服务端,而是应用json-server,这个工具能够把json文件托管成一个WEB服务器。特点:基于Express,反对GET,POST,PUT,DELETE办法,反对跨域
  • 官网:https://www.npmjs.com/package...
  • 装置:npm install -g json-server(全局装置,cmd处于任意目录下就能够)
  • 创立db.json文件
{  "posts": [    { "id": 1, "title": "json-server", "author": "typicode" },    { "id": 2, "title": "json-server2", "author": "typicode2" }    { "id": 3, "title": "json-server3", "author": "typicode3" }  ],  "comments": [    { "id": 1, "body": "some comment", "postId": 1 }  ],  "profile": { "name": "typicode" }}
  • 启动Json服务:json-server --watch db.json(时cmd在db.json所在的目录下输出,json-server --watch --port 3000 json-server更改端口)
  • 拜访http://localhost:3000/posts/1,会返回{ "id": 1, "title": "json-server", "author": "typicode" }

明确接口规定是什么

RESTful接口规定标准,参见这篇文章http://www.ruanyifeng.com/blo...

特点:只须要关怀申请形式,不必必关怀 增删改查时应用不同的url

json-server工具利用RESTful接口规定 :(以下是json-server运行后的接口,曾经实现了能够间接用)

  • routers(路由)
GET申请页面      POST增加数据(上传数据),数据在申请头中PUT批改数据,数据在申请体中DELETE删除数据 
GET    /posts     查问所有数据GET    /posts/1   查问id为1的数据POST   /postsPUT    /posts/1   批改id为1的数据DELETE /posts/1  删除id为1的数据
  • 分页查问
//10 items are returned by defaultGET /posts?_page=7//一页返回20条数据GET /posts?_page=7&_limit=20
  • 含糊查问
//title是字段,查问title中和server类似的记录GET /posts?title_like=server
  • 其余更多标准

postman测试接口

postman是一款接口测试工具
  • 官网:下载
  • 界面

  • 应用

POST 状态码201,其余都是200

发送申请

应用Ajax还是axios发送网络申请的实质都是XMLHttpRequest,咱们能够应用插件不便操作

axios:能够在任何中央用于发送申请,举荐应用

中文文档

github官网

npm install axios装置到对应目录

根本应用规定

<script src="axios.js的地位"></script><script>    //GET    axios        .get(url)//  /posts查所有,/posts/id查指定id        .then((res)=>{                res.data//获取的数据        })        .catch((error)=>{            //出错后的解决        })                //POST    axios        .post(url,{提交的数据})//  /posts        .then((res)=>{            res.data//获取的数据            })         .catch((error)=>{                //出错后的解决         })                     //PUT    axios        .put(url,{提交的数据}) //  /put/id批改指定id的数据        .then((res)=>{            res.data//获取的数据            })         .catch((error)=>{                //出错后的解决         })            //DELETE    axios        .delete(url) //  /delete/id删除指定id的数据        .then((res)=>{            res.data//获取的数据            })         .catch((error)=>{                //出错后的解决         })    </script>

在网页中应用

<script src="node_modules/axios/dist/axios.js"></script>    <script>        axios            .get("http://localhost:3000/posts")            .then((res)=>{                const {status,data}=res                if(status==200){                    console.log(data)                }            })            .catch((err)=>{            })                    axios            .post("http://localhost:3000/posts",{                titlt:"hh",                author:"hh"            })            .then((res)=>{                const {status,data}=res                if(status==201){                    console.log(data)                }            })            .catch((err)=>{            })        axios            .put("http://localhost:3000/posts/5",{                titlt:"hh2",                author:"hh2"            })            .then((res)=>{                const {status,data}=res                if(status==200){                    console.log(data)                }            })            .catch((err)=>{            })                    axios            .delete("http://localhost:3000/posts/5")            .then((res)=>{                const {status,data}=res                if(status==200){                    console.log(data)                }            })            .catch((err)=>{            })    </script>

在Vue我的项目中应用

new Vue({    el: '#app',    data: {        lists: [],    },    mounted() {        this.getAll() //查问所有数据在网页加载后调用,用生命周期    },    methods: {        //把增删改查函数写在methods中        //网页加载后调用,放到mounted中        //通过触发工夫调用的,给对应的html元素增加 v-on: 指令        getAll() {            axios                .get("http://localhost:3000/posts")                .then((res) => {                    const {                        status,                        data                    } = res                    if (status == 200) {                        this.lists = data                    }                })                .catch((err) => {                })        }    }})

其余

import axios from 'axios'//给axios拜访的API后面增加固定前缀axios.defaults.baseURL="http://8.131.105.244:3000"//通过axios拦截器增加token验证axios.interceptors.request.use(config=>{    //给config的headers减少新的字段Authorization,把token增加进去    config.headers.Authorization=window.sessionStorage.getItem('token')    return config})

6.vue-cil工具

vue-cli:生成一套规范的vue我的项目目录

vue-cil称为脚手架

vue-cli是全局命令行工具

vue-cli反对热更新,删除代码,自动更新启动服务器;如果批改我的项目配置文件,须要从新npm run dev

启动UI界面:vue ui

官网:https://cli.vuejs.org/zh/

应用步骤

  • 装置:前提是要求曾经装置nodejs
//装置vue-cli3npm install -g @vue/cli//使得vue-cli3能够应用vue-cli2的 vue-init 指令npm install -g @vue/cli-init
  • 创立我的项目步骤
在须要的文件夹下,执行以下指令。起名用英文名,不能有vue webpack等关键字
//vue init 我的项目模板 我的项目名vue init webpack-simple heroes

依据须要抉择,抉择默认就间接回车

//进入我的项目目录//装置创立我的项目的依赖包,主动找到package.json文件中的记录进行装置npm install//运行自带的服务器,弹出网页npm run dev

目录构造剖析

  • src下

    • assets :搁置css,字体,图标等动态资源
    • App.vue : .vue是组件文件,组成:tempalte script style 。 App.vue相当于整个我的项目的根组件,所有其余组件都要放到App.vue中,并导出,在main.js导入
    • main.js : 程序的入口文件,导入各种包(App.vue组件,路由router.js)
    //ES6对于模块的应用//导出export default{}//导入,本人写的导入写地址,别的间接写包名import App from './App.vue'//Nodejs中module.exportsrequire()
    //默认main.jsimport App from './App.vue'new Vue({  el: '#app',  render: h => h(App)})

  • .babelrc :因为有的浏览器不反对ES6,应用babel进行转换,这个文件是bable的配置文件
  • .editorconfig编辑器的配置文件
  • .gitignore:记录的git的排除疏忽文件
  • index.html的代码中引入了build.js,vue-cli中应用了webpack,webpack把资源解决放在在build.js中
  • package.json记录我的项目依赖的包和其余我的项目信息
//package.json中有一个scripts的字段,key是value命令的简写,cmd调用时写 "npm run 简写""scripts": {    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"  }
  • package-lock.json 记录我的项目依赖的包所应用的版本和下载地址
  • webpack.config.js:webpack的配置文件,vue-cli中应用了webpack

.vue文件构造

<template>     <div>         //页面模板    </div></template><script>    //引入页面所有的包    import echarts from "echarts"    //    export default{        //生命周期函数        created(){},        mounted(){//这时候页面的dom元素曾经渲染结束了},        //数据        data(){            return{                a:"xx"            }        },        //办法        methods:{                    }    }</script><style lang="less" scoped>    //lang="less"反对less语法    //scoped示意style款式只在组件内起作用    //款式</style>

7.vue-router

路由根底

vue-router是Vue的官网插件,性能是实现前端路由

  • 装置 npm install vue-router

援用前必须引入vue.js

<script src="/path/to/vue.js"></script><script src="/path/to/vue-router.js"></script>
  • 应用

<div id="app" >        <!--1.设置跳转-->        <!--      网址url变成'....#/a' . to属性的值中/能够省略   -->         <router-link to="/a">首页</router-link>         <router-link to="/b">热点</router-link>         <router-link to="/c">视频</router-link>        <!--2.容器-->        <router-view></router-view>    </div>
<script src="node_modules/vue/dist/vue.js"></script>    <script src="node_modules/vue-router/dist/vue-router.js"></script>    <script>        //3.设置渲染页面        var comA = { template: '<div>首页</div>' }        var comB = { template: '<div>热点</div>' }        var comC = { template: '<div>视频</div>' }        //4.路由配置(设置路由匹配规定)        var routes = [          { path: '/a', component: comA },          { path: '/b', component: comB },          { path: '/c', component: comC }                  ]        //5.实例化路由        const router = new VueRouter({          routes // (缩写) 相当于 routes: routes        })        new Vue({              el: '#app',              //6.挂载路由,当引入vue-router后就vue多了一个选项router               router // (缩写) 相当于 router: router                                   })        </script>    

动静路由

适宜于不同标识(url中#之后的局部)渲染雷同页面,例如:详情页

<div id="app" >        <!--1.设置跳转-->         <router-link to="/baskball">篮球</router-link>         <router-link to="/football">足球</router-link>         <router-link to="/pp">乒乓球</router-link>        <!--2.容器-->        <router-view></router-view>    </div>
    <script src="node_modules/vue/dist/vue.js"></script>    <script src="node_modules/vue-router/dist/vue-router.js"></script>    <script>        //3.设置渲染页面            //$route是获取routes对象        var Ball= { template: '<div>球组件{{$route.params.id}}</div>' }            //4.配置路由(设置路由匹配规定)        var routes = [            //动静路由的写法,id是个参数          { path: '/:id', component: Ball },                  ]        //5.实例化路由        const router = new VueRouter({          routes // (缩写) 相当于 routes: routes        })        new Vue({              el: '#app',              //6.挂载路由               router // (缩写) 相当于 router: router                                   })            </script>        

从数据中获取url标识

data中绑定user的值为home,同时通过应用v-bind绑定 to属性,赋值跳转的链接

<div id="app" >        <!--1.设置跳转-->        <!--      网址url变成'....#/a'     -->         <router-link v-bind:to="user">家</router-link>                 <!--2.容器-->        <router-view></router-view>    </div>
<script src="node_modules/vue/dist/vue.js"></script>    <script src="node_modules/vue-router/dist/vue-router.js"></script>    <script>        //3.设置渲染页面        var Ball= { template: '<div>球组件</div>' }            //4.配置路由(设置路由匹配规定)        var routes = [          { path: '/home', component: Ball }                  ]        //5.实例化路由        const router = new VueRouter({          routes // (缩写) 相当于 routes: routes        })        new Vue({              el: '#app',              data:{                  user:"home"              },              //6.挂载路由               router // (缩写) 相当于 router: router                                   })            </script>    

总结下

//固定<router-link to="固定的链接"></router-link>//动静路由,点击不同链接,加载同一个页面,只不过页面数据不同(适宜做详情页)<router-link to="/a"></router-link><router-link to="/b"></router-link>var Ball= { template: '<div>球组件{{$route.params.id}}</div>' }var routes = [{ path: '/:id', component: Ball }]//user的值由data确定<router-link v-bind:to="uer的值"></router-link>//后面的例子,配置路由只有path,component字段,能够增加name字段<router-link v-bind:to="{path:'指定配置的路由中的path字段值'}"></router-link><router-link v-bind:to="{name:'指定配置的路由中的name字段值'}"></router-link>

重定向

//4.配置路由(设置路由匹配规定)        var routes = [            //形式一:指定path            // {path:"/",redirect:{            //     path:"/home"}            // },            //形式二:只当name            {path:"/",redirect:{                name:"aa"}                            },            { path: '/home',name:"aa", component: Ball },            //写在最初,如果拜访的地址不是下面的,就重定向            { path: '*',name:"aa", redirect:{                path:"/home"}             }                  ]

编程式导航

如果不能应用<router-link>进行路由,能够用v-bind绑定办法,在办法里,获取路由对象$router.push( {path:' 门路'} )进行路由,参数{“门路”} {path:"门路"} {name:"routes中的name"}

<div id="app" >        <!--1.设置点击跳转-->         <button @click="urlchange()">点击跳转</button>        <!--2.容器-->        <router-view></router-view>    </div>
<script src="node_modules/vue/dist/vue.js"></script>    <script src="node_modules/vue-router/dist/vue-router.js"></script>    <script>        //3.设置渲染页面        var Ball= { template: '<div>球组件</div>' }            //4.配置路由(设置路由匹配规定)        var routes = [            { path: '/home',name:"aa", component: Ball },                ]        //5.实例化路由        const router = new VueRouter({          routes // (缩写) 相当于 routes: routes        })        new Vue({              el: '#app',              data:{                  user:"home"              },              //6.挂载路由              router:router,            //跳转办法              methods:{                                       urlchange(){                      this.$router.push({path:'/home'})                  }              }                                                                    })            </script>    

嵌套路由

<div id="app" >        <!--1.设置跳转-->        <router-link to="/a">音乐</router-link>        <!--2.容器-->        <router-view></router-view></div>
<script src="node_modules/vue/dist/vue.js"></script>    <script src="node_modules/vue-router/dist/vue-router.js"></script>    <script>        //3.设置渲染页面        var music= { template: `<div>            <router-link to="/music/rock">摇滚</router-link>            <router-link to="/music/pop">风行</router-link>            <router-view></router-view>        </div>`        }            //二级渲染页面                    var musicSub={template:`<div>            我是music音乐组件        </div>`        }        //4.配置路由(设置路由匹配规定)        var routes = [            { path: '/a',              component:music,              //二级路由,children和routes的用法一样              children:[{                  path:"/music/:id",                  component:musicSub              }]             },                    ]        //5.实例化路由        const router = new VueRouter({          routes // (缩写) 相当于 routes: routes        })        new Vue({              el: '#app',              data:{                  user:"home"              },              //6.挂载路由              router // (缩写) 相当于 router: router                                                              })            </script>    

路由守卫

在路由跳转之前 咱们次要是利用vue-router提供的钩子函数beforeEach()对路由进行判断。

// 路由守卫router.beforeEach((to,from,next)=>{        if(to.matched.some(res=>res.meta.isLogin)){//判断是否须要登录            if (sessionStorage['username']) {                next();            }else{                next({                    path:"/login",                    query:{                        redirect:to.fullPath                    }                });            }        }else{            next()        }    });export default router;

to 示意将要跳转到的组件 (指标组件)
console.log(from); //(源组件)
next();
next 是一个函数
next() 进入下一个组件的钩子函数
next(false) 阻止跳转 中断导航
next("/login") 进入指定的组件的钩子函数

补充

let routeData = this.$router.resolve({path:'exteriorColourPicList',query:{albumId:albumId}});window.open(routeData.href);

8.Vuex

Vuex官网文档

Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式。它采纳集中式存储管理利用的所有组件的状态,并以相应的规定保障状态以一种可预测的形式发生变化。

看以下例子

state和getters的用法

mutations的用法:

更改 Vuex 的 store 中的状态的惟一办法是提交 mutation。且不能是异步办法

action的用法:

Action 是用来解决异步操作的,提交的是 mutation,而不是间接变更状态

const store = new Vuex.Store({  state: {    count: 0  },  mutations: {    increment (state) {      state.count++    }  },  actions: {    incrementASync (context) {      context.commit('increment')    }  }})
this.$store.dispatch('incrementASync')

9. 案例

## 我的项目起步

应用vue-cli新建我的项目

组件化

  1. 在boostrap官网找到bootstrap3的后盾模板(https://v3.bootcss.com/exampl...),右键“查看网页源代码”,复制body中的html代码,粘贴到App.vew文件的template下
  2. 在main.js中引入款式文件
npm install bootstrap@3//下载bootstrp//style.css请到网页源码中找出引入款式的链接,进入,复制源码,新建文件style.css放在assets目录下//导入款式文件import "../node_modules/bootstrap/dist/css/bootstrap.css"import "./assets/style.css"

报错,有不能辨认的文件,须要需改webpack.config.js

增加以下文件(察看文档构造,就晓得加在哪里了)

{    test:/\.(ttf|woff2|woff|eot)$/,        loader:'file-loader',            options:{                name:'[name].[ext]?[hash]'            }}
  1. npm run dev

  1. 在原来的根底上新建

  1. 把之前粘贴的到App.vue的template中的html,划分成一个一个组件,别离放在.vue文件中的template中
  2. 【5】的具体步骤,在App.vue文件中template提取nav头部,放到appNav.vue的template中(特地留神一点:template中内容必须在同一个根div下),script中减少export default{ }进行导出。接下来在App.vue中操作,如下:
<!--App.vue文件--><template>  <div id="app">    <!--顶部栏-->    <!-- 3.通过组件名,应用组件,命名是驼峰标识appNav ,能够应用app-nav,不是的话,间接写-->    <app-nav></app-nav>    //其余部分不变<template>    <script>      //在App.vue中应用appnav.vue组件      //1.引入组件      import appNav from './components/common/appnav.vue'          export default {    name: 'app',    //2.通过选项注册组件    components:{      //appNav:appNav简写成appNav      appNav    },    data() {      return {        msg: 'Welcome to Your Vue.js App'      }    }  }</script><style> //不变</style>

提取路由模块

src下新建router文件,在其下建router.js

//router.js//模块:路由,官网文档中给出的应用形式import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)//导入要渲染的组件import List from "../components/list/list.vue"import Bar from "../components/bar/bar.vue"import Foo from "../components/foo/foo.vue"var routes=[  {name:"heroes",path:"/heroes",component:List},  {name:"bar",path:"/bar",component:Bar},  {name:"foo",path:"/foo",component:Foo}]var router=new VueRouter({  //全局设置激活router-link后,给对应router-link的class属性减少的值.点击后减少active选中成果  linkExactActiveClass:'active',  routes})//导出router在main.js中应用export default router
//main.js中减少//1.导入路由import router from "./router/router.js"new Vue({  el: '#app',  render: h => h(App),  //2.挂载导入的对象  router})

appslider.vue 侧边栏组件

<template>  <ul class="nav nav-sidebar">      <!--tag="li"是让router-link在渲染html页面是时渲染成<li>-->    <router-link to="/heroes" tag="li"><a>英雄列表</a></router-link>    <router-link to="/bar" tag="li"><a>武器列表</a></router-link>    <router-link to="/foo" tag="li"><a>配备</a></router-link>  </ul></template><script>  export default{  }</script><style></style>

应用接口服务器server-json

在heroes我的项目外建设server文件夹,新建db.json

{    "heroes":[        {"id":1,"name":"张1","gender":"男"},        {"id":2,"name":"张2","gender":"男"},        {"id":3,"name":"张3","gender":"女"},        {"id":4,"name":"张4","gender":"男"},        {"id":5,"name":"张5","gender":"男"},        {"id":6,"name":"张6","gender":"女"},        {"id":7,"name":"王1","gender":"男"},        {"id":8,"name":"王2","gender":"女"}    ]}

启动json-server(装置啥的看之前的【4】)

json-server --watch db.json

list.vue显示取出数据,删除数据

在我的项目中装置axio,用于发送申请

npm install axios

在list.vue中

<template>   <div>     <h2 class="sub-header">Section title</h2>     <a class="btn btn-success">减少</a>     <div class="table-responsive">         <thead>           <tr>             <th>ID</th>             <th>姓名</th>             <th>性别</th>             <th>操作</th>           </tr>         </thead>         <tbody>           <tr v-for="list in lists" v-bind:key="list.id">             <td>{{list.id}}</td>             <td>{{list.name}}</td>             <td>{{list.gender}}</td>             <td>                <a v-on:click="deleteById(list.id)">删除</a>             </td>           </tr>         </tbody>       </table>     </div>   </div></template><script>  //from后间接写包名  import axios from 'axios'  export default{    data(){      return{        lists:[]      }    },    mounted(){      this.getData()    },    methods:{      //查问所有      getData(){        axios              .get("http://localhost:3000/heroes")              .then(res=>{                const {status,data}=res                if(status==200){                  this.lists=data                }              })      },      deleteById(id){        axios              .delete("http://localhost:3000/heroes/"+id)              .then((res)=>{                const {status,data}=res                if(status==200){                  console.log("删除胜利")                  this.getData()                }              })      }    }  }</script><style></style>

优化

//1.不必在每个须要网络申请的vue组件中引入axios//2.增删改查,同一个api,只不过申请形式不同和加不加id值,把根底url提取进去,放到全局//以下代码均写在main.js中import axios from 'axios'//解决问题1,把axios进行全局配置,在任意一个vue组件中能够间接应用,不必importVue.prototype.axios=axios//各个组件文件中,不用引入axios,用axios的中央换成this.axios.get/post/put/delete即可//解决问题2axios.defaults.baseURL="api中根底url,比方:http://localhost:3000/"//this.axios.get("要拼接的内容") 函数会主动把baseURL拼接上

10.综合案例

前端初始化

前提装置好vue-cli

//形式一:命令启动(要建我的项目的目录下)vue init webpack 我的项目名//呈现的让选的内容,只写了重点的选啥//选 runtime+compilervue build //查看代码标准,不标准报错。不启用use ESlint to lint you code? n//开启单元测试set up unit tests? n//开启端对端的测试setup e2e tests with Nigtwatch? n//启动我的项目npm run dev///////////////////////////////////////////////////形式二:界面启动(要建我的项目的目录下)vue ui初始化git仓库倡议  init project选手动装置 Babel,Router,应用配置文件预设保不保留均可 创立我的项目后,进入我的项目仪表盘,找到插件,装置vue-cli-plugin-element。导入形式抉择按需导入装置依赖,axios (装置到运行依赖) 启动我的项目 工作-》server-》运行

我的项目托管

增加公钥

登录码云 www.gitee.com

//本地任意目录cmd输出后,连按3次回车ssh-keygen -t rsa -C "xxxxx@xxxxx.com"//例如,我的输出ssh-keygen -t rsa -C "1270433876@qq.com" //在本地找到【 用户/电脑名/.ssh 文件夹 】,关上其中的id_ras.pub,复制内容粘贴到 码云-》设置-》ssh公钥-》增加公钥中,增加公钥//本地任意目录cmdssh -T git@gitee.com 抉择yes,增加以后主机到可信赖列表

托管本我的项目

登录码云-》新建仓库

在我的项目目录关上cmd,

//在任意地位下,做全局配置git config --global user.name "用户名"git config --global user.email "邮箱"//在我的项目目录下git statusgit add .git commit -m"第一次提交"//在我的项目目录下,把本地新建的vue我的项目上传到码云git remote add origin https://gitee.com/hyj1270433876/test.git git push -u origin master//弹出窗口,输入码云的邮箱,明码,确定就上传胜利了
////本地提交到指定近程分支上//如果本地以后所在分支与近程分支同名git push 近程仓库名 近程分支名//不同名须要建设本地分支与近程分支之间的映射git push 近程仓库名 本地分支名:近程分支名

登陆组件

token维持登录状态原理

http是无状态的

  • 通过cookie 在客户端记录登录状态
  • 通过session 在服务端登录记录状态
  • 通过token形式维持登录状态(存在跨域问题时应用)

因为浏览器前后台之间存在跨域问题,所以应用token

用户点击登录验证明码,服务端返回token,客户端接管到保留在sessionStorage(会话存在期间存在,完结销毁)中

以下是token原理图

开发登录性能

  • git status查看是否有未提交的内容,有的话git addgit commit -m "提交标注"
  • 创立新分支 git checkout -b 分支名,并切换到该分支,git branch查看所有分支,加*的是以后分支
  • 输出vue ui进入vue面板,工作-》server-》运行,待编译实现后,vue我的项目就能跑起来了,点击“启动app”
  • 整顿目录把本来默认的我的项目目录清理下
  • 在components中新建组件login.vue
  • 应用反对less语言,在vue-cli面板中,依赖-》增加依赖-》搜寻less-loader ,抉择"开发依赖"-》装置,在搜寻less装置到“开发依赖”。 在 工作-》server-》点击进行后,再启动
<!--login.vue--><template>    <div>登陆组件</div></template><script>    export default{}</script><style lang="less" scoped>    /*    lang="less"是使style反对less语言    scoped是款式尽在组件内失效    */    </style>
  • 在router.js中注册login.vue组件。import和增加routes
import VueRouter from 'vue-router'import Login from './components/login.vue'Vue.use(VueRouter)const routes = [    {path: '/',redirect:'/login'},    {path: '/login',name: 'login',component: Login}     ]const router = new VueRouter({  routes})export default router
  • 因为应用element-ui时,应用的按需导入,所以在plugins/element.js进行导入,注册
import Vue from 'vue'//因为应用element-ui时,应用的按需导入,所以应用什么组件都要导入import { Button } from 'element-ui'import { Form,FormItem } from 'element-ui'import { Input } from 'element-ui'//注册成全局可用的标签Vue.use(Button)Vue.use(Form)Vue.use(FormItem)Vue.use(Input)
  • 进一步欠缺 login.vue, element文档中给出了from组件的办法,如何应用?
//给按钮绑定 v-on="d()" 给表单组件绑定 ref="a" <script>    //能够有生命周期函数        data(){//必须有return的函数        return{                      }    },      methods:{//对象          d(){              //this是以后的vue对象            this.$refs.a.文档中给出的办法              }      }</script>

  • 最终 login.vue
<template>    <div class="login_container">        <div class="login_box">            <!--头像-->            <div class="avatar">                <img src="../assets/logo.png"/>            </div>            <!--表单区-->            <el-form ref="form"  :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form" >              <!-- 账号 -->              <el-form-item prop="manager_email" >                <el-input v-model="loginForm.manager_email"  prefix-icon="czs-user"></el-input>              </el-form-item>              <!-- 明码 -->              <el-form-item  prop="manager_password">                <el-input v-model="loginForm.manager_password"  prefix-icon="czs-lock" show-password></el-input>              </el-form-item>              <!-- 按钮 -->              <el-form-item  class="btns">                 <el-button type="primary" @click="login()">登录</el-button>                 <el-button type="info" disabled>重置</el-button>              </el-form-item>            </el-form>        </div>            </div></template><script>    export default{                data(){            return{                //登录表单的数据绑定对象                loginForm:{                    manager_email:'',                    manager_password:''                },                //表单验证规定                loginFormRules:{                    //email                    manager_email:[//trigger:blur失去焦点时触发                        { required: true, message: '请输出登陆邮箱', trigger: 'blur' }                    ],                    manager_password:[                        { required: true, message: '请输出明码', trigger: 'blur' }                    ]                                    }            }         },        methods:{            login(){                        this.$refs.form.validate(valid=>{                    if(!valid){//格局验证不对,res为flase                        return                    }                    console.log("表单验证胜利")                    var res= this.$axios                                        .post('/login',this.loginForm)                                                .then((res)=>{                                                //特地留神,后盾api接口返回的内容放在了res.data字段了,res.date.date才有manager_id,token等字段                                            // console.log(res.data.err_code)                                            // console.log(res.data.message)                                            // console.log(res.data.data.token)                                                                    if(res.data.err_code==1){                                                //登陆失败                                                this.$message.error(res.data.message)                                            }else{                                                //登陆胜利                                                this.$message.success(res.data.message)                                                //把token保留到本地                                                window.sessionStorage.setItem("token",res.data.data.token)                                                //编程式导航                                                this.$router.push("/home")                                            }                                                                                                                                    })                                                })            }        }            }</script><style lang="less" scoped>.login_container{    background-color:#274a6c;    height: 100%;}.login_box{    width: 450px;    height: 300px;    background-color: white;    border-radius: 3px;    position: absolute;    left: 50%;    top: 50%;    transform: translate(-50%,-50%);}.avatar{    height: 130px;    width: 130px;    border: 1px  solid #eee;    border-radius: 50%;    padding: 10px;    box-shadow:  0 0 10px #ddd;    position: absolute;    left:50%;//相对定位,该元素的左边缘挪动到父元素的50%的    transform: translate(-50%,-50%);//横向,纵向 挪动本元素宽,高的50%    background-color: white;    img{        width: 100%;        height: 100%;        border-radius: 50%;        background-color: #eee;    }    }    .btns{    display: flex;    justify-content: flex-end;}.login_form{    position: absolute;    bottom: 0;    width: 100%;    padding: 0 30px;    box-sizing: border-box;}    </style>
  • 路由导航守卫
//挂载路由导航守卫router.beforeEach((to,from,next)=>{    //to 示意要拜访的门路    //from 示意从哪个门路跳转而来    //next 是一个函数,示意放行        //如果拜访登录页,间接放行    if(to.path=="/login") return next()    //拜访的不是登录页,查看是否有token,没有返回登录页    const tokenStr=window.sessionStorage.getItem("token")            if(!tokenStr){        console.log("尚未登陆,主动跳转回首页")        return next('/login')    }    next()})
  • 实现退出登录,实际上就是清空本地存储的token

    在home.vue组件中

<template>    <el-button type="info" @click="logout">退出</el-button></template><script>            export default{        methods:{                            logout(){                window.sessionStorage.clear()                this.$router.push("/login")            }        }    }</script><style lang="less" scoped></style>

git提交到近程仓库

git status //查看本地分支git add .  //显示有文件,就用这个提交到暂存区git commit -m"实现登录模块" //提交到本地仓库git branch  //查看以后分支,因为之前写我的项目时,进入的login分支,所以会显示login前有个*号///////////////////////////////////////////1.切换到主分支master,再从主分支合并login分支git checkout master //切换到主分支git branch //查看以后分支是否为mastergit merge login //在master上执行,合并login分支git push //提交到近程仓库///////////////////////////////////////////2.处在login分支。 因为login分支是第一次提交所以用以下命令git push -u origin login//网站上就能够看到login分支了,之后提交间接git push就好//如果是克隆指定分支 git clone -b 近程分支名称 代码仓库地址 //如果我的项目文件夹不是从近程分支上拉下来的,本人在本地写的,先初试化成git目录, git init ,就会生成.git文件夹,能够自动记录变动了。

补充个小插曲,我在应用git时呈现了谬误,所有文件都回滚了

git log //查commit提交本地仓库的记录,我找到了对应记录的commit后的一串码即sha码,应用如下命令复原git reset --hard sha码//执行后本地文件复原

后盾主页组件

通过axios拦截器增加token验证

//在main.js中增加,在import axios from 'axios'之后//每次axios申请时,header会带着token传到服务端,服务端能够通过对token的判断确定用户身份axios.interceptors.request.use(config=>{    //给config的headers减少新的字段Authorization,把token增加进去    config.headers.Authorization=window.sessionStorage.getItem('token')    return config})

home开发

留神下,vue中有些标签属性的值为布尔型或是数字,然而属性值只能是string。比方:unique-opened的属性值是布尔值,一种:间接写unique-opened;另一种:v-bind:unique-opened="true",Vue会把字符串true转成布尔值。对于数值,只有一种形式: v-bind:XXXX="20",Vue会把字符串20转成数字

<el-menu background-color="#333744"  text-color="#fff" active-text-color="#4787d5" v-bind:default-active="active" unique-opened>    

home.vue.

<template>    <el-container>        <!-- 头部区 -->        <el-header>            <div>                <span>电商后盾管理系统</span>            </div>            <el-button type="info" @click="logout">退出</el-button>        </el-header>        <!-- 主体区 -->        <el-container>            <!-- 侧边栏 -->            <el-aside width="200px">                <el-menu background-color="#333744"  text-color="#fff" active-text-color="#4787d5" v-bind:default-active="active" unique-opened router>                    <!-- 一级菜单  index接管的是字符串,所以用 数字+''-->                    <el-submenu v-bind:index="menulist.id+''" v-for="menulist in menulists" v-bind:key="menulist.id">                        <!-- 一级菜单模板区 -->                        <template slot="title">                            <!-- 图标 -->                            <i v-bind:class="menulist.icon"></i>                            <!--文本-->                            <span style="margin-left: 10px;">{{menulist.menuName}}</span>                        </template>                                        <!-- 二级菜单 -->                        <el-menu-item v-on:click="saveActive(second_item.path)" v-bind:index="second_item.path+''" v-for="second_item in menulist.children" v-bind:key="second_item.id">                            <template slot="title">                                <!-- 图标 -->                                <i class="el-icon-menu"></i>                                <!--文本-->                                <span>{{second_item.secondMenuName}}</span>                            </template>                                                    </el-menu-item>                    </el-submenu>                                                        </el-menu>            </el-aside>            <!-- 右侧内容 -->            <el-main>                <router-view></router-view>            </el-main>        </el-container>    </el-container></template><script>    export default {                    created(){            this.getMenuList()            this.active=window.sessionStorage.getItem("active")        },                data(){            return{                //左侧菜单数据                menulists:[],                active:''            }        },        methods: {            logout() {                window.sessionStorage.clear()                this.$router.push("/login")            },            getMenuList(){                this.$axios                            .get("/menus")                            .then(backinfo=>{                                //要用的数据在backinfo.data中,把这个值给res。该写法是ES6解构对象。                                const {data:res}=backinfo                                                                if(res.err_code==0){                                    console.log(res)                                    this.menulists=res.data                                    //return this.$message.success(res.message)                                }                            })                            },                            saveActive(active){                //因为一刷新,选中项就会不高亮,所以存下来,每次created执行,再从sessionStorage中取                window.sessionStorage.setItem("active",active)                this.active=window.sessionStorage.getItem("active")            }        }    }</script><style lang="less" scoped>    /*el组件名,能够间接当类名用*/    .el-container {        height: 100%;    }    .el-header {        background-color: #373c41;        display: flex;        justify-content: space-between;        align-items: center;        /*外部文本*/        color: white;        font: 20px;        >div {            display: flex;            align-items: center;            span {                margin-left: 15px;            }        }    }    .el-aside {        background-color: #323744;        .el-menu{            border-right: none;        }    }            .el-main {        background-color: #f6f8fa;    }</style>

新建一个customer.vue。给router.js的routes中配置路由,home中有一个router-viwe,给其配置子路由

//拜访后盾时,主动加载上“用户子组件”    {path: '/home',name: 'home',component: Home, redirect:"/customer" ,children:[        {path: '/customer',name: 'customer',component: Customer}    ]}

这里的customer.vue曾经写了局部内容,咱们在前面会具体写出

即时消息告诉

树形构造的生成

以下性能

有时候咱们要做一个树形构造,然而往往树的层数是不定的,如何在一个表中存下来呢?应用如下的表构造,parent_id就是父层级的order_type_id,is_endnode如果是1则为最终结点

如何把把表格读出来后变成树形的构造呢

exports.getAllOrderType=function(callback){    function treeData(source){          let cloneData = JSON.parse(JSON.stringify(source))    // 对源数据深度克隆          return cloneData.filter(father=>{                           let branchArr = cloneData.filter(child=>father.order_type_id == child.parent_id)    //返回每一项的子级数组            branchArr.length>0 ? father.children = branchArr : ''   //如果存在子级,则给父级增加一个children属性,并赋值            return father.parent_id==0;      //返回第一层          })    }    queryStr="select * from  order_type"    sql.query(connectionString, queryStr, (err, rows) => {        if(err){                    }else{            var a=treeData(rows)            callback({err_code:0,message:'获取订单类型胜利',data:a,affectedRows:0})        }    })}

以下例子是把树形数据,扁平化的计划

let res = []        // 用于存储递归后果(扁平数据)// 递归函数const fn = (source)=>{    source.forEach(el=>{        res.push(el)        el.children && el.children.length>0 ? fn(el.children) : ""        // 子级递归    })} // 树形数据const arr = [    { id: "1", rank: 1 },    { id: "2", rank: 1,        children:[             { id: "2.1", rank: 2 },            { id: "2.2", rank: 2 }         ]     },    { id: "3", rank:1,        children:[             { id: "3.1", rank:2,                 children: [                     { id:'3.1.1', rank:3,                        children:[                             { id: "3.1.1.1", rank: 4,                                 children:[                                    { id: "3.1.1.1.1", rank: 5 }                                ]                             }                         ]                     }                 ]             }         ]     }] fn(arr)             // 执行递归函数console.log(res)    // 查看后果

文件的上传与下载

Vue+element+Nodejs

pdf文件的在线预览和打印

间接点击存储在服务器的文件的直链,如果是pdf。chrome会间接关上pdf,如果是doc会间接进入下载页面

统计图表组件

关上vue的图形化面板【vue ui 命令进入】=>依赖=>增加依赖=>运行依赖=>搜寻echart=>装置

Echart的官网:https://echarts.apache.org/zh/tutorial.html#5%20%E5%88%86%E9%92%9F%E4%B8%8A%E6%89%8B%20ECharts

//在.vue文件中 不能应用<script src="xx"></script>的形式引入  要在 .vue 文件的<script>标签中退出import xxx from "xxx"【写在export default】

myChart.setOption(result);中result是配置和数据,在这里咱们把配置写在data()中,数据是发动网络申请返回的,应用Lodash.js来进行深拷贝,合并在一起并赋值给result。

Lodash.js的官网:https://www.lodashjs.com/

<template>    <!-- 2.为ECharts筹备一个具备大小(宽高)的Dom -->    <div id="main" style="width: 600px;height:400px;"></div></template><script>    //1.导入echarts    import echarts from "echarts"    //深拷贝,创立一个新对象,把两个对象合并成一个放进去    //lodash提供了一个merge(对象1,对象2)函数,返回一个新对象    import _ from "lodash"    export default {        mounted() { //dom元素曾经渲染结束            // 3.基于筹备好的dom,初始化echarts实例            var myChart = echarts.init(document.getElementById('main'));            // 4.指定图表的【配置项】和【数据】            const result = _.merge(this.option, res.data)            // 5.应用刚指定的【配置项】和【数据】显示图表。            myChart.setOption(result);        },        data() {            return {                //图的配置项                option : {                    title: {                        text: 'ECharts 入门示例'                    },                    tooltip: {},                    legend: {                        data: ['销量']                    },                    xAxis: {                        data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]                    },                    yAxis: {},                    series: [{                        name: '销量',                        type: 'bar',                        data: [5, 20, 36, 10, 10, 20]                    }]                }            }        },        method:{            //取回图的数据        }    }</script><style></style>

vue结构设计

https://www.processon.com/min...

举荐文章

《深入浅出Vue.js》读书笔记