vue2笔记完整版

发布时间 2023-08-07 18:00:47作者: 20岁的老年人

 

VUE闲来无事

 

 

 

VUE闲来无事一、vue核心的相关学习一,搭建vue开发环境1.下载vue.js2.下载扩展工具二,hello world案例三,helloworld项目扩展四,模板语法五,数据绑定六,el和data的两种写法发七,理解MVVM模型八,数据代理1.Object.defineProperty2.什么是数据代理3.vue中的数据代理九,事件处理1.事件处理的基本使用2.事件修饰符3.键盘事件4.事件总结十,计算属性1.姓名案例2.计算属性的简写3.天气案例 监视属性-watch4.深度监视5.监视属性简写十一,class和style绑定十二,条件渲染十三,列表渲染1,基本列表2.列表过滤3.列表排序4.数据更新时的问题5.vue数据检测的原理6.set()方法7.总结十四,表单渲染十五,内置指令1.v-text2.v-html3.v-cloak4.v-once5.v-pre十六,自定义属性十七,生命周期一,mounted二,创建三,挂载四,更新五,销毁六,不常用的钩子二,vue组件的理解,开始组件化编程一,对组件的理解二,非单文件组件一,基本构成二,注意事项三,组件的嵌套四,VueComponent五,组件和实例的内置关系三,单文件组件三,vue脚手架的相关知识一,创建脚手架二,分析脚手架结构三,render函数四,修改默认配置五,refs属性六,props配置七,mixin混入八,ToDoList案例1.组件化编码流程(通用)2.代码部分3.总结部分九,组件自定义事件1.绑定2.解绑3.总结十,全局事件总线十一,$nextTick十二,过渡与动画1,动画配置2,过度效果3,多个元素过度4,集成第三方库十三,插件四,vue中的AJAX1.配置代理2.github请求案例3,插槽1.默认插槽2.具名插槽3.作用域插槽4.总结五,vuex1,vuex简介2,求和案例3,vuex的工作原理4,搭建vuex的环境5,vuex开发者工具6,getters配置对象7,mapState和mapGetters八,mapActions和mapMutations九,多组件共享数据十,vuex模块化十一,vuex模块化二六,路由一,什么是路由二,路由技术的基本使用三,路由使用的注意事项四,路由的嵌套五,路由的query参数六,命名路由七,路由的param参数八,router-link的replace属性九,编程式路由导航十,缓存路由组件十一,两个新的生命周期函数十二,路由守卫七,Vue UI组件库

 

一、vue核心的相关学习

本人想先看vue3的但是奈何没文化看不懂,环境也不会装,直接就寄了,只能从头看。

 

一,搭建vue开发环境

1.下载vue.js

http://v2.cn.vuejs.org/v2/guide/installation.html

2.下载扩展工具

我见过最**的事情了,先是下载很难,最后借的网盘下载完成后,谷歌自己引入后不能用,只能用联想浏览器,真的醉了。

 

二,hello world案例


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>
<body>

  <!-- 一个容器 -->
  <div id="root">
      <h1>Hello World! 我是{{name}}</h1>
      <h1>我的年龄时21</h1>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      //创建实例
      new Vue({
          el:'#root' , // el用于指定当前实例服务于那个容器,值通常为css选择器
          data:{//data用于存储数据,数据共el指向对象使用,值暂时先写成一个对象
              name:'王鼎舒'
          }
      })
  </script>
</body>
</html>

1.想让vue工作,就必须创建一个vue实例,且要传入一个配置对象

2.root容器里的代码依然符合html规范,只不过混入了一些特殊的vue语法

3.root容器的代码被称为【vue模板】

三,helloworld项目扩展

1.vue容器和实例一一对应

2.真实开发中只有一个vue实例,配合着一些组件一起使用

3.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的属性

4.一旦data中的数据发生改变,那么页面中用到数据的地方也会发生改变。

四,模板语法


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>
<body>
  <!--



    -->

  <div id="root">
      <h1>插值语法</h1>
      <h3>你好,{{name}}</h3>
      <hr>
      <h1>语法指令</h1>
      <a v-bind:href="url">点击跳转到学习网站1</a>
      <a :href="url">点击跳转到学习网站2</a>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
     
      new Vue(
          {
              el:"#root",
              data:{
                  name:"wds",
                  url:"https://www.huya.com/"
              }
          }
      )
  </script>
</body>
</html>

vue模板语法有两大类:

1.插值语法:

​ 功能:用于解析标签体内容

​ 写法:{{xxx}},xxx是js表达式且可以直接读取到data中的属 性

2.指令语法:

​ 功能:用于解析标签(包括:标签属性,标签体内容,绑定事件.....)

​ 举例”v-bind:“简写为“:”且可以直接读取data中的所有属性

​ 备注:vue有很多的指令,且形式都是v-????,此处我们只是用v-bind举个例子。

五,数据绑定


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>数据绑定</title>
</head>
<body>
  <div id="root">
      单项数据绑定:<input type="text" v-bind:value="name"><br>
      双向数据绑定:<input type="text" v-model:value="name"><br>
   
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue(
          {
              el:'#root',
              data:{
                  name:'我讨厌学习'
              }
          }
      )
  </script>
</body>

</html>

vue中有两种数据绑定方式:

1.单向绑定:(v-bind),数据只能从data导向页面

2.双向绑定:(v-model),数据不仅能从data流向页面,还可以从页面流向data

备注;

​ 1.双向绑定一般都应用在表单类元素上(如input select等)

​ 2.v-model:value简写为v-model,其默认收集的就是value

六,el和data的两种写法发


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>
<body>

  <div id="root">
      <h1>Hello World! 我是{{name}}</h1>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      var a = new Vue({
          //第一种写法
          // el:'#root' ,
          //对象式:data的第一种写法
          // data:{
          //     name:'王鼎舒'
          // }
          data:function () {
              return {
                  name:'王鼎舒 '
              }
               
          }
           
      })
      setTimeout(()=>{
          //第二种写法
          a.$mount('#root')
      },1000)
         
  </script>
</body>
</html>

el的两种写法:

​ 1.new Vue的时候配置el的属性

​ 2.先创建Vue的实例,随后再通过vm.¥mount(‘#root’)指定el的值

data的两种写法

​ 1.对象式

​ 2.函数式

​ 选择:目前两种写法都可以,学习组件后,data必须是函数式,否则出错

一个重要的原则:

​ 由Vue管理的函数一定不能写箭头函数

七,理解MVVM模型

v 视图 view 对应data中的数据

m 模型 model 模板

vm 视图模型 vue实例对象

八,数据代理

1.Object.defineProperty

备注:我也不知道学这个是干啥


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>
<body>
  <script type="text/javascript">
      Vue.config.productionTip = false

      let number = 18
      let person = {
          name:"王鼎舒",
          age:"21"
      }

      Object.defineProperty(person,'sex',{
          // value:'man',
          // enumberable:true,//控制属性是否可以枚举,默认值是false
          // writeable:true,//控制属性是否可以被修改,默认值是false
          // configurable:true//控制属性是否可以被删除,默认值是false

//当有人调用person的age属性时,get函数就会被调用,且返回值就是get的值
get:function(){
  return 'hello'
}

      })
      // console.log(Object.keys(person))
      console.log(person)
       
  </script>
</body>
</html>xxxxxxxxxx 

 

2.什么是数据代理

通过一个对象代理另一个对象中属性的操作(读/写)

3.vue中的数据代理

 

九,事件处理

1.事件处理的基本使用

 


<div id="root">
      <h2>{{name}}讨厌学习</h2>
      <!-- <button v-on:click="shouInfo">点击产生提示</button> -->
      <button @click="shouInfo">点击产生提示</button>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false

      const vm = new Vue({
          el:"#root",
          data:{
              name:"王鼎舒"
          },
          methods:{
              shouInfo(event){
                  //event.target 发生事件的事件目标
                  // console.log(event.target)
                  //这里的this指向vm对象
                  // console.log(this)
                  alert("绝了")
              }
          }

      })
  </script>

2.事件修饰符

vue中的事件修饰符:

1.prevent:默认阻止事件(常用)

2.stop:默认事件冒泡(常用)

3.once:事件只触发一次(常用)

4.capture:使用事件捕获模式

5.self:只有event,target是当前操作的元素时才触发

6.passive:事件只有默认行为执行,无需等待回调执行完毕。

3.键盘事件

1.vue中常用的按键别名:

  1. 回车 enter

  2. 删除 delete

  3. 退出 esc

  4. 空格 space

  5. 换行 tab

  6. 上 up 下 down 左 left 右 right

4.事件总结

修饰符是能连着写的 例如:@click.stop.prevent=“abc”

键盘事件 例如:@keyup.ctrl.y

十,计算属性

1.姓名案例

method方法


<div id="root">
      姓:<input type="text" v-model="firstName"><br><br>
      名:<input type="text" v-model="lastName"><br><br>
      姓名:<span>{{fullName()}}</span>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el:"#root",
          data:{
              firstName:'张',
              lastName:'三'
          },
          methods:{
              fullName(){
                  return this.firstName + '-' + this.lastName
              }
          }
      })
  </script>
</body>

  <div id="root">
      姓:<input type="text" v-model="firstName"><br><br>
      名:<input type="text" v-model="lastName"><br><br>
      姓名:<span>{{firstName.slice(0,3)}}-{{lastName }}</span>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el:"#root",
          data:{
              firstName:'张',
              lastName:'三'
          }
      })
  </script>

这两种方法效率不高

计算属性方法


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>

<body>
  <div id="root">
      姓:<input type="text" v-model="firstName"><br><br>
      名:<input type="text" v-model="lastName"><br><br>
      姓名:<span>{{fullName}}</span>
  </div>

  <script type="text/javascript">
      Vue.config.productionTip = false
      const vm = new Vue({
          el: "#root",
          data: {
              firstName: '张',
              lastName: '三'
          },
          computed:{
              fullName:{
                  //get当有人读取fullname时,get就会被调用,且返回值就作为fullName的值
                  //get的调用1.初次调用get时 2.所依赖的属性发生改变
                   
                  get(){
                      return this.firstName+'-'+this.lastName
                  },

                  set(value){
                      const arr = value.split("-")
                      this.firstName = arr[0]
                      this.lastName = arr[1]
                  }
               
               
              }
          }
      }
      )
  </script>
</body>

</html>

计算属性:

  1. 定义:要用的属性不存在,要通过已有属性计算

  2. 原理:底层借助了之前的Object.defineproperty方法提供getter和setter方法

  3. 优势:与methods方法相比,内部有缓存机制

  4. 备注:1.计算的属性最终会出现在vm上,可以直接读取

    ​ 2.如果计算属性要被修改,那就必须要写set函数上去修改

2.计算属性的简写

只考虑读取不考虑修改的时候才能够使用简写形式

3.天气案例 监视属性-watch


  <div id="root">
      <h2>今天天气很{{nice}}</h2>
      <button @click="showInfo">切换天气</button>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false

      new Vue({
          el:"#root",
          data:{
              ishot:true
          },
          computed:{
              nice(){
                  return this.ishot? "炎热" : "凉爽"
              }
          },
          methods: {
              showInfo(){
                  this.ishot = !this.ishot
              }
          },
          // watch:{
          //     ishot:{
          //         immediate:true,//初始化handler时调用一下
          //         //handler什么时候被调用?当ishot发生改变
          //     handler(newvalue,oldvalue){
          //         console.log("天气发生变化",newvalue,oldvalue)
          //     }
          // }
          // }
      })
          vm.$watch('ishot',{immediate:true,
                   
              handler(newvalue,oldvalue){
                  console.log("天气发生变化",newvalue,oldvalue)
              }
              })
  </script>

监视属性watch:

  1. 当被监视额属性变化时,回调函数自动调用,进行相关操作

  2. 监视属性必须存在,才能监视

  3. 监视属性的两种写法

    ​ 1.new vue时传入watch配置

    ​ 2.通过vm.$watch监视

4.深度监视


  <div id="root">
      <h2>今天天气很{{nice}}</h2>
      <button @click="showInfo">切换天气</button>
      <hr>
      <h3>a的值是{{numbers.a}}</h3>
      <button @click="numbers.a++">点击让a+1</button>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false

      new Vue({
          el:"#root",
          data:{
              ishot:true,
              numbers:{
                  a:1,
                  b:2
              }
          },
          computed:{
              nice(){
                  return this.ishot? "炎热" : "凉爽"
              }
          },
          methods: {
              showInfo(){
                  this.ishot = !this.ishot
              }
          },
          watch:{

              //深度监视
              numbers:{
                  deep:true,
                  handler(){
                      console.log("a发生改变")
                  }
              },
              //监视多级属性中某一属性的变化
              'numbers.a':{
                  handler(){
                      console.log("a发生改变")
                  }
              }
          }
      })

  </script>
</body>

深度监视:

vue中的watch默认不监视对象内部的值的变化(一层)

配置deep:true可以检测对象 内部值的改变(多层)

备注:

vue自身可以检测对象内部值的改变,但是watch默认不可以

使用watch时根据数据具体结构,决定是否采用深度监视

5.监视属性简写

配置项里之后handler时可以简写

十一,class和style绑定

绑定class样式

1.字符串写法

2.数组写法

3.对象写法


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
  <style>
      * {
          margin: 0px;
          padding: 0px;
      }

      html,
      body {
          height: 100%;
      }

      .basic {
          width: 200px;
          height: 150px;
          border: 2px solid black;
      }

      .normal {
         
      }

      .happy {
         
      }

      .sad {
         
      }
  </style>
</head>

<body>
  <div id="root">
      <div class="basic" :class="a" @click="changemod">这是一个div</div><br><br>
      <div class="basic" :class="classArr" @click="changemod">这是一个div</div><br><br>
      <div class="basic" :class="classobj" @click="changemod">这是一个div</div>
       
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el:"#root",
          data:{
              a:"normal",
              classArr:['happy','sad','normal'],
              classobj:{
                  happy:false,
                  sad:false,
                  normal:true
              }
          },
          methods: {
            changemod(){
              const arr = ["happy" , "normal" , "sad"]
              const index = Math.floor( Math.random()*3)
              this.a = arr[index]
            }  
          },
      })
  </script>
</body>

</html>

style样式绑定一般不使用

十二,条件渲染

v-if:写法

1.v-if=”表达式”

2.v-else=“表达式”

3.v-else-if=“表达式”

适用于切换频率较低的场景,其中不展示dom的元素直接被移出(display:none),三个表达式可以一起使用,但是结构体不能被打断。

 

v-show:写法

1.v-shou=“表达式”

适用于切换频率较高的场景

不展示的dom不会被移出只是会被隐藏起来。

十三,列表渲染

1,基本列表


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>
<body>
  <div id="root">
      <h1>{{name}}讨厌学习</h1>
      <button @click="add">点击添加刘鹏的数据</button>
      <ul>
          <li v-for="p,index in persons" :key="p.id">{{p.name}}-{{p.age}}<input type="text"></li>
      </ul>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el:"#root",
          data:{
              name:"王鼎舒",
              persons:[
                  {id:001,name:"wds",age:18,sex:"man"},
                  {id:002,name:"lkc",age:81,sex:"man"},
                  {id:003,name:"lt",age:8,sex:"man"}
              ]
          },
          methods: {
              add(){
                  const p = {id:'004',name:"lp",age:'100+',sex:'woman'}
                  this.persons.unshift(p)
              }
          },
      })
  </script>
</body>
</html>

面试题:react、vue中的key有什么作用?(key的内部原理)

虚拟DOM中key的作用:key是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

对比规则:

旧虚拟DOM中找到了与新虚拟DOM相同的key:

若虚拟DOM中内容没变, 直接使用之前的真实DOM若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面

用index作为key可能会引发的问题:

若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题开发中如何选择key?

最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

2.列表过滤


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>

<body>
  <div id="root">
      <h1>人员列表</h1>
      <hr>
      <input type="text" placeholder="请输入姓名" v-model="keyword">
      <li v-for="(p,index) in filpersons" :key="p.id">{{p.name}}-{{p.age}}</li>
      </ul>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el: "#root",
          data: {
              name: "王鼎舒",
              keyword: '',
              persons: [
                  { id: 001, name: "wds", age: 18, sex: "男" },
                  { id: 002, name: "lkc", age: 81, sex: "男" },
                  { id: 003, name: "lt", age: 8, sex: "男" },
                  { id: 004, name: "nm", age: 18, sex: "男" },
                  { id: 005, name: "dly", age: 81, sex: "男" },
                  { id: 006, name: "adsaddasd", age: 8, sex: "男" }
              ],
              filpersons: []
          },

          watch: {
              keyword: {
                  immediate: true,
                  handler(value){
                      this.filpersons = this.persons.filter((p) => {
                      return p.name.indexOf(value) !== -1
                  })
              }

          }
      }
         
           
      })
  </script>
</body>

</html>

3.列表排序

出了问题


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <title>Document</title>
</head>

<body>
  <div id="root">
      <h1>人员列表</h1>
      <hr>
      <input type="text" placeholder="请输入姓名" v-model="keyword">
      <button @click="sortType=2">升序排序</button>
      <button @click="sortType=1">降序排序</button>
      <button @click="sortType=0">原顺序</button>
      <li v-for="(p,index) in filpersons" :key="p.id">{{p.name}}-{{p.age}}</li>
      </ul>
  </div>
  <script type="text/javascript">
      Vue.config.productionTip = false
      new Vue({
          el: "#root",
          data: {
              name: "王鼎舒",
              keyword: '',
              sortType: 0 ,
              persons: [
                  { id: 001, name: "wds", age: 18, sex: "男" },
                  { id: 002, name: "lkc", age: 81, sex: "男" },
                  { id: 003, name: "lt", age: 8, sex: "男" },
                  { id: 004, name: "nm", age: 28, sex: "男" },
                  { id: 005, name: "dly", age: 831, sex: "男" },
                  { id: 006, name: "adsaddasd", age: 44, sex: "男" }
              ],
          },

         
          computed:{
              filpersons(){
                  return this.persons.filter((p)=>{
                      return p.name.indexOf(this.keyword) !== -1
                  })


                  if(this.sortType){

                      arr.sort((p1,p2)=>{
                      return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                      })
                  }

                  return arr
              }
               
               

          }
           
      })
  </script>
</body>

</html>

4.数据更新时的问题


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>
<body>
   <div id="root">
       <h1>{{name}}讨厌学习</h1>
       <button @click="ubdatewds">修改wds的数据的数据</button>
       <ul>
           <li v-for="p,index in persons" :key="p.id">{{p.name}}-{{p.age}}<input type="text"></li>
       </ul>
   </div>
   <script type="text/javascript">
       Vue.config.productionTip = false
       new Vue({
           el:"#root",
           data:{
               name:"王鼎舒",
               persons:[
                  {id:001,name:"wds",age:18,sex:"man"},
                  {id:002,name:"lkc",age:81,sex:"man"},
                  {id:003,name:"lt",age:8,sex:"man"}
              ]
          },
           methods: {
               ubdatewds(){
                   // //点击按钮时数据直接发生了更新
                   // this.persons[0].age = 21


                   //点击后数据发生更新但是页面不显示
                   this.persons[0] = {id:001,name:"wds", age:21, sex:"man"}
              }
          },
         
      })
   </script>
</body>
</html>

5.vue数据检测的原理

通过data数据,利用vm代理data中的数据

Vue监视数据的原理:

vue会监视data中所有层次的数据

如何监测对象中的数据?

通过setter实现监视,且要在new Vue时就传入要监测的数据

对象中后追加的属性,Vue默认不做响应式处理如需给后添加的属性做响应式,请使用如下API:Vue.set(target,propertyName/index,value)vm.$set(target,propertyName/index,value)如何监测数组中的数据?

通过包裹数组更新元素的方法实现,本质就是做了两件事:

调用原生对应的方法对数组进行更新重新解析模板,进而更新页面在Vue修改数组中的某个元素一定要用如下方法:

使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()Vue.set() 或 vm.$set()特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data等) 添加属性————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

6.set()方法


<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>

<body>
   <div id="root">
       <h1>{{wdsinfo.name}}的爱好列表</h1>
       <h2>年龄:{{wdsinfo.age}}</h2>
       <button @click="addage">添加年龄</button>
       <ul>
           <li v-for="(h,index) in hobby" :key="index">{{h}}</li>
       </ul>
       <ul>
           <li v-for="(f,index) in wdsinfo.friends" :key="index">{{f.name}}--{{f.age}}</li>
       </ul>
   </div>

   <script type="text/javascript">
       Vue.config.productionTip = false

       const vm =new Vue({
           el:"#root",
           data:{
               wdsinfo:{
                   name:"王鼎舒",
                   school:"山西农业大学",
                   friends:[
                      {name:"qqq",age:"22"},
                      {name:"www",age:"24"},
                      {name:"eee",age:"25"}
                  ]
              },
               hobby:["抽烟","喝酒","烫头"]
          },
           methods: {
               addage(){
                   this.$set(this.wdsinfo,"age",21)
              }
          },
      })
   </script>
</body>

</html>

7.总结

十四,表单渲染


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>
<body>

   <div id="root">
       <form @submit.prevent="demo">
          账号:<input type="text" v-model="account"><br><br>
          密码:<input type="password" v-model="password"><br><br>
          性别:
          男<input type="radio" name="sex" v-model="sex" value="male">
          女<input type="radio" name="sex" v-model="sex" value="female"><br><br>
          爱好:
          <input type="checkbox" v-model="hobby" value="sing">唱
          <input type="checkbox" v-model="hobby" value="jump">跳
          <input type="checkbox" v-model="hobby" value="rap">rap
          <input type="checkbox" v-model="hobby" value="bassketball">篮球<br><br>
          所属校区
          <select  v-model="city">
           <option value="taiyuan">太原</option>
           <option value="taigu">太谷</option>
           <option value="yuncheng">运城</option>
           <option value="changzhgi">长治</option>
           <option value="datong">大同</option>
          </select>
          <br><br>
          其他信息:
          <textarea  cols="30" rows="10">
          </textarea><br><br>
          <input type="checkbox">
          阅读并接受<a href="#">《用户协议》</a>
          <br><br>
          <button>提交 </button>


           
       </form>
   </div>
   <script type="text/javascript">
       Vue.config.productionTip = false

       const vm = new Vue({
           el:"#root",
           data:{
               account:'',
               password:'',
               sex:'male',
               // 多组勾选框要写成数组形式,否则默认识别check的值
               hobby:[],
               city:'太原'
          },
           methods: {
               demo(){
                   console.log(this._data)
              }
          },
      })

   </script>
</body>
</html>

总结:

收集表单数据:

若:<input type="text"/>,则v-model收集的是value值,用户输入的内容就是value值若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value属性若:<input type="checkbox"/>没有配置value属性,那么收集的是checked属性(勾选 or 未勾选,是布尔值)配置了value属性:v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)v-model的初始值是数组,那么收集的就是value组成的数组v-model的三个修饰符:

lazy:失去焦点后再收集数据number:输入字符串转为有效的数字trim:输入首尾空格过滤————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

十五,内置指令

1.v-text

总结,没啥用

2.v-html

1.向指定节点中渲染包含html结构的内容

2.与插值语法的区别:

​ 1.v-html公共替换掉节点的内容{{xxx}}则不会

​ 2.v-html可以识别html结构

3.严重注意:v-html有安全性问题

​ 1.一定要在可信的网站上使用v-html,绝对不要用在提交内容上。

3.v-cloak

指令是没有值的

本质是一个特殊的属性,vue实例创建完毕并且接管容器后,会删掉v-cloak属性

使用css配合c-cloak可以解决网速缓慢时,页面内展示出{{xxx}}的问题

4.v-once

1.v-once所在的节点在初次动态渲染之后,就视为静态内容了

2.以后数据更新的改变不会引起v-once所在结构的更新,可以用于性能的优化。

5.v-pre

1.跳过其所在节点的编译过程

2.可利用它跳过,没有使用指令语法,没有使用插值语法的节点,会加快编译。

十六,自定义属性

说白了就是封装dom

有两种方式

1.函数式

2.对象式


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>
<body>
   <div id="root">
       <h2>当前值是:<span v-text="n"></span></h2>
       <h2>扩大10倍后的值<span v-big="n"></span></h2>
       <button @click="n++">n+1</button>
   </div>
   <script type="text/javascript">
       Vue.config.productionTip = false
       new Vue({
           el:"#root",
           data:{
               n :1
          },
           //函数式
           directives:{
               //big函数什么时候会被调用1.指令与元素成功绑定时2.指令所在的模板被重新解析时

               big(element,binding){
                   element.innerText = binding.value *10
                   
              },

               find:{
                   //指令与元素绑定时
                   bind(){
                  },
                   //元素被插入到页面时
                   inserted(){

                  },
                   //指令所在的模板被调用时
                   update(){

                  }

              }
               
          }
      })
   </script>
</body>
</html>

 

十七,生命周期

一,mounted

当vue完成模板渲染,并且将dom元素放入页面之后,(挂在完毕)第一次调用称为挂载,第二次以及之后就是更新了。

但是这仅仅是vue生命周期的一部分,一个完整的生命周期包含很多的部分

生命周期是什么:

  1. 生命周期又叫做生命周期函数,生命周期回调函数,生命周期钩子。

  2. vue再特殊时期帮我们调用的一些函数。

  3. 生命周期函数的名字不可更改,但是函数内部的内容是我们自己编写的

  4. 生命周期函数中的this指向的是vue实例化的对象,或者是组件的实例对象。

生命周期的四个大阶段:

  1. 更新

  2. 更新

  3. 挂载

  4. 销毁

二,创建

  1. beforecreate,此时我们还无法访问vm中的data和methods等等

  2. created,此时我们可以通过实例化vue对象来访问到data和methods中的内容,随后页面开始解析模板,生成虚拟DOM并且将DOM存起来

三,挂载

挂载的流程可谓是生命周期中最长的一条线,在整个挂载的过程中:

  1. berforeMount,此时页面呈现没有经过vue编译的DOM内容,举个例子我们的插值语句会以原本的姿态呈现出来

  2. mounted,此时页面呈现的内容就是vue编译过后的DOM,从现在开始算是初始化的过程结束了

四,更新

  1. beforeUpdate,此时数据更新了但是页面是旧的

  2. upDated,此时数据和页面都是更新过后的

五,销毁

  1. beforeDestory,弥留之际,此时还是能拿到数据和调用方法的,但是此时页面已经不在调用了

  2. destory,完全销毁一个实例,清理它与实例的连接,解绑它的全部指令及事件监听器,这里的事件是自定义事件

六,不常用的钩子

nnd,没认真上课,这里其实还有三个钩子,分别是后面的$nexttick和激活和失活,赶紧补上。

二,vue组件的理解,开始组件化编程

组件就是一块砖,哪里需要哪里搬

一,对组件的理解

定义:用来实现局部(特定)功能效果的代码集合(html/css/js/image/....)

作用:复用代码,简化项目编码,提高运行效率。

传统方式编写应用存在的问题:

1.依赖关系混乱,不好维护。

2.代码复用率不高。

使用组件的方式编写代码。

二,非单文件组件

一,基本构成

上了一波大当,这玩意几乎不用,还让我听了30分钟。


<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>

<body>
   <div id="root">
       <h1>{{title}}</h1><br>
       <school></school>
       <hr>
       <student></student>

   </div>
   <script type="text/javascript">
       Vue.config.productionTip = false


       //创建school组件
       const school = Vue.extend({
           //组件定义时,不要写el属性
           template: `<div>
               
               <h2>学校姓名:{{schoolname}}</h2>
               <h2>学校地址:{{address}}</h2>
               
                       </div>`,

           data() {
               return {
                   schoolname: "山西农业大学",
                   address: "山西晋中太谷县"

              }
          }

      })

       //创建学生组件
       const student = Vue.extend({
           //组件定义时,不要写el属性

           template: `<div>
               
               <h2>学生姓名:{{studentname}}</h2>
                <h2>学生年龄:{{age}}</h2>
                       
                       </div>`,

           data() {
               return {
                   studentname: "王鼎舒",
                   age: 22
              }
          }

      })

       //创建vm
       new Vue({
           el: "#root",
           data:{
               title:"你好啊"
          },
           components: {
               school: school,
               student: student
          }
      })


       // new Vue({
       //     el:'#root',
       //     data:{
       //         schoolname:"山西农业大学",
       //         address:"山西晋中太谷县",
       //         studentname:"王鼎舒",
       //         age:22,
       //     }
       // })
   </script>
</body>

</html>

二,注意事项

关于组件名:

一个单词组成:

第一种写法(首字母小写):school第二种写法(首字母大写):School多个单词组成:

第一种写法(kebab-case命名):my-school第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)备注:

组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行可以使用name配置项指定组件在开发者工具中呈现的名字关于组件标签:

第一种写法:<school></school>第二种写法:<school/>备注:不使用脚手架时,<school/>会导致后续组件不能渲染一个简写方式:const school = Vue.extend(options)可简写为:const school = options————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

三,组件的嵌套


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script type="text/javascript" src="../vue.baise/vue.js"></script>
   <title>Document</title>
</head>
<body>

   <div id="root">
       <school></school>
       <hr>

   </div>
   <script type="text/javascript">
       Vue.config.productionTip = false
         //定义学生组件
         const student = Vue.extend({
           template:`<div>
               <h2>学生名称:{{name}}</h2>
               <h2>学生年龄:{{age}}</h2>
               </div>`,

               data(){
                   return{
                       name:"王鼎舒",
                       age:18
                  }
              }

             
      })


       //定义school组件
       const school = Vue.extend({
           template:`<div>
               <h2>学校名称:{{name}}</h2>
               <h2>学校地址:{{address}}</h2>
               <student></student>
               </div>`,

               data(){
                   return{
                       name:"山西农业大学",
                       address:"太谷",
                  }
              },
               components:{
                   student
              }

             
      })

     

       new Vue({
             
           el:"#root",
           components:{
               school:school,
               student:student
          }
              })
       
   </script>
</body>
</html>

四,VueComponent

关于VueComponent:

school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的

我们只需要写<school/><school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)

特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!

关于this指向:

组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是VueComponent实例对象new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是Vue实例对象VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)

Vue的实例对象,以后简称vm————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

五,组件和实例的内置关系

(我听到头疼,是真的头疼,学前端的我恶补了一下后端的基础,绝了)

Vueconpontent.prototype.proto === vue.proto

个人浅薄理解:一个构造函数,有两个对象,一个是实例对象,就是定义构造函数时,函数内写的对象,另一个是原型对象,原型对象是系统给的,不是我们写的,本来组件的原型对象的原型对象因该是object对象,但是vue让组件的原型对象的原型对象指向vue的原型对象,于是组件就能够使用vue原型对象的方法和属性。

(说实话没听懂)


只能说当年的我,甚至连最基本的js基础都没模棱两可就开始干vue了,除了不小的乱子,组件的实例对象就是一个普普通通的对象,这个普通的对象的原型那就是Object对象,但是如何让组件使用vue的方法呢,这里vue的高深就来了,他将vue组件的实例对象的实例对象从Object对象变成了vue的实例对象,不要问是怎么变换的,那就是源码的事情了,我们就当作是公理来看待就好,对象继承原型对象的方法和属性,所以我们才可以在组件中使用vue的方法。

三,单文件组件

内容有好多,

首先我们应该创建vue文件来创建我们的组件,为了让其他组件能够服用必须模块化语言暴露组件

school.vue


<template>
   <!-- 组件的结构 -->
   <div>
       <h2>学校名称:{{ name }}</h2>
       <h2>学校地址:{{ address }}</h2>
   </div>
</template>

<script>

// 组件交互的相关代码
   export default {
   name:'School',
   data() {
       return {
           name: "山西农业大学",
           address: "太谷",
      }
  },

   

}

</script>

<style>
/* 组件的样式 */
.demo {
   background-color: orange;
}
</style>

<!-- const school = Vue.extend({
   template:`<div>
       <h2>学校名称:{{name}}</h2>
       <h2>学校地址:{{address}}</h2>
       <student></student>
       </div>`,

       data(){
           return{
               name:"山西农业大学",
               address:"太谷",
           }
       },
       components:{
           student
       }

     
}) -->

student.vue


<template>
   <div class="demo2">
       <h2>学生名称:{{ name }}</h2>
       <h2>学生年龄:{{ age }}</h2>
   </div>
</template>

<script>
export default {

   name:"student",
   
   
   data(){
       return{
           name:"王鼎舒",
           agae:"21"
      }
  },

}
</script>

<style>

.demo {
   background-color: blue;
}

</style>

这里要注意定义组件的名称的时候使用两个单词双驼峰形式写,否则在放入脚手架后会报错

随后就要创建vue的老大哥App.vue 把之前的模块组合起来

App.vue


<template>
 <div>
   <SchoolInfo></SchoolInfo>
   <StudentInfo></StudentInfo>
</div>
</template>

<script>

import SchoolInfo from './components/school.vue'
import StudentInfo from './components/student.vue'

export default {
   name:'App',

   template:'<app></app>',

   components:{

       SchoolInfo,
       StudentInfo

  }
}
</script>

这串代码是我放入脚手架之后的代码所以组建的名称都发生了改变,改变就是在原基础名称后面写上Info

之后编写main.js代码,引入vue对象和App.vue方便我们操作


import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
 render: h => h(App),
}).$mount('#app')

最后创建index.html文件来创建一个容器放入我们之前的代码

这里引入代码时将引入的代码放在body最下面,放置出现创建但是没有渲染的问题


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root">
      <App></App>
  </div>
  <script type="text/javascript" src="../vue.baise/vue.js"></script>
  <script type="text/javascript" src="./main.js"></script>
</body>
</html>

大概我们要写的就是这么多

但是我们写好的内容是跑不起来的需要脚手架的帮助才能跑起来。

三,vue脚手架的相关知识

终于是学到vue脚手架了折磨,痛苦啊。

一,创建脚手架

如果下载缓慢请配置 npm 淘宝镜像:npm config set registry http://registry.npm.taobao.org全局安装@vue/cli:npm install -g @vue/cli切换到你要创建项目的目录,然后使用命令创建项目:vue create xxxx选择使用vue的版本启动项目:npm run serve暂停项目:Ctrl+CVue 脚手架隐藏了所有 web————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

二,分析脚手架结构

.文件目录├── node_modules ├── public│ ├── favicon.ico: 页签图标│ └── index.html: 主页面├── src│ ├── assets: 存放静态资源│ │ └── logo.png│ │── component: 存放组件│ │ └── HelloWorld.vue│ │── App.vue: 汇总所有组件│ └── main.js: 入口文件├── .gitignore: git版本管制忽略的配置├── babel.config.js: babel的配置文件├── package.json: 应用包配置文件 ├── README.md: 应用描述文件└── package-lock.json: 包版本控制文件————————————————版权声明:本文为CSDN博主「梦入_凡尘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_55593227/article/details/119717498

最后将代码放入脚手架中

 

非常的离谱,头一次执行代码没出什么太大的错误,

这里吐槽之前学习的maven和ssm框架简直是噩梦。

三,render函数

vue.js与vue.runtime.xxx.js的区别:

1.vue.js是完整版的Vue,包含核心功能加模板解析

2.vue.runtime.xxx.js是运行版的Vue,只包含核心功能,没有模板解析器,需要render函数接收creatElement函数去指定具体内容。

四,修改默认配置

没仔细听,默认的配置我们最好还是不要手欠改一下。


这里我说一下,默认配置,真的别动。

五,refs属性

1.id属性的替代者

2.应用在html标签上,获取的是真实的dom元素,应用在组件标签上的的是组建的实例对象。

3.使用方式,在html上获取的是真实的dom元素,应用在组件标签上的是组件实例对象。


<template>

<!-- 模板文档只能有一个容器 -->
<div>
  <h1 ref="text">真TMD服了!!!</h1>
  <MyName></MyName>
  <button @click="showMe">点我输出test的节点</button>
</div>
</template>

<script>
import MyName from "./components/MyName.vue";

export default {
 name: "App",
 components: {
   MyName,
},
 methods: {
   showMe(){
     console.log(this.$refs.text)
  }
},
};
</script>


六,props配置


?这一节我当时就没听吗?

<!-- 这里是App.vue -->
<SchoolInfo name="山西农业大学" address="晋中太谷"></SchoolInfo>
<!-- 这里是School.vue -->
<template>
   <!-- 组件的结构 -->
   <div class="demo">
       <h2>学校名称:{{ name }}</h2>
       <h2>学校地址:{{ address }}</h2>
   </div>
</template>

<script>

// 组件交互的相关代码
   export default {
   name:'SchoolInfo',
   props:["name","address"]

}
</script>

在写的过程中其实有一个问题,但是我的例子中没有体现出来,就是我们传递的信息,都是以字符串的形式传递的,这个时候,如果我们需要传入数字,就需要写的复杂一点,加上v-bind,(其实现在想一想,java其实也挺好的,明确了数据类型在之后的操作中,方便了不少,起码不会0.1+0.2!=0.3)


props:{
   name:{
type:String,//name的类型是字符串
        required:true//name是必要的
  }
   address:{
       type:String,
       required:true
  },
   //下面这个是我举得例子,真实的项目没有这一项
       age:{
           type:Number,
           default:23//默认值
      }
}

props传过来的值是不能修改的。严格并不是不能改,改的话会发生不可预期的错误,但是改了之后是有效果的。

 

七,mixin混入

遇到组件script部分有重复的地方的时候写这个(这个部分是后来再次看的,真不知道当时学了个什么)

app.vue


<template>

<!-- 模板文档只能有一个容器 -->
 <div>
   <h1 ref="text">真TMD服了!!!</h1>
   <MyName name="王鼎舒"></MyName>
   <button @click="showMe">点我输出test的节点</button>
 </div>
</template>

<script>
import MyName from "./components/MyName.vue";

import {a} from '../minix.js'

export default {
 name: "App",
 components: {
   MyName,
},
mixins:[a]
};
</script>


minix.js (创建文件的时候打错字了)


export const a = {methods: {
   showMe(){
     console.log(this.$refs.text)
  }
}
}

 

八,ToDoList案例

1.组件化编码流程(通用)

1.实现静态组件:抽取组件,使用组件实现静态页面的效果

2.展示动态数据

​ 2.1数据的类型、名称是什么。

​ 2.2数据保存在那个组件。

3.交互-从绑定事件开始

2.代码部分

header.vue


<template>
<div class="todo-header">
  <input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
</div>
</template>

<script>
import {nanoid} from 'nanoid'
export default {
 name: "MyHeader",
 methods:{
   add(e){
     if(!e.target.value) return alert("不能输入空值")
     
     const todoobj = {id:nanoid(),title:e.target.value,completed:false}
    //将用户的输入包装成为一个对象
     this.receive(todoobj)
     e.target.value=''
  }
},
 props:["receive","todos"]
};
</script>

<style scoped>
.todo-header input {
 width: 560px;
 height: 28px;
 font-size: 14px;
 border: 1px solid #ccc;
 border-radius: 4px;
 padding: 4px 7px;
}

.todo-header input:focus {
 outline: none;
 border-color: rgba(82, 168, 236, 0.8);
 box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}


</style>

footer.vue


<template>
<div class="todo-footer">
  <label>
    <input type="checkbox" :checked="isAll" @change="checkAll"/>
  </label>
  <span>
    <span>已完成{{todoDone}}</span> / 全部{{todos.length}}
  </span>
  <button class="btn btn-danger" @click="deleteAll">清除已完成任务</button>
</div>
</template>

<script>
export default {
 name: "MyFooter",
 computed: {
   total(){
     return  this.todos.length
  },

   todoDone() {
     return this.todos.reduce((pre,todo)=> pre + (todo.completed ? 1 : 0),0)
   
  },

   isAll(){
     return this.todoDone === this.total && this.todoDone >0
  }
},
 methods:{
   checkAll(e){
     this.checkAllTodo(e.target.checked)
  },

   deleteAll(){
     this.clearAlltodo()
  }
},
props: ["todos","checkAllTodo","clearAlltodo"],
};
</script>

<style scoped>
/*footer*/
.todo-footer {
 height: 40px;
 line-height: 40px;
 padding-left: 6px;
 margin-top: 5px;
}

.todo-footer label {
 display: inline-block;
 margin-right: 20px;
 cursor: pointer;
}

.todo-footer label input {
 position: relative;
 top: -1px;
 vertical-align: middle;
 margin-right: 5px;
}

.todo-footer button {
 float: right;
 margin-top: 5px;
}
</style>

list.vue


<template>
<ul class="todo-main">
  <MyItem
     v-for="todoobj in todos"
    :key="todoobj.id"
    :todo="todoobj"
    :checkTodo="checkTodo"
    :deletetodo="deletetodo"></MyItem>
</ul>
</template>

<script>
import MyItem from "./MyItem.vue";
export default {
 name: "MyList",
 components: {
   MyItem,
},
 props:["todos","checkTodo","deletetodo"],
 methods:{
 
}
};
</script>

<style scoped>
/*main*/
.todo-main {
 margin-left: 0px;
 border: 1px solid #ddd;
 border-radius: 2px;
 padding: 0px;
}

.todo-empty {
 height: 40px;
 line-height: 40px;
 border: 1px solid #ddd;
 border-radius: 2px;
 padding-left: 5px;
 margin-top: 10px;
}
</style>

item.vue

<template>
  <li>
    <label>
      <input type="checkbox" :checked="todo.completed" @change="handleCheck(todo.id)"/>
      <span>{{todo.title}}</span>
    </label>
    <button class="btn btn-danger" @click="removetodo(todo.id)">删除</button>
  </li>
</template>

<script>
export default {
name: "MyItem",
props:["todo","checkTodo","deletetodo"],
methods:{
handleCheck(id){

  this.checkTodo(id)
},

removetodo(id){
  if(confirm("你确定吗?")){
    this.deletetodo(id)
  }
}

}
};
</script>

<style scoped>
/item/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}

li label {
float: left;
cursor: pointer;
}

li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}

li button {
float: right;
display: none;
margin-top: 3px;
}

li:before {
content: initial;
}

li:last-child {
border-bottom: none;
}

li:hover{
background-color: #ddd;
}

li:hover button{
display: block;
}
</style>


app.vue

<template>
 <div id="root">
   <div class="todo-container">
     <div class="todo-wrap">
       <MyHeader :receive="receive"></MyHeader>
       <MyList :todos="todolist" :checkTodo="checkTodo" :deletetodo="deletetodo"></MyList>
       <MyFooter :clearAlltodo="clearAlltodo"  :todos="todolist" :checkAllTodo="checkAllTodo"></MyFooter>
     </div>
   </div>
 </div>
</template>

<script>
import MyHeader from "./components/MyHeader.vue";
import MyFooter from "./components/MyFooter.vue";
import MyList from "./components/MyList.vue";

export default {
 name: "App",
 components: {
   MyHeader,
   MyFooter,
   MyList,
},
 data(){
   return{
     todolist:[
      {id:'001',title:'唱',completed:true},
      {id:'002',title:'跳',completed:false},
      {id:'003',title:'rap',completed:true},
      {id:'004',title:'篮球',completed:true}
    ]
  }
},
 methods:{
   receive(x){
   
    this.todolist.unshift(x)
  },


   checkTodo(id){
     this.todolist.forEach((todo) => {
       if(todo.id === id) todo.completed = !todo.completed
    });

  },

   deletetodo(id){
     this.todolist = this.todolist.filter((todo) =>{
       return todo.id !== id
    });
  },

   checkAllTodo(completed){
     this.todolist.forEach((todo)=>{
       todo.completed = completed
    })
  },

   clearAlltodo(){
     this.todolist = this.todolist.filter((todo)=>{
       return !todo.completed
    })
  }
}
};
</script>

<style>s
body {
 background: #fff;
}

.btn {
 display: inline-block;
 padding: 4px 12px;
 margin-bottom: 0;
 font-size: 14px;
 line-height: 20px;
 text-align: center;
 vertical-align: middle;
 cursor: pointer;
 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),
   0 1px 2px rgba(0, 0, 0, 0.05);
 border-radius: 4px;
}

.btn-danger {
 color: #fff;
 background-color: #da4f49;
 border: 1px solid #bd362f;
}

.btn-danger:hover {
 color: #fff;
 background-color: #bd362f;
}

.btn:focus {
 outline: none;
}

.todo-container {
 width: 600px;
 margin: 0 auto;
}
.todo-container .todo-wrap {
 padding: 10px;
 border: 1px solid #ddd;
 border-radius: 5px;
}


</style>

3.总结部分

九,组件自定义事件

1.绑定

用来从子类向父类传递值

方法:

  1. 通过父组件给子组件传递函数的类型的props实现,子给父传递数据

    2.通过父组件给子组件一个自定义事件实现,子给父传递数据

1.通过绑定@或者v-on事件

2.通过使用ref

app.vue


<template>
<div>
  <SchoolInfo :getschoolname="getschoolname" v-on:wwds="demo2"></SchoolInfo>
   
   
  <!-- <StudentInfo v-on:wds="demo"></StudentInfo> -->
   
   
  <StudentInfo ref="student"></StudentInfo>
</div>
</template>

<script>

import SchoolInfo from './components/school.vue'
import StudentInfo from './components/student.vue'

export default {
   name:'App',

   template:'<app></app>',

   components:{

       SchoolInfo,
       StudentInfo

  }
,
   methods:{
       getschoolname(x){
           console.log(x)
      },
       demo(name){
           console.log("demo事件触发",name)
      },
       demo2(name){
           console.log(name)
      }
  },

   mounted(){
       setTimeout(()=>{this.$refs.student.$on('wds',this.demo)},3000)

  }
}
</script>

student.vue


<template>
  <div class="demo2">
      <h2>学生名称:{{ name }}</h2>
      <h2>学生年龄:{{ age }}</h2>
        <button @click="sendstudentname">把学生姓名给APP</button>
  </div>
</template>

<script>
export default {

   name:"studentInfo",
   
   
   data(){
       return{
           name:"王鼎舒",
           age:"21"
      }
  },

   methods:{

       sendstudentname(){
          //触发student组件身上的事件
           this.$emit('wds',this.name)
      }
  }
}
</script>

<style>

.demo2{
   background-color: blue;
}

</style>

school.vue


<template>
  <!-- 组件的结构 -->
  <div class="demo">
      <h2>学校名称:{{ name }}</h2>
      <h2>学校地址:{{ address }}</h2>
      <button @click="sendschoolname">把学校姓名给APP</button>
        <button @click="sendschooladdress">把学校地址给APP</button>
  </div>
</template>

<script>

// 组件交互的相关代码
   export default {
   name:'SchoolInfo',
   data() {
       return {
           name: "山西农业大学",
           address: "太谷",
      }
  },
   props:["getschoolname"],
   methods:{
       sendschoolname(){
          this.getschoolname(this.name)
      },
       sendschooladdress(){
           this.$emit('wwds',this.address)
      }
  }
   

}

</script>

<style>
/* 组件的样式 */
.demo {
   background-color: orange;
}
</style>

<!-- const school = Vue.extend({
   template:`<div>
      <h2>学校名称:{{name}}</h2>
      <h2>学校地址:{{address}}</h2>
      <student></student>
      </div>`,

       data(){
           return{
               name:"山西农业大学",
               address:"太谷",
          }
      },
       components:{
           student
      }

     
}) -->

2.解绑


<template>
  <div class="demo2">
      <h2>学生名称:{{ name }}</h2>
      <h2>学生年龄:{{ age }}</h2>
        <button @click="sendstudentname">把学生姓名给APP</button>
        <button @click="unbind">解绑事件</button>
        <button @click="death">销毁事件</button>
  </div>
</template>

<script>
export default {

   name:"studentInfo",
   
   
   data(){
       return{
           name:"王鼎舒",
           age:"21"
      }
  },

   methods:{

       sendstudentname(){
          //触发student组件身上的事件
           this.$emit('wds',this.name)
      },
       unbind(){

          // //单词解绑
           this.$off('wds')

          //解绑多个自定义事件
          // this.$off(['wds','aaa'])

          //最终极端解绑(所有全解绑)
          // this.$off()
      },
       death(){
           this.$destroy()
      }
  }
}
</script>

<style>

.demo2{
   background-color: blue;
}

</style>

3.总结

总的来说:父传子 props

​ 子传父 $emit( event , val)

十,全局事件总线

任意组件间的通信(视频开局说比较重要,之后却不用,不明白,而且时间的名字不能重复,麻烦)

1.首先main.js安装全局事件总线


import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
 render: h => h(App),

 beforeCreate(){
   Vue.prototype.$bus = this
}
}).$mount('#app')

2.school.vue


<template>
   <!-- 组件的结构 -->
   <div class="demo">
       <h2>学校名称:{{ name }}</h2>
       <h2>学校地址:{{ address }}</h2>
   </div>
</template>

<script>

// 组件交互的相关代码
   export default {
   name:'SchoolInfo',
   data() {
       return {
           name: "山西农业大学",
           address: "太谷",
      }
  },

   methods:{
       demo(data){
           console.log("school接收到了student的参数",data)
      }
  },

   mounted(){
       this.$bus.$on('demo',this.demo)
  },

   beforeDestory(){
       this.$bus.$off('demo')
  }

  }

   


</script>

<style>
/* 组件的样式 */
.demo {
   background-color: orange;
}
</style>

2.school.vue


<template>
   <div class="demo2">
       <h2>学生名称:{{ name }}</h2>
       <h2>学生年龄:{{ age }}</h2>
       <button @click="sendstudentname">向school里传递name</button>
   </div>
</template>

<script>
export default {

   name:"studentInfo",
   
   
   data(){
       return{
           name:"王鼎舒",
           age:"21"
      }
  },

  methods:{
   sendstudentname(){
       this.$bus.$emit('demo',this.name)
  }
  }

}
</script>

<style>

.demo2{
   background-color: blue;
}

</style>

十一,$nextTick

实现点击编辑后自动获取文本框焦点


<template>
<li>
  <label>
    <input type="checkbox" :checked="todo.completed" @change="handleCheck(todo.id)"/>
    <span v-show="!todo.isEdit">{{todo.title}}</span>
    <input type="text"
             ref="abc"
            :value="todo.title"
             v-show="todo.isEdit"
             @blur="handleBlur(todo,$event)">
  </label>
  <button class="btn btn-danger" @click="removetodo(todo.id)">删除</button>
  <button class="btn btn-edit"  @click="handleEdit(todo)">编辑</button>
</li>
</template>

<script>
export default {
 name: "MyItem",
 props:["todo"],
 methods:{
   handleCheck(id){

     this.$bus.$emit('checkTodo',id)
  },

   removetodo(id){
     if(confirm("你确定吗?")){
       this.$bus.$emit('deletetodo',id)
    }
  },

   handleEdit(todo){

     
        this.$set(todo,'isEdit',true)
      //这行代码不会被执行是因为,在上一行代码走完之后
      //会执行下一行代码,但是此时页面还没有渲染focus不能渲染没有出现的input框
       
       
        //在下一次DOM更新结束后,执行回调
        this.$nextTick(function(){
           this.$refs.abc.focus()
        })
  },
//失去焦点回调(真正执行修改逻辑)
   handleBlur(todo,event){
     this.$set(todo,'isEdit',false)
    //这行是我自己写的。。。
    // this.todo.title = t his.$refs.abc.value
     this.$bus.$emit('updataTodo',todo.id,event.target.value)
  }

}
};
</script>

<style scoped>
/*item*/
li {
 list-style: none;
 height: 36px;
 line-height: 36px;
 padding: 0 5px;
 border-bottom: 1px solid #ddd;
}

li label {
 float: left;
 cursor: pointer;
}

li label li input {
 vertical-align: middle;
 margin-right: 6px;
 position: relative;
 top: -1px;
}

li button {
 float: right;
 display: none;
 margin-top: 3px;
}

li:before {
 content: initial;
}

li:last-child {
 border-bottom: none;
}

li:hover{
 background-color: #ddd;
}

li:hover button{
 display: block;
}
</style>

十二,过渡与动画

1,动画配置


<template>
<div>
   
  <button @click="abc = !abc" >点击隐藏/显示</button>
 
  <!-- 浏览器不认识transition标签,这个标签是给vue用的* -->
  <transition name="wds" appear>
    <h1 v-show="abc" >大家好</h1>
  </transition>
</div>
</template>

<script>
export default {
 name: "Mytest",
 data() {
   return {
     abc: true,
  };
},
};
</script>

<style>
h1 {
 background-color: orange;
}

.wds-enter-active {
 animation: test 2s;
}

.wds-leave-active {
 animation: test 2s reverse;
}

@keyframes test {
 from {
   transform: translateX(-100%);
}
 to {
   transform: translateX(0);
}
}
</style>

2,过度效果

个人感觉没啥用啊(个人)


<template>
<div>
   
  <button @click="abc = !abc" >点击隐藏/显示</button>
 
  <!-- 浏览器不认识transition标签,这个标签是给vue用的* -->
  <transition name="wds" appear>
    <h1 v-show="abc" >大家好</h1>
  </transition>
</div>
</template>

<script>
export default {
 name: "Mytest",
 data() {
   return {
     abc: true,
  };
},
};
</script>

<style>
h1 {
 background-color: orange;
 transition: 0.5s;
}

/* 进入的起点 */
.wds-enter{
 transform: translateX(-100%);
}
/* 进入的终点 */
.wds-enter-to{
 transform: translateX(0);
}

/* 进入的起点 */
.wds-leave{
 transform: translateX(0);
}
/* 进入的终点 */
.wds-leave-to{
 transform: translateX(-100%);
}
/* @keyframes test {
from {
  transform: translateX(-100%);
}
to {
  transform: translateX(0);
} */
/* } */
</style>

3,多个元素过度

transiton 只能使用单元素

transiton-group 可以使用多个元素,并且每个元素必须配置key值

4,集成第三方库

怎么说。。非常好用!!!


<template>
<div>
    <button @click="abc = !abc" >点击隐藏/显示</button>
  <transition name="animate__animated animate__bounce"
               appear
               enter-active-class="animate__wobble"
               leave-active-class="animate__wobble"
              >
 
    <h1 v-show="abc" >大家好</h1>
  </transition>
</div>
</template>

<script>

import 'animate.css'

export default {
 name: "Mytest2",
 data() {
   return {
     abc: true,
  };
},
};
</script>

<style>
h1 {
 background-color: orange;
 transition: 0.5s;
}


</style>

十三,插件

作用:增强vue

安装插件后,import导入之后通过Vue.use()调用

四,vue中的AJAX

比较了各种AJAX的方式,xhr,jQuery,fetch,综合考虑都不好,直接就G了,xhr学过,fetch了解过,jQuery听说过,结果最后表示要用axios。。。点个海克斯“考前恶补”。

1.配置代理


<template>
 <div>
   <button @click="getstudents">获取学生信息</button>
</div>
</template>

<script>


import axios from 'axios'

export default {
   name:'App',
   methods:{
       getstudents(){
       axios.request(' http://localhost:3000/students').then(response=>{
           console.log('请求成功',response.data)
      }),
       error=>{
           console.log('请求失败',error.message)
      }
      }
  }



}
</script>

2.github请求案例

MyList.vue


<template>
  <div class="row">
    <div v-show="users.length" class="card" v-for="user in userList" :key="user.id">
      <a :href="user.html_url" target="_blank">
        <img :src="user.avatar_url" style='width: 100px'/>
      </a>
      <p class="card-text">{{user.login}}</p>
    </div>
    <!-- 展示欢迎词 -->
    <h1 v-show="isFirst">欢迎使用</h1>
    <!-- 展示加载中 -->
    <h1 v-show="isLoding">loding......</h1>
    <!-- 展示错误信息 -->
    <h1 v-show="errorMsg">找不到页面啊,出错了{{errorMsg}}</h1>
  </div>
</template>

<script>  
export default {
 name: "MyList",
 data(){
   return {
     isFirst:true,
     isLoding:false,
     errorMsg:'',
     userList:[]
     
  }
},
 mounted(){
   this.$bus.$on('getusers',(users,isFirst,isLoding,errorMsg)=>{
       console.log("我是list组件,收到数据",users)
       this.isFirst = isFirst
       this.isLoding = isLoding
       this.errorMsg = errorMsg
       
       
       this.userList = users
  })
}
};
</script>

<style>
.album {
 min-height: 50rem; /* Can be removed; just added for demo purposes */
 padding-top: 3rem;
 padding-bottom: 3rem;
 background-color: #f7f7f7;
}

.card {
 float: left;
 width: 33.333%;
 padding: 0.75rem;
 margin-bottom: 2rem;
 border: 1px solid #efefef;
 text-align: center;
}

.card > img {
 margin-bottom: 0.75rem;
 border-radius: 100px;
}

.card-text {
 font-size: 85%;
}
</style>

Search.vue


<template>
  <section class="jumbotron">
    <h3 class="jumbotron-heading">Search Github Users</h3>
    <div>
      <input type="text" placeholder="enter the name you search" v-model="keyWord">&nbsp;
      <button @click="SearchUsers">Search</button>
    </div>
  </section>
</template>

<script>

import axios from 'axios'
export default {
   name:'Search',
   data(){
     return {
       keyWord:""
    }
  },
   methods:{
     SearchUsers(){
       axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
         response =>{
           console.log("请求成功",response.data)
           this.$bus.$emit('getusers',response.data.items)
        },
         error =>{
           console.log("请求失败",error.message)
        })
    }
  }
}
</script>

<style>

</style>

3,插槽

1.默认插槽

相当于在页面组件挖个坑,在app组件的组件标签里写html标签,由于解析完app后才会传送到其他页面,可以将html标签的样式写在app组件里。

slot标签

Mylist.vue


<template>
<div>
  <h1>{{title}}</h1>
  <slot></slot>
</div>
</template>

<script>
export default {
   name:"MyList",
   props:['title' ]

}
</script>

<style scoped>
   div{
       width: 200px;
       height: 300px;
       background-image: linear-gradient(#A0F99E,#46ADD5);
  }
   h1{
       text-align: center;
       background-color:orange;
       
  }
   ul{
       list-style: none;
  }
</style>

app.vue


<template>
<div class="container">
  <MyList title="美食" >
    <ul>
      <li v-for="(demo, index) in foods" :key="index">{{ demo }}</li>
    </ul>
  </MyList>
  <MyList title="游戏" >
    <ul>
      <li v-for="(demo, index) in games" :key="index">{{ demo }}</li>
    </ul></MyList>
  <MyList title="爱好" >
    <img src="./assets/logo.png" alt="">
  </MyList>
</div>
</template>

<script>
import MyList from "./components/Mylist.vue";
export default {
 name: "App",
 components: {
   MyList,
},
 data() {
   return {
     foods: ["apple", "pear", "banana"],
     hobbies: ["抽烟", "喝酒", "烫头"],
     games: ["王者荣耀", "刺激战场", "LOL"],
  };
},
};
</script>

<style>
.container {
 display: flex;
 justify-content: space-around;
}
</style>

2.具名插槽

app.vue


<template>
<div class="container">
  <MyList title="美食" >
    <ul slot="center">
      <li v-for="(demo, index) in foods" :key="index">{{ demo }}</li>
    </ul>
    <a  href="http://www.4399.com">点击获取更多游戏</a>
  </MyList>
  <MyList title="游戏" >
    <ul>
      <li v-for="(demo, index) in games" :key="index">{{ demo }}</li>
    </ul></MyList>x
  <MyList title="爱好" >
    <img src="./assets/logo.png" alt="">
  </MyList>
</div>
</template>

list.vue


<template>
<div>
  <h1>{{title}}</h1>
  <slot name="center"></slot>
  <slot name="footer"></slot>
</div>
</template>

有一种新的写法,v-slot:demo

但是这种写法只能用在template标签中

3.作用域插槽

mylist.vue


<template>
<div>
  <slot :games="games"></slot>
</div>
</template>

<script>
export default {
 name: "MyList",
 data() {
   return {
     games: ["王者荣耀", "和平经营", "老铁666"],
  };
},
};
</script>

<style>
</style>

app.vue


<template>
<div>
  <MyList>
    <template scope="wds">
      <ul>
        <li v-for="(w, index) in wds.games" :key="index">{{ w }}</li>
      </ul>
    </template>
  </MyList>
  <MyList>
    <template scope="wds2">
      <ol>
        <li v-for="(w, index) in wds2.games" :key="index">{{ w }}</li>
      </ol>
    </template>
  </MyList>
  <MyList>
    <template scope="wds3">
        <h4 v-for="(w, index) in wds3.games" :key="index">{{ w }}</h4>
    </template>
  </MyList>
</div>
</template>

<script>
import MyList from "./components/Mylist.vue";
export default {
 name: "App",
 components: {
   MyList,
},
};
</script>

<style>
</style>

作用域插槽怎么说,他是要发送的地方挖个坑,对应使用的地方要根据不同的需求而变换的时候,使用这个作用域插槽,重要但是很少用到

4.总结

五,vuex

1,vuex简介

专门在vue中实现集中式状态(数据)管理的一个vue插件,对vue应用中多个组件的共享状态进行集中的管理(读/写),也是一种中间件通信方式,且适用于组件间的通信。

什么时候使用vuex

​ 1.多个组件依赖于同一状态

​ 2.来自不同组件的行为需要变更同一状态。

2,求和案例


<template>
 <div>
   <h1>当前的数值为:{{ num }}</h1>
   <select v-model="n">
     <option :value="1">1</option>
     <option :value="2">2</option>
     <option :value="3">3</option>
   </select>
   <button @click="jia">+</button>
   <button @click="jian">-</button>
   <button @click="jishujia">当前和为奇数再加</button>
   <button @click="dengdengjia">等一等再加</button>
 </div>
</template>

<script>
export default {
 name: "MyTest",
 data() {
   return {
     n: 1,
     num: 0,
  };
},
 methods: {
   jia() {
     this.num += this.n;
  },
   jian() {
     this.num -= this.n;
  },
   jishujia() {
     if (this.num % 2) {
       this.num += this.n;
    }
  },
   dengdengjia() {
     setTimeout(() => {
       this.num += this.n;
    }, 3000);
  },
},
};
</script>

<style  scoped>
div {
 display: flex;
 justify-content: space-between;
}
</style>

3,vuex的工作原理

直接用人家的图吧Vuex 是什么? | Vuex (vuejs.org)

自己只能大概理解逻辑但是解释的不是很好,图上少了一个仓库,vuex中的三个组成action,mulation,

states这三兄弟需要受到store的管理。


真的服了,回头看看笔记都不知道之前是学了个啥?

这么直说吧,vuex的配置中有三个部分,state,mutation,action,一共是三个,这里说一下,这三个兄弟都是对象,这三兄弟state是用来存储数据的,可以直接放数据,相当于仓库,其次就是action了,action的作用相当于索引,对我而言本身就是一个传递数据的作用,直接来看代码:


methods(){
   XXX(){
       this.$store.dispatch('方法名',参数)
  }
}

action:{
   //a和b,知识定义形参的时候写的,普遍的写法应该是,context和value
   a:function(a,b){
       console.log(a,b)
       //这里的方法名使用大写
       a.commit('方法名',b)
  }
}

这里比较复杂,就不再代码中写注释了,直接来讲,a是相当于起一个上下文的作用,里面包含了部分store的方法和属性,这里很抽象,怎么说就是我要从上文获取一些东西,这些东西里面有dispatch传递过来的数据,有后面会讲到的getter,还有要vuex中state中的参数,这么多的东西是要干什么呢,是用来传递给之后的mutation方法中的,总的来说它就是起一个连接的作用,如果觉得麻烦,其实是可以跳过这一步的,但是这些都是后话了。再说说这个b,这个b就是通过组件中的dispatch传过来的参数,dispatch传递的东西有两个,一个是方法名,还有一个是需要传递的参数,重要的是这个a中,有一个方法是commit方法,这个方法向mutation中传递方法,携带的参数分别是方法名和参数值。


mutation:{
   //这里又有两个参数,a是指state,b指的是之前的参数,
   '方法名'(a,b){
       //然后进行对state的操作
  }
}

最后在页面如果需要使用state中的参数就是插值的问题了,多种写法任你挑选,这里介绍两种常见的

  1. {{¥store.state.XXX}}

  2. 在computed计算属性中写

4,搭建vuex的环境

npm i vuex@3

安装完成之后在src下创建store文件夹创建index文件(这里我不是这样创建的,这是不规范的 ,我们应该按照官方的来)

store.js


import Vue from 'vue'

//引入vuex
import Vuex from 'vuex'

Vue.use(Vuex)
//创建actions-用于相应组件中的动作
const actions = {}
//创建mutations-用于操作数据(state)
const mutations = {}
//创建state-用于数据存取
const state = {}

//创建并且暴露store
export default new Vuex.Store({
   actions,
   mutations,
   state
})

main.js


import Vue from 'vue'
import App from './App.vue'


import store from './vuex/store'

Vue.config.productionTip = false



const vm = new Vue({

 store,
 render: h => h(App),
}).$mount('#app')

console.log(vm)

由于import在脚手架里总是先运行,非常离谱,只能将vuex导入到store.js中。

ps\

在模板里不用写this,能直接看到vc身上的东西。

mytest.vue


<template>
 <div>
   <h1>当前的数值为:{{$store.state.sum}}</h1>
   <select v-model="n">
     <option :value="1">1</option>
     <option :value="2">2</option>
     <option :value="3">3</option>
   </select>
   <button @click="jia">+</button>
   <button @click="jian">-</button>
   <button @click="jishujia">当前和为奇数再加</button>
   <button @click="dengdengjia">等一等再加</button>
 </div>
</template>

<script>
export default {
 name: "MyTest",
 data() {
   return {
     n: 1,
  };
},
 methods: {
   jia() {
     this.$store.commit("jia", this.n);
     console.log(this.$store.dispatch)
  },
   jian() {
     this.$store.dispatch('jian',this.n)
  },
   jishujia() {
     if(this.$store.state.sum % 2 ){
     this.$store.dispatch('jishujia',this.n)}
  },
   dengdengjia() {
     setTimeout(() => {
       this.$store.dispatch('deng',this.n)
    }, 3000);
  },
},
};
</script>


store.js


import Vue from 'vue'

//引入vuex
import Vuex from 'vuex'

Vue.use(Vuex)
//创建actions-用于相应组件中的动作
const actions = {
   // jia(context,value){
   //     console.log('666 action中的加被调用了',context,value)
   //     context.commit('jia',value)
   // },
   jian(context,value){
       context.commit('jian',value)
  },
   jishujia(context,value){
      context.commit('jia',value)
  },
   deng(a,b){
       a.commit('deng',b)
  }
}
//创建mutations-用于操作数据(state)
const mutations = {
   jia(state,value){
       console.log('mutations的jia被调用',state,value)
       state.sum += value
       console.log(state.sum)
  },
   jian(state,value){
       state.sum -= value
  },

   deng(a,b){
       a.sum += b
  }
}
//创建state-用于数据存取
const state = {
   sum:0
}

//创建并且暴露store
export default new Vuex.Store({
   actions,
   mutations,
   state
})

5,vuex开发者工具

打开vue开发者工具,点击上方从左往右第二个图标进入vuex开发者工具。

6,getters配置对象

为什么不能用计算属性代替呢?因为计算属性不能跨组件执行。


getters只要用途就是加工state数据用的

mytest.vue


<template>
 <div>
   <h1>当前的数值为:{{$store.state.sum}}</h1>
    <h1>当前的数值扩大十倍为:{{$store.getters.bigsun}}</h1>
   <select v-model="n">
     <option :value="1">1</option>
     <option :value="2">2</option>
     <option :value="3">3</option>
   </select>
   <button @click="jia">+</button>
   <button @click="jian">-</button>
   <button @click="jishujia">当前和为奇数再加</button>
   <button @click="dengdengjia">等一等再加</button>
 </div>
</template>

<script>
export default {
 name: "MyTest",
 data() {
   return {
     n: 1,
  };
},
 methods: {
   jia() {
     this.$store.commit("jia", this.n);
     console.log(this.$store.dispatch)
  },
   jian() {
     this.$store.dispatch('jian',this.n)
  },
   jishujia() {
     if(this.$store.state.sum % 2 ){
     this.$store.dispatch('jishujia',this.n)}
  },
   dengdengjia() {
     setTimeout(() => {
       this.$store.dispatch('deng',this.n)
    }, 3000);
  },
},
};
</script>


store.js


import Vue from 'vue'

//引入vuex
import Vuex from 'vuex'

Vue.use(Vuex)
//创建actions-用于相应组件中的动作
const actions = {
   // jia(context,value){
   //     console.log('666 action中的加被调用了',context,value)
   //     context.commit('jia',value)
   // },
   jian(context,value){
       context.commit('jian',value)
  },
   jishujia(context,value){
      context.commit('jia',value)
  },
   deng(a,b){
       a.commit('deng',b)
  }
}
//创建mutations-用于操作数据(state)
const mutations = {
   jia(state,value){
       console.log('mutations的jia被调用',state,value)
       state.sum += value
       console.log(state.sum)
  },
   jian(state,value){
       state.sum -= value
  },

   deng(a,b){
       a.sum += b
  }
}
//创建state-用于数据存取
const state = {
   sum:0
}

const getters= {
   bigsun(state){
       return state.sum*10
  }
}

//创建并且暴露store
export default new Vuex.Store({
   actions,
   mutations,
   state,
   getters
})

7,mapState和mapGetters

为什么要用mapState,当我们直接通过插值语法插入vuex中state的数据的时候,是否存在一直写$store.state的烦恼,没关系解决方法他来了,使用mapState,其本质是帮助我们生成计算属性的代码,用官方的话来说就是帮助我们映射state中的数据为计算属性。

使用之前先导入import {mapState} from 'vuex'

mapState有两种写法:


//对象写法
...mapState({XXX:"xxx"})//X是对象名,即计算属性方法名,x即获取state中的数据名
//数组写法
...mapState(['xxx'])//这里表示的x,是指生成的计算属性方法名和states中的数据名一致的时候,使用这种写法

那么至于getters那就是一个道理了,毕竟getters的本质就是将states加工一下mapGetters


<template>
 <div>
   <h1>当前的数值为:{{sum}}</h1>
    <h1>当前的数值扩大十倍为:{{shibei}}</h1>
    <p>学校:{{school}},专业:{{$store.state.subject}}</p>
   <select v-model="n">
     <option :value="1">1</option>
     <option :value="2">2</option>
     <option :value="3">3</option>
   </select>
   <button @click="jia">+</button>
   <button @click="jian">-</button>
   <button @click="jishujia">当前和为奇数再加</button>
   <button @click="dengdengjia">等一等再加</button>
 </div>
</template>

<script>
import {mapState} from 'vuex'
import {mapGetters} from 'vuex'
export default {
 name: "MyTest",
 data() {
   return {
     n: 1,
  };
},
 methods: {
   jia() {
     this.$store.commit("jia", this.n);
  },
   jian() {
     this.$store.dispatch('jian',this.n)
  },
   jishujia() {
     if(this.$store.state.sum % 2 ){
     this.$store.dispatch('jishujia',this.n)}
  },
   dengdengjia() {
     setTimeout(() => {
       this.$store.dispatch('deng',this.n)
    }, 3000);
  },  
},
 computed:{
   // sum(){
   //   return this.$store.state.sum
   // }
   // school(){
   //   return this.$store.state.school
   // },
   //以下代码代替上面的代码(ES6)

   // ...mapState({sum:'sum',school:'school'}),
   //上面的代码可以简写成以下的形式
   ...mapState(['sum','school']),
   ...mapGetters({shibei:'bigsun'})

},
 mounted(){
}
};
</script>

八,mapActions和mapMutations

和上面同理,唯一和上面不一样的地方,就是传递参数的额时候比较麻烦(这里终于知道vue为什么不用做大型项目了,太混乱了)

这里mapMutations为例子


//对象写法
...mapMutations({XXX:"XXX"})//X(前)是方法名,X(后)即获取mutation中的方法名,这里的X为什么大写,因为这里是mutation,因该采用小驼峰写法。
//数组写法
...mapMutationse(['XXX'])

但是到了这里的时候我们发现,没有办法传递参数了,

于是我们在插值语法中传递参数,例如{{XXX(x)}},至于actions是一致的,不过多赘述。

九,多组件共享数据

结合起来,将一个state的数据多个组件都在使用,实现数据共享

这里我新写了一个组件,用来记录生成的爱好,并且在求和的组件中添加数组的长度。


<template>
 <div class="box">
  在此处添加爱好:<input type="text" v-model="hobby" /><button
     @click="submit"
   >
    提交
   </button>
   <ul>
     <li v-for="h in hobbyList" :key="h.id">{{ h.hobby }}</li>
   </ul>
 </div>
</template>

<script>
export default {
 name: "MyHobby",
 data() {
   return {
     hobby: "",
  };
},
 methods: {
   submit() {
     this.$store.commit("Submit", this.hobby);
     this.hobby = ""
  },
},
 computed: {
   hobbyList() {
     return this.$store.state.hobbylist;
  },
},
};
</script>

const mutations = {

   Submit(state,value){
       
       const newhobby = {id:nanoid(),hobby:value};
       console.log(value)
       state.hobbylist.unshift(newhobby);
  }
}
//创建state-用于数据存取
const state = {

   hobbylist:[
      {id:1,hobby:'抽烟'}
  ]
}

这里我就不写了,页面添加信息的方法我就不在写了。

十,vuex模块化

这就很离谱了

vue组件

<template>
 <div>
   <h1>当前的数值为:{{sum}}</h1>
    <h1>当前的数值扩大十倍为:{{shibei}}</h1>
    <p>学校:{{school}},专业:{{subject}},爱好总数:{{hobbylist.length}}</p>
   <select v-model="n">
     <option :value="1">1</option>
     <option :value="2">2</option>
     <option :value="3">3</option>
   </select>
   <button @click="jia(n)">+</button>
   <button @click="jian(n)">-</button>
   <button @click="jishujia(n)">当前和为奇数再加</button>
   <button @click="dengdengjia(n)">等一等再加</button>
 </div>
</template>

<script>
import {mapState} from 'vuex'
import {mapGetters} from 'vuex'
import {mapMutations,mapActions} from 'vuex'
export default {
 name: "MyTest",
 data() {
   return {
     n: 1,
  };
},
 methods: {

       ...mapMutations('b',{jia:"jia"}),
       ...mapActions('b',["jian","jishujia","dengdengjia"]),


},
 computed:{

   ...mapState('b',['sum','school','subject']),
   ...mapState('a',['hobbylist']),
   ...mapGetters('b',{shibei:'bigsun'}),
},
 mounted(){
   console.log(this.$store)
}
};
</script>


store.js

import Vue from 'vue'

import Vuex from 'vuex'

import { nanoid } from 'nanoid'

Vue.use(Vuex)

const personoptions = {
   namespaced: true,
   actions: {},
   mutations: {
       Submit(state, value) {

           const newhobby = { id: nanoid(), hobby: value };
           console.log(value)
           state.hobbylist.unshift(newhobby);
      }
  },
   state: {
       hobbylist: [
          { id: 1, hobby: '抽烟' }
      ]
  },
   getters: {},
}

const numberoptions = {
   namespaced: true,
   actions: {
       jian(context, value) {
           context.commit('jian', value)
      },
       jishujia(context, value) {
           if (context.state.sum % 2) {
               context.commit('jia', value)
          }
      },
       dengdengjia(a, b) {
           setTimeout(() => {
               a.commit('jia', b)
          }, 3000);

      }
  },
   mutations: {
       jia(state, value) {
           state.sum += value
      },
       jian(state, value) {
           state.sum -= value
      },
  },


   state: {
       sum: 0,
       school: '山西农业大学',
       subject: '前端',
  },
   getters: {
       bigsun(state) {
           return state.sum * 10
      }
  },
}




export default new Vuex.Store({
   modules: {
       a: personoptions,
       b: numberoptions
  }
})

这里只列举部分代码

十一,vuex模块化二

目的:让代码模块化区分,数据分类明确

这里讲述了不使用map,纯手写如何组件化开发,store.js我就不重写了(一摸一样的和上面,真的别折磨我了)

//获取state的写法,就老老实实写
this.$store.state.对象名.
//但是获取getter里的值的时候,就有变化了
this.$store.getter['对象名/属性名']//这里的/不是隔开的意思,而是就得带上这个/
//commit和dispatch写法就一样了,和getter类似
this.$store.commit('对象名/方法名',值)
this.$store.dispatch('对象名/方法名',值)

同时我们可以将写好的store.js的各个模块分别打包模块化暴露,最后引入文件,真真做到了模块化开发

但是这些都不是本节最重要的重点

重点是vuex和ajax结合(当年这个给问题让我夜不能寐 。。。。却是如此简单)


actions={
   add(context){
       axios.get("#").then(response=>{
           context.commit('ADD',{name:"response.data.name",age:"response.data.age"})
      },err=>{
           console.log(err.message)
      } )
  }
}

 

六,路由

一,什么是路由

路由就是一组key value的对应。 route

多组路由集合为路由器

vue中使用库 vue-router 专门来实现SPA应用

  1. 单页web应用SPA

  2. 整个应用只有一个完整的页面

  3. 点击页面中的导航链接不会刷新页面,指挥做页面的局部更新

  4. 数据需要通过ajax请求获取

ps:这里说一下我在学习过程中一直以来遇到的问题

Component name "XXXXX" should always be multi-word vue/multi-word-component-names

这个问题让我痛不欲生,解决的方法就是在vue项目里package.js里的rules里写上下面的代码,并且重新启动服务器,真的绝了。

 "vue/multi-word-component-names": "off"

二,路由技术的基本使用

安装vue-router插件npm i vue-router@3

这里因为是使用vue2所以只能使用3版本,否则会报错

main.js


import Vue from 'vue'
import App from './App.vue'

import VueRouter from 'vue-router'
import router from './router/index'

Vue.use(VueRouter)


Vue.config.productionTip = false

new Vue({
 render: h => h(App),

 router:router
}).$mount('#app')

index.js


import VueRouter from "vue-router";
import About from '../components/About'
import Home from '../components/Home'
import Test from '../components/Test'


//创建一个路由器
export default new VueRouter({

   routes:[
      {
           path:'/about',
           //家人们我真的无语了,手抽把这个C写成大写了。真的绝了,他也不报错
           component:About
      },
      {
           path:'/home',
           component:Home
      },
      {
           path:'/test',
           component:Test
      }
  ],
   mode:'history'
})

App.vue


<template>
 <div>
   <div>
     <div class="row">
       <div class="col-xs-offset-2 col-xs-8">
         <div class="page-header"><h2>Vue Router Demo</h2></div>
       </div>
     </div>
     <div class="row">
       <div class="col-xs-2 col-xs-offset-2">
         <div class="list-group">
           <!-- <a class="list-group-item active" href="./about.html">About</a>
         <a class="list-group-item" href="./home.html">Home</a> -->
           <!-- 实现路由的切换 -->
           <router-link class="list-group-item" active-class="active" to="/about">About</router-link>
           <router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
            <router-link class="list-group-item" active-class="active" to="/test">Test</router-link>
         </div>
       </div>
       <div class="col-xs-6">
         <div class="panel">
           <div class="panel-body">
             <!-- 指定组件的展示位置 -->
             <router-view></router-view>

           </div>
         </div>
       </div>
     </div>
   </div>
 </div>
</template>

<script>
export default {
 name: "App",
 components: {},
};
</script>

<style>
</style>

About.vue


<template>
 <h2>我是About的内容</h2>
</template>

<script>
export default {
   name:'About',
      mounted(){
       console.log('beiyingyong ')
  }
}
</script>

<style>

</style>

Home.vue


<template>
  <h2>我是Home的内容</h2>
</template>

<script>
export default {
   name:'Home',
   mounted(){
       console.log('beiyingyong ')
  }
}
</script>

<style>

</style>

Test.vue


<template>
 <h2>这里是我自己写的Test页面</h2>
</template>

<script>
export default {
   name:'Test'
}
</script>

<style>

</style>

三,路由使用的注意事项

路由组件一般放在component文件下的pages文件夹里

四,路由的嵌套

home.vue


<template>
 <div>
   <h2>Home组件内容</h2>
   <div>
     <ul class="nav nav-tabs">
       <li>
         <router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
       </li>
       <li>
         <router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
       </li>
     </ul>
           <router-view></router-view>
   </div>
 </div>
</template>

<script>
export default {
 name: "Home",

};
</script>

<style>
</style>

message.vue


<template>
 <div>
   <ul>
     <li>news001</li>
     <li>news002</li>
     <li>news003</li>
   </ul>
 </div>
</template>

<script>
export default {
 name: "News",
};
</script>

<style>
</style>

news.vue


<template>
 <div>
   <ul>
     <li>news001</li>
     <li>news002</li>
     <li>news003</li>
   </ul>
 </div>
</template>

<script>
export default {
 name: "News",
};
</script>

<style>
</style>

index.js


import VueRouter from "vue-router";
import About from '../components/About'
import Home from '../components/Home'
import Test from '../components/Test'
import News from '../components/News'
import Message from '../components/Message'


//创建一个路由器
export default new VueRouter({

   routes:[
      {
           path:'/about',
           //家人们我真的无语了,手抽把这个C写成大写了。真的绝了,他也不报错
           component:About
      },
      {
           path:'/home',
           component:Home,
           children:[
              {
                   path:'news',
                   component:News
              },
              {
                   path:'message',
                   component:Message
              }
          ]
      },
      {
           path:'/test',
           component:Test
      }
  ],
   mode:'history'
})

在配置二级路由时,path里的值不能写斜杠

在组件中引入二级路由时,一定要添加上一级路由例如:/home/news

五,路由的query参数

可以通过query参数传递值

message.vue


<template>
 <div>
   <ul>
     <!-- 跳转路由携带参数to的字符串写法 -->
     <!-- <li v-for="n in messageList" :key="n.id"><router-link :to="`/home/message/detail?id=${n.id}&title=${n.title}`">{{n.title}}</router-link>&nbsp;&nbsp;</li> -->
     <!-- 跳转路由携带参数to的对象写法 -->
   <li v-for="n in messageList" :key="n.id">
     <router-link :to="{
     path:'/home/message/detail',
     query:{
       id:n.id,
       title:n.title
     }
   }
   ">{{n.title}}</router-link>&nbsp;&nbsp;</li>
   </ul>
   <router-view></router-view>
 </div>
</template>

<script>
export default {
 name: "Message",
 data() {
   return {
     messageList: [
      { id: "001", title: "消息一" },
      { id: "002", title: "消息二" },
      { id: "003", title: "消息三" },
    ],
  };
},
};
</script>

<style>
</style>

detail.vue


<template>
 <div>
  message:id{{$route.query.id}}<br>
  message:title{{$route.query.title}}
 </div>
</template>

<script>
export default {
   name:'Detail',
}
</script>

<style>

</style>

六,命名路由

只有在路由过长的时候,为了方便解决问题,在配置路由的时候添加名字。

就用上面的代码作为例子来解析一下

message.vue


<router-link :to="{
    name:'detail',
     query:{
       id:n.id,
       title:n.title
     }
   }
   ">{{n.title}}</router-link>

router/index.js


children:[
                      {
                           name:'detail',
                           path:'detail',
                           component:Detail
                      }
                  ]

路由嵌套较少的时候还是不要这么用比较好

七,路由的param参数

直接将要传递打的对象写道路由里,按理说是安全,但是个人感觉鸡肋

message.vue


     <!-- 跳转路由携带参数to的字符串写法 -->
     <!-- <li v-for="n in messageList" :key="n.id"><router-link :to="`/home/message/detail/${n.id}/${n.title}`">{{n.title}}</router-link>&nbsp;&nbsp;</li> -->
     <!-- 跳转路由携带参数to的对象写法 -->
   <li v-for="n in messageList" :key="n.id">
     <router-link :to="{
      name:'detail',
     params:{
       id:n.id,
       title:n.title
     }
   }
   ">{{n.title}}</router-link>&nbsp;&nbsp;</li>

detail.vue


 <div>
  message:id{{$route.params.id}}<br>
  message:title{{$route.params.title}}
 </div>

/router/index.js


children:[
{
name:'detail',
       //这里要写展位符
path:'detail/:id/:title',
component:Detail
}
]

八,router-link的replace属性

在router-link标签的后面添加replace

当我们点击路由的时候浏览器会产生记录,应为浏览器会有push模式向栈中压入路由,所以浏览器可以前进和后退,但是,如果我们在router-link的后面添加了replace属性之后,该路由之前前的路由被替换,就不能够生成记录了,实在是说不清楚。

比较官方的说法:

  1. 作用:控制路由跳转时操作浏览器历史记录的模式

  2. 浏览器的历史记录有两种写入方式,分别是push和replace,push时追加历史记录,replace是替换当前记录,路由跳转时候默认为push

  3. 开启replace写法如下


<router-link replace to="#"></router-link>
<!--或者是比较复杂的写法-->
<router-link :replace=true to="#"></router-link>

九,编程式路由导航

顾名思义不借助router-link标签来完成路由的跳转和前进和后退


this.$router.push({
name:"#",
params:{
id:#,
name:#,
}
})

this.$router.replace({
name:"#",
params:{
id:#,
name:#,
}
})
this.$router.forward();//前进
this.$router.back();//后退
this.$router.go();//go中传入参数,整数为前进,负数为后退,数字为一次后退次数

十,缓存路由组件

作用是让不展示的路由保持挂载不被销毁

具体编码:


<!-- 这里的#是组件名 -->
<keep-alive include="#">
  <!-- 这个路由对应的必须是#所展示的路由,不能包裹在整哥结构的外侧-->
   <router-view></router-view>
</keep-alive>

十一,两个新的生命周期函数

前面说了我们可以让路由保持挂载不销毁,但是我希望这个路由保存我不想销毁的地方不被销毁,其他地方销毁(听听?人话?)定义了两个新的钩子activated和deactivated,激活和失活但是不销毁。


activated(){
   
},
deactivated(){
     
}

十二,路由守卫

内容不难,但是有点多,很重要


beforeEach((to,from,next)=>{
  //前置路由守卫
})

afterEach((to,from)=>{
  //后置路由守卫
})

beforeEnter((to,from,next)=>{
   //组件路由守卫
})

to中有一个meta参数,可以放置路由元数据

 

七,Vue UI组件库

移动端ui组件库,pc端ui组件库

以下代码使用elementUI组件

个人感觉非常好用

main.js


import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
//引入ui的全部样式
import 'element-ui/lib/theme-chalk/index.css';

//注册成全局的UI
Vue.use(ElementUI);
Vue.config.productionTip = false

new Vue({
 render: h => h(App),
}).$mount('#app')

app.vue


<template>
 <div >
  <button>原生的按钮</button>
  <input type="text">

  <el-row>
 <el-button>默认按钮</el-button>
 <el-button type="primary">主要按钮</el-button>
 <el-button type="success">成功按钮</el-button>
 <el-button type="info">信息按钮</el-button>
 <el-button type="warning">警告按钮</el-button>
 <el-button type="danger">危险按钮</el-button>
</el-row>
 </div>
</template>

<script>

export default {
 name: 'App',

}
</script>

<style>
</style>

真就cv工程师

以上是完整引入elementui组件,但是这个时候由于是引入所有的组件,导致写的文件非常大,为了解决这个问题,往下看,使用按需引入。

但是按需引入这里遇到了问题,这个问题又和webpack有关头大了,但是书写的代码是没有问题的。

main.js


import Vue from 'vue'
import App from './App.vue'



import { Button, Row, } from 'element-ui';

Vue.config.productionTip = false

Vue.component('wds-button', Button);
Vue.component('wds-row', Row);


new Vue({
 render: h => h(App),
}).$mount('#app')

app.vue


<template>
 <div >
  <button>原生的按钮</button>
  <input type="text">

  <wds-row>
 <wds-button>默认按钮</wds-button>
 <wds-button type="primary">主要按钮</wds-button>
 <wds-button type="success">成功按钮</wds-button>
 <wds-button type="info">信息按钮</wds-button>
 <wds-button type="warning">警告按钮</wds-button>
 <wds-button type="danger">危险按钮</wds-button>
</wds-row>
 </div>
</template>

<script>

export default {
 name: 'App',

}
</script>

<style>
</style>

bable.config.js


module.exports = {
 //预设包
 presets: [
   '@vue/cli-plugin-babel/preset',["@bable/preset-env", { "modules": false }]

],
 "plugins": [
  [
     "component",
    {
       "libraryName": "element-ui",
       "styleLibraryName": "theme-chalk"
    }
  ]
]
}

到这里,vue2粗略的学完了,学习内容还有很多需要精细,例如vue生命周期的相关知识等,日后还是有的忙的。