Vue学习笔记

Vue学习笔记


声明

该文章为转载多方文章加一些自己的理解所成所成
转自百度网盘,链接链接:https://pan.baidu.com/s/1HC_TRtyt2ncC1zMRNCnlSw?pwd=1234
提取码:1234

gitee代码链接

1、初识vue

初识vue:
1.要用vue首先得创建一个vue实例,还要绑定一个
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的语法;
3.root容器中的代码被称为Vue模板
4.Vue实例和容器是一一对应的;
5真实开发中只有一个Vue实例并且会配合着组件一起使用;
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;7.一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新;

1.1.第一个vue程序

学习到了vue里vue实例和容器的绑定以及对vue-devtools的使用

代码如下(示例):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h1>你好,{{name}}</h1>
</div>
<script>
  Vue.config.productionTip=false

  //创建vue实例
  const x =new Vue({
    el:"#root" ,       //el用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
    data:{            //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象
      name:'vue',
      age:13
    }
  })
</script>
</body>
</html>

在这里插入图片描述


2.一个容器只能对应一个实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script src="vue.js"></script>
</head>
<body>
<div class="root">
  <h1>你好,{{name}}</h1>
</div>
<div class="root">
    <h1>你好,{{name}}</h1>
</div>
<script>
  Vue.config.productionTip=false

  //创建vue实例
  const x =new Vue({
    el:".root" ,       //el用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
    data:{            //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象
      name:'vue',
      age:13
    }
  })
</script>
</body>
</html>

在这里插入图片描述

3.模板语法

vue模板语法有2大类:
1.插值语法:
功能:用于解析标签体内容。
写法:{ixxx}}, xxx是js表达式,且可以直接读取到data中的所有属性。
2.指令语法:
功能:用于解析标签
(包括:标签属性、标签体内容、绑定事件…) .
举例:v-bind: href=“xxx”或简写为:href=” xxx",xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是: v-???,此处我们只是拿v-bind举个例

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script src="vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
<h1>插值语法</h1>
<h3>你好,{{name.toUpperCase()}}</h3>
<hr>
<h1>指令语法</h1>
<a v-bind:href="school.url.toUpperCase()">点我去{{school.name}}学习!</a>
<a :href="school.url">点我去学习!</a>
</div>
</body>
<script type="text/javascript">
  Vue.config.productionTip=false
  new Vue({
    el:'#root',
    data:{
      name:'jack',

        school:{
            name:"csdn",
            url:'https://www.csdn.net/',
        }
    }
  })
</script>
</html>

4.数据绑定

这里是引用

Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
  1.双向绑定一般都应用在表单类元素上(如: input、select等)
 2.v-model:value可以简写为v-model,因为v-model默认收集的就是value值

4.el和data的两种写法

真相只在代码之中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<body>
<div class="root">
    <h1>你好,{{name}}</h1>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip=false //阻止vue 在启动时生成生产提示
    const v = new Vue({
        // el:"#root" , el d的第一种写法
        data:{
            name:'vue'
        }
    })
    console.log(v)
    v.$mount('#root') //el的第二种写法

    //data的两种写法
    new Vue({
        el:'#root',
        //data的第一种写法,对象式
        /*
        data:{
        name:'尚硅谷'
        }

        */

        //data的第二种写法:函数式
        data(){
            console.log('@@@',this) //此处的this
            return{
                name:'vue'
            }
        }
    })
</script>
</html>

5.MVVM

MVVM模型
 1。M:模型(Model) : data中的数据
 2.V:视图(View):模板代码
 3.VM:视图模型(ViewModel):Vue实例
观察发现:
 1.data中所有的属性,最后都出现在了vm身上。
 2.vm身上所有的属性及 Vue原型上所有属性,在Vue模板中都可以直接使用。

6.数据代理

6.1.Object.defineProperty方法

这一小节主要将了Object.defineProperty方法的用法,其中有许多使实用的属性值需要学习

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>回顾Object.defineproperty方法</title>
    <script src="vue.js"></script>

</head>
<body>
<script>
    let address='阿大多数'
  let person={
    name:'崔浩然',
    age:18,
    sex:'男'
  }
  Object.defineProperty(person,'address', {
      value: "山西省大同市",
      enumerable: true,   //控制该属性是否可被枚举
      writable: true,  //控制属性是否可以被修改
      configurable: true, //控制属性是否可以被删除

      //当有人读取person的age属性时,get函数就可以被调用,且返回值就是age的值
      get: function () { //简写为get(){}
          return address
      },


      //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
      set(value){
        console.log("有人修改了age属性,且值是:",address)
      }
  })

  console.log(Object.keys(person)) //Object.keys方法:参数:要返回其枚举自身属性的对象 返回值:一个表示给定对象的所有可枚举属性的字符串数组
  for(let key in person){
    console.log("@",person[key])

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

6.2 数据代理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>何为数据代理</title>
</head>
<body>
<!--  数据代理:通过一个对象代理对另一个对象中属性的操作(/)-->
<script type="text/javascript">
    let obj={x:100}
    let obj2={y:200}

    Object.defineProperty(obj2,'x',{
        get(){
            return obj.x
        },
        set(value){
            obj.x=value
        }
    })
</script>
</body>
</html>

6.3Vue中的数据代理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
  <h2>学校名称:{{name}}</h2>
  <h2>学校地址:{{address}}</h2>
</div>
</body>

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

  const vm = new Vue({
    el:'#root',
    data:{
      name:'齐大',
      address:'齐齐哈尔市建华区'
    }
  })
</script>
</html>

在这里插入图片描述

7.事件处理

7.1事件的基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script type="text/javascript" src="vue.js"></script>

</head>
<body>
<div id="root">
  <h2>欢迎来到{{name}}学习</h2>
  <button v-on:click="showInfo">点我1</button>
  <button @click="showInfo2(66,$event)">点我2</button>
</div>
</body>
<script type="text/javascript">
  Vue.config.productionTip =false //阻止vue在启动的时候生成提示
  new Vue({
    el:'#root',
    data:{
      name:'齐大'
    },
    methods:{
      showInfo(event){
        alert('同学你好')
          console.log(event.target.innerText)
          console.log(this) //此处的this是vm
      },
        showInfo2(number,a){
            console.log(number,a)

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

7.2 事件修饰符

Vue中的事件修饰符:
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用):
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素是才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="vue.js"></script>
    <style>
        * {
            margin-top: 20px;
        }

        .demo1 {
            height: 50px;
            background-color: red;
        }

        .box1 {
            padding: 5px;
            background-color: skyblue;
        }

        .box2 {
            padding: 5px;
            background-color: orange;
        }
        .list{
            width:200px;
            height: 20px;
            background-color: darkblue;
            overflow: auto;
        }
        li{
            height: 100px;
        }
    </style>
</head>
<body>
<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
    <!--    阻止默认事件(常用)-->
    <a href="https://www.bilibili.com/" @click.prevent="showInfo">dianwo</a>
    <!--    阻止事件冒泡-->
    <div class="demo1" @click="showInfo">
        <button @click.stop="showInfo">dinawo2</button>
    </div>
    <!--    事件只触发一次(常用)-->
    <button @click.once="showInfo">dinawo3.once</button>
    <!--    使用事件的捕获模式-->
    <div class="box1" @click="showMsg(1)">
        div1
        <div class="box2" @click="showMsg(2)">
            div2
        </div>
    </div>

<!--    只有event.target是当前操作的元素时才触发事件-->
    <div class="demo1" @click="showInfo5">
        <button @click="showInfo5"> 点我提示信息</button>
    </div>

<!--   事件的默认行为立即执行,无需等待事件回调执行完毕-->
<!--    @scroll是滚动滚动条触发事件,wheel是鼠标滚轮滚动触发事件,让他们的默认行为立即执行则@scroll.passive-->
    <ul @scroll="demo" class="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
</div>

</body>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止vue在启动的时候生成提示
    new Vue({
        el: '#root',
        data: {
            name: '齐大'
        },
        methods: {
            showInfo(event) {
                event.preventDefault()
                alert('同学你好')
            },
            showMsg(msg){
                alert('alshdad')
            },
            showInfo5(event) {
                console.log(event.target)
            },
            demo() {
                console.log('A')
            }
        }
    })
</script>
</html>

7.3键盘修饰符

1.Vue中常用的按键别名:
回车=>enter
删除=>delete(捕获"删除”和退格”键)退出=>esc
空格=>space
换行=>tab(特殊,必须配合keydown使用)
上=> up
下 =>down
左=>left
右=>right
2.Vue未提供别名的按键,可以使用按健原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctr1、alt、shift、meta
  (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
  (2).配合keydown使用:正常触发事件。
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config.keyCodes.自定义键名=键码,可以去定制按键别名

8.姓名案例

8.1插值语法实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>姓名案例_插值语法实现</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h1>{{name}}</h1>
  <input type="text" v-model="firstname"> <br> <br>
  <input type="text" v-model="lastname"> <br> <br>
  全名: <span> {{firstname+lastname}}</span>
</div>

<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      firstname: 'cui',
      lastname:'haoran'
    },
    methods:{
      showInfo(e){
        console.log(e.target.value)
      }
    }
  })
</script>
</body>
</html>

8.2methods实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例_插值语法实现</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <input type="text" v-model="firstname"> <br> <br>
    <input type="text" v-model="lastname"> <br> <br>
    全名: <span> {{fullName()}}</span>
    <button @click="fullName()">点我</button>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            firstname: 'cui',
            lastname:'haoran'
        },
        methods:{
            fullName(){
               return this.firstname+this.lastname
            }
        }
    })
</script>
</body>
</html>

8.3计算属性

计算属性:
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了objcet.defineproperty方法提供的getter和setter。3.get函数什么时候执行?
 (1).初次读取时会执行一次。|
 (2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
 1.计算属性最终会出现在vm上,直接读取使用即可。
 2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例_计算属性实现</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <input type="text" v-model="firstname"> <br> <br>
    <input type="text" v-model="lastname"> <br> <br>
   测试 <input type="text" v-model="x"> <br> <br>
    全名: <span> {{fullName()}}</span>

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            firstname: 'cui',
            lastname:'haoran'
        },
        computed:{
            fullname:{
                get(){
                    return this.firstname+'-'+this.lastname
                },
                set(value){
                    console.log('set',value)
                    const arr= value.split('-')
                    this.firstname=arr[0]
                    this.lastname=arr[1]
                }
            }
        }
    })
</script>
</body>
</html>

9监视属性

监视属性watch:
1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm. $watch监视

9.1天气案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>天气案例</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h2>今天天气很{{info}}</h2>
  <button @click="change">切换天气</button>
</div>
</body>
<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      isHot:true
    },
    computed:{
      info(){
        return this.isHot?'炎热':"凉爽"
      }
    },
    methods:{
      change(){
        this.isHot=!this.isHot
      }

    }

  })
</script>

</html>

9.2handler

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>天气案例_监视属性</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h2>今天天气很{{info}}</h2>
  <button @click="change">切换天气</button>
</div>
</body>
<script>
  Vue.config.productionTip = false
  const vm=new Vue({
    el: "#root",
    data: {
      isHot:true
    },
    computed:{
      info(){
        return this.isHot?'炎热':"凉爽"
      }
    },
    methods:{
      change(){
        this.isHot=!this.isHot
      }

    },
    watch:{
      isHot:{
        // immediate:true,//初始化时让handler调用一下
        //handler什么时候调用?当ishot发生改变时
        handler(newValue,oldValue){
          console.log("isHot被修改了",newValue,oldValue)
        }
      }
    }

  })
  vm.$watch('isHot',{
    immediate:true,//初始化时让handler调用一下
    //handler什么时候调用?当ishot发生改变时
    handler(newValue,oldValue){
      console.log("isHot被修改了",newValue,oldValue)
    }
  })
</script>

</html>

9.3深度属性

deep:true //监视多级结构中所有的变化,可以在对numbers监视的情况下,只要改变其中的值就可以检测到numbers的变化

9.4watch和computed的区别

计算属性computed不能开启异步任务去维护数据
computed和lwatch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如: watch可以进行异步操作。两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
2所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

10绑定样式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
<!--  绑定css样式--字符串写法,适用于:样式的类名不确定,需要动态指定-->
  <div class="basic" :class="a" @click="changeMood">{{name}}</div>
<!--  绑定css样式--数组写法,要绑定的样式个数不确定,名字也不确定-->
  <div class="basic" :class="classArr" >{{name}}</div>
<!--  绑定css样式--对象写法,适用于:要绑定的样式个数确定,名字也确定,单要动态觉得用不用-->
  <div class="basic" :class="classObj" >{{name}}</div>

  <div class="basic" :style="styleObj">{{name}}</div>
<!--  同时使用俩个样式-->
  <div class="basic" :style="[styleObj,styleObj2]">{{name}}</div>
</div>
</body>
<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      name: '崔浩然',
      a:'normal',
      classArr:['a','b','c'],
      classObj:{
        asdhl:false,
        asdad:false
      },
      fsize:20,
      styleObj:{
        fontSize:'40px',
        color:'red',

      },
      styleObj2:{

        backgroundColor:'blue'
      }
    },
    methods:{
      // changeMood(){
      //   console.log('阿达代理商')
      //  document.getElementById('demo').className='basic happy'
      // },
      changeMood(){
       const arr = ['happy','sad','normal']
        const index=Math.floor(Math.random()*3)
        this.a=arr[index]
      },

    }
  })
</script>

</html>

11.条件渲染

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>条件渲染</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
<!--  v-show-->
  <h1 v-show="false">{{name}}</h1>


<!--  v-if-->
  <h1 v-if="false">{{n}}</h1>
  <button @click="n++">点我n加一</button>
  <div v-if="n===1">阿萨达</div>
  <div v-else-if="n===2">阿的萨达</div>
  <div v-else-if="n===3">add</div>
  <div v-else-="n===3">啊大大</div>
</div>
</body>
<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      name: '崔浩然',
      n:1
    },
    methods:{
      showInfo(e){
        console.log(e.target.value)
      }
    }
  })
</script>

</html>

12.列表渲染

12.1基本列表

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表渲染</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <h2>人员列表</h2>
    <ul>
        <!--        <li v-for="person in persons" :key="p.id">{{person}}</li>-->
        <li v-for="(p,index) in persons" :key="p.id">{{p.name}}---{{p.age}}</li>

    </ul>

    <h2>汽车嘻嘻</h2>
    <ul>
        <li v-for="(value,key) of car" :key="key">{{key}}---{{value}}</li>
    </ul>
    <h2>遍历字符串</h2>
    <ul>
        <li v-for="(value,key) in str" :key="key">{{key}}---{{value}}</li>
    </ul>
</div>
</body>
<script>
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: '崔浩然',
            persons: [
                {id: '1', name: '张三', age: 18},
                {id: '2', name: '三大', age: 12},
                {id: '3', name: '啊大', age: 13}
            ],
            car: {
                name: '奥迪a6',
                price: '57w',
                color: 'white'
            },
            str:'hello'
        }
    })
</script>

</html>

12.2key的原理

面试题:react、 vue中的key有什么作用?(key的内部原理)
 1。虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

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

3。用index作为key可能会引发的问题:
(1)若对数据进行:逆序添加、逆序删除等破坏顺序操作;会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。
(2)如果结构中还包含输入类的DOM:会产生错误DOM更新==>界面有问题。
4。开发中如何选择key?:
(1)最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
(2)t加果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用干渲染列表用于展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表渲染</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <h2>人员列表</h2>
  <button @click.once="add">添加一个老刘</button>
    <ul>
        <li v-for="(p,index) of persons" :key="p.key">{{p.name}}---{{p.age}}
          <input type="text"></li>

    </ul>
</div>
</body>
<script>
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: '崔浩然',
            persons: [
                {id: '1', name: '张三', age: 18},
                {id: '2', name: '三大', age: 12},
                {id: '3', name: '啊大', age: 13}
            ]
        },
      methods:{
          add(){
            const p={id:'4',name:'老刘',age:23}
            this.persons.unshift(p)
          }
      }
    })
</script>

</html>

12.3列表过滤

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>列表过滤</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <h2>人员列表</h2>

    <input type="text" placeholder="请输入名字" v-model="keyword">
    <ul>
        <li v-for="(p,index) of filPersons" :key="p.key">{{p.name}}---{{p.age}}--{{p.sex}}


    </ul>
</div>
</body>
<script>
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            keyword: "",
            persons: [
                {id: '1', name: '张三', age: 18, sex: '男'},
                {id: '2', name: '三大', age: 12, sex: '男'},
                {id: '3', name: '啊大', age: 13, sex: '男'},
                {id: '4', name: '阿萨达', age: 13, sex: '男'},
                {id: '5', name: '梵蒂冈', age: 13, sex: '男'}
            ],
            // filPersons: [] 用watch实现时启用
        },
        //用watch是实现
        // watch: {
        //     keyword: {//这里通过immediate让监视属性在页面加载时执行一次,再通过indexof("")的结果为全部使初始页面展示全部人的信息
        //         immediate:true,
        //         handler(val) {
        //             this.filPersons = this.persons.filter((p) => {
        //                 return p.name.indexOf(val) !== -1
        //             })
        //
        //         }
        //     }
        // },
        //

        //用computed实现
        computed:{
            filPersons(){
                return this.persons.filter((p)=>{
                    return p.name.indexOf(this.keyword)!== -1})

            }
        }
    })
</script>

</html>

12.4列表排序

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>列表排序</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h2>人员列表</h2>

  <input type="text" placeholder="请输入名字" v-model="keyword">
  <button @click="sortType=2"> 年龄升序</button>
  <button  @click="sortType=1">年龄降序</button>
  <button @click="sortType=0">原顺序</button>
  <ul>
    <li v-for="(p,index) of filPersons" :key="p.id">{{p.name}}---{{p.age}}--{{p.sex}}
      <input type="text">

  </ul>
</div>
</body>
<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      keyword: "",
      sortType:0, //0原序,1降序,2升序
      persons: [
        {id: '1', name: '张三', age: 18, sex: '男'},
        {id: '2', name: '三大', age: 12, sex: '男'},
        {id: '3', name: '啊大', age: 13, sex: '男'},
        {id: '4', name: '阿萨达', age: 13, sex: '男'},
        {id: '5', name: '梵蒂冈', age: 13, sex: '男'}
      ],

    },

    computed:{
      filPersons(){
        const arr = 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>

</html>

12.5更新时的一个问题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>更新时的</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h2>人员列表</h2>
  <button @click="updateSan">更新信息张三</button>
  <ul>
    <li v-for="(p,index) of  persons" :key="p.id">{{p.name}}---{{p.age}}--{{p.sex}} </li>


  </ul>
</div>
</body>
<script>
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      keyword: "",
      sortType:0, //0原序,1降序,2升序
      persons: [
        {id: '1', name: '张三', age: 18, sex: '男'},
        {id: '2', name: '三大', age: 12, sex: '男'},
        {id: '3', name: '啊大', age: 13, sex: '男'},
        {id: '4', name: '阿萨达', age: 13, sex: '男'},
        {id: '5', name: '梵蒂冈', age: 13, sex: '男'}
      ]

    },
    methods:{
      updateSan(){
        this.person[0].name='马老师'//奏效
        this.person[0].age=50//奏效
        this.person[0].name='马老师'//奏效
        this.persons[0]={id: '1', name: '张四', age: 18, sex: '男'}
      }
    }

  })
</script>

</html>

12.6 Vue检测数据改变的原理_对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue监测数据改变的原理</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <h2>学校名称{{name}}</h2>
    <h2>学校地址{{address}}</h2>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            name:"宗棂",
          address:"山西"


        },
        methods: {
            updateSan() {
                this.person[0].name = '马老师'//奏效
                this.person[0].age = 50//奏效
                this.person[0].name = '马老师'//奏效
                this.persons[0] = {id: '1', name: '张四', age: 18, sex: '男'}
            }
        }

    })
</script>

</html>

12.7模拟一个数据监测

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>数据监测</title>
</head>
<body>
<div id="root">
  <h2>学校名称{{name}}</h2>
  <h2>学校地址{{address}}</h2>
</div>
</body>
<script type="text/javascript">
  let data={
    name:"大会上的",
    address:"大师等级"
  }

  //创建一个监视的实例对象,用于监测data中属性的变化
  const obs=new Observer(data)
  console.log(obs)

  let vm={}
  vm._data= data=obs
  function Observer(obj){
    //汇总对象中所有属性形成一个数组
    const keys= Object.keys(obj)
    //遍历
    keys.forEach((k)=>{
      Object.defineProperty(this,k,{
        get(){
          return obj[k]
        },
        set(val){
          console.log("${k}被改了,解析模板,生成虚拟dom")
          obj[k] = val
        }
      })
    })
  }
</script>

</html>

12.8Vue中set的使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>数据监测</title>
</head>
<body>
<div id="root">
  <h2>学校名称{{name}}</h2>
  <h2>学校地址{{address}}</h2>
  <hr>
  <h2>学生姓名:{{student.name}}</h2>
  <h2>学生年龄:真实{{student.age.rage}},对外:{{{student.age.sage}}</h2>
  <h2>朋友们</h2>
  <ul>
    <li v-for="(f,index) in student.friends" :key="index">
      {{f.name}}--{{f.age}}
    </li>
  </ul>
</div>
</body>
<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
    el: "#root",
    data: {
      name:"宗棂",
      address:"山西",
      student:{
        name:'tom',
        age:{
          rage:20,
          sage:19
        },
        friends:[
          {name:'安顺',age:32},
          {name:'三大',age:43},
        ]
      }


    },
    methods: {
      updateSan() {
        this.person[0].name = '马老师'//奏效
        this.person[0].age = 50//奏效
        this.person[0].name = '马老师'//奏效
        this.persons[0] = {id: '1', name: '张四', age: 18, sex: '男'}
      }
    }

  })
</script>

</html>

12.9Vue监测数据时改变的原理_数组

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据监测改变原理</title>
    <script src="vue.js"></script>
</head>
<body>
<div id="root">
    <h2>学校信息</h2>
    <h2>学校名称:{{school.name}}</h2>
    <h2>学校地址{{school.address}}</h2>
    <hr/>
    <h1>学生信息</h1>
    <button @click="updateSan">添加一个性别属性,默认值是男</button>
    <h2>姓名:{{student.name}}</h2>
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2>年龄:真实{{student.age.rage}},对外:{{student.age.sage}}</h2>
    <h2>爱好们</h2>
    <ul>
        <li v-for="(h,index) in student.hobby" :key="index">
            {{h}}
        </li>
    </ul>
    <ul>
        <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}}--{{f.age}}
        </li>
    </ul><ul>
    <li v-for="(p,index) in persons" :key="index">
        {{p.name}}--{{p .age}}--{{p.sex}}
    </li>
</ul>

</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            school:{
                name:'齐大',
                address:'黑龙江'
            },
            student:{
                name:'崔浩然',
                age:{
                    rage:40,
                    sage:29
                },
                friends:[
                    {name:"tom",age:23},
                    {name:"mary",age:18},
                ],
                hobby:["抽烟","喝酒","烫头"],
            },

            persons: [
                {id: '1', name: '张三', age: 18, sex: '男'},
                {id: '2', name: '三大', age: 12, sex: '男'},
                {id: '3', name: '啊大', age: 13, sex: '男'},
                {id: '4', name: '阿萨达', age: 13, sex: '男'},
                {id: '5', name: '梵蒂冈', age: 13, sex: '男'}
            ]
        },
        methods: {
            updateSan() {
                //0表示从第0个开始,1表示删除并插入一个,后面要插入的值
                this.persons.splice(0, 1, {id: '1', name: "马老师", age: 50, sex: "男"})
            }
        }
    })
</script>

</html>

Vue监测总结

Vue监视数据的原理:

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

  2. 如何监测对象中的数据? 通过setter实现监视,且要在new Vue时就传入要监测的数据。
    (1)对象中后追加的属性,Vue默认不做响应式处理
    (2)如需给后添加的属性做响应式,请使用如下API:
    Vue.set(target.propertyName/index.value)或vm.$set(target.propertyName /index,value)

  3. 如何监测数组中的数据?
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    (1).调用原生对应的方法对数组进行更新。
    (2).重新解析模板,进而更新页面。

  4. 在Vue修改数组中的某个元素一定要用如下方法:
    (1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort(),reverse()
    (2)Vue.set()或vm. s e t ( ) 特 别 注 意 : V u e . s e t ( ) 和 v m . set() 特别注意:Vue.set()和 vm. set():Vue.set()vm.set()不能给vm或 vm的根数据对象添加属性!!!

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>数据监测改变原理</title>
  <script src="vue.js"></script>
</head>
<body>
<div id="root">
  <h1>学生信息</h1>
  <button @click="student.age++">年龄增加一岁</button>
  <button @click="addsex">添加一个性别属性,默认值是男</button>
  <button @click="stundent.sex='未知'">修改性别</button>
  <button @click="addfriend">在列表首位添加一个朋友</button>
  <button @click="updateFirstfriendname">修改死一个朋友的名字为:张三</button>
  <button @click="addHobby">添加一个爱好</button>
  <button @click="updateHobby">修改第一个爱好为:开车</button>
  <h2>姓名:{{student.name}}</h2>
  <h2 v-if="student.sex">性别:{{student.sex}}</h2>
  <h2>年龄:{{student.age}}</h2>
  <h2>爱好们</h2>
  <ul>
    <li v-for="(h,index) in student.hobby" :key="index">
      {{h}}
    </li>
  </ul>
  <ul>
    <li v-for="(f,index) in student.friends" :key="index">
      {{f.name}}--{{f.age}}
    </li>
  </ul><ul>
  <li v-for="(p,index) in persons" :key="index">
    {{p.name}}--{{p .age}}--{{p.sex}}
  </li>
</ul>

</div>
</body>
<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
    el: "#root",
    data: {
      student:{
        name:'崔浩然',
        age:23,
        friends:[
          {name:"tom",age:23},
          {name:"mary",age:18},
        ],
        hobby:["抽烟","喝酒","烫头"],
      }
    },
    methods: {
      addsex() {
        //添加性别方法一
        // Vue.set(this.student,'sex','男')
        //第二种方法
        this.$set(this.student,"sex","男")
      },
      addfriend(){
        this.student.friends.unshift({name:"jack",age:34})
      },
      updateFirstfriendname(){
        this.student.friends[0].name="张三"
      },
      addHobby(){
        this.student.hobby.push("学习")
      },
      updateHobby(){
        // this.studnet.hobby.splice(0,1,'开车') //方法一
        // Vue.set(this.student.hobby,0,'开车') //方法二
        this.$set(this.student.hobby,0,'开车') //方法三
      }
    }
  })
</script>

</html>

13 表单提交

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="vue.js"></script>
</head>
<!--收集表单数据:-->
<!--若:<input type="text"/>,则v-model收集的是value值。用户输入的就是value值。若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。若:<input type="checkbox" />-->
<!--1.没有配置input的value属性,那么收集的就是checked(勾选or未勾选,是布尔值)2.配置input的value属性:-->
<!--(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or未勾选,是布尔值)(2)v-model的初始值是数组,那么收集的的就是value组成的数组-->
<!--备注:v-model的三个修饰符:-->
<!--lazy:失去焦点再收集数据-->
<!--number:输入字符串转为有效的数字trim:输入首尾空格过滤-->

<body>
<div id="root">
    <h1>提交表单</h1>
    <form @submit.prevent="demo">
        账号: <input type="text" v-model.trim="account"><br><br>                         //trim可以去掉输入框前后的空格
        密码: <input type="password" v-model="password"><br><br>
        年龄: <input type="number" v-model.number="age"> <br> <br>
        性别:
        男: <input type="radio" name="sex"  v-model="sex" value="">
        女: <input type="radio" name="sex"  v-model="sex" value=""><br><br>
        爱好:
        学习: <input type="checkbox" name="hobby" v-model="hobby" value="学习">
        打游戏: <input type="checkbox" name="hobby" v-model="hobby" value="打游戏">
        吃饭: <input type="checkbox" name="hobby" v-model="hobby" value="吃饭"><br><br>
        所属校区:
        <select v-model="city">
            <option value="请选择校区">请选择校区</option>
            <option value="北京">北京</option>
            <option value="上海">上海</option>
            <option value="天津">天津</option>
        </select>
        <br><br>
        其他信息:
        <textarea v-model.lazy="other"></textarea>        //lazy可以实现输入框在市区焦点的时候才收集
        <br><br>
        <input type="checkbox" v-model="agree">阅读并接受 <a href="https://www.baidu.com/">用户协议</a>
        <button>提交</button>
    </form>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            account:'',
            password:'',
            age:"", 
            sex:'',
            hobby:[],
            city:"请选择校区",
            other:'',
            agree:''
        },
        methods:{
           demo(){
               console.log(JSON.stringify(this._data))
           }
        }
    })
</script>

</html>

14过滤器

过滤器: 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。语法:
1.注册过滤器:Vue.filter(name,callback)或new Vue{filters:{}
2.使用过滤器:{{ xxx│过滤器名}}或v-bind:属性="xxx|过滤器名"备注:

  1. 过滤器也可以接收额外参数、多个过滤器也可以串联
  2. 并没有改变原本的数据,是产生新的对应的数据
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>过滤器</title>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript" src="js/dayjs.min.js"></script>
</head>
<body>
<div id="root">
  <h1>显示格式化后的时间</h1>
<!--  计算属性实现-->
  <h3>现在是:{{fmtTime}}</h3>
<!--  methods实现-->
  <h3>现在是:{{getFmtTime()}}</h3>
<!--  过滤器实现-->
  <h3>现在是:{{time | timeFormater | mySlice}} </h3>
</div>
</body>
<script type="text/javascript">
  Vue.config.productionTip = false
  Vue.filter('mySlice',function (value){ //全局过滤器
    return value.slice(0,4)
  })
  new Vue({
    el: "#root",
    data: {
      time:1649243285810 //时间戳
    },
    methods:{
      getFmtTime(){
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    },
    computed:{
      fmtTime(){
        return dayjs(this.time).format("YYYY-MM-DD HH:mm:ss")
      }
    },
    filters:{
      timeFormater(value){
        return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
      },
      mySlice(value){
        return value.slice(0,4)
      }
    }
  })
</script>

</html>

15内置指令

我们学过的指令:
v-bind :单向绑定解析表达式,可简写为 :xxx
v-model :双向数据绑定
v-for :遍历数组/对象/字符串
v-on:绑定事件监听,可简写为@
v-if:条件渲染(动态控制节点是否存存在)
v-else:条件渲染(动态控制节点是否存存在)
v-show:条件渲染(动态控制节点是否展示)
v-text指令:
1.作用:向其所在的节点中渲染文N内容。
2.与插值语法的区别: v-text会替换掉节点中的内容,{{xx}}则不会。

15.1 v_text指令

<!DOCTYPE html>
<html lang="en">
<head>
  <!--
  我们学过的指令:
        v-bind :单向绑定解析表达式,可简写为 :xxx
        v-model :双向数据绑定
        v-for :遍历数组/对象/字符串
        v-on:绑定事件监听,可简写为@
        v-if:条件渲染(动态控制节点是否存存在)
        v-else:条件渲染(动态控制节点是否存存在)
        v-show:条件渲染(动态控制节点是否展示)
    v-text指令:
        1.作用:向其所在的节点中渲染文N内容。
        2.与插值语法的区别: v-text会替换掉节点中的内容,{{xx}}则不会。-->
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>

<body>
<div id="root">
    <h1>你好,{{name}}</h1>
    <h1 v-text="name">你好,</h1>
    <h1 v-text="str"></h1>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: '崔浩然',
            str:'<h3>你好啊</h3>'
        },
        methods:{
            showInfo(e){
                console.log(e.target.value)
            }
        }
    })
</script>

</html>

15.2 v-html指令

v-html指令:
1.作用:向指定节点中渲染包含html结构的内容
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!
(1)·在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

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

    <meta charset="UTF-8">
    <title>v-html指令</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<!--v-html指令:
1.作用:向指定节点中渲染包含html结构的内容
2.与插值语法的区别:
    (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
    (2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
    (1)·在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
    (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
-->
<body>
<div id="root">
    <h1>你好,{{name}}</h1>
    <h1 v-html="name">你好,</h1>
    <h1 v-html="str"></h1>
</div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: '崔浩然',
            str: '<h3>你好啊</h3>'
        }
    })
</script>

</html>

15.3 v-cloak指令

v-cloak指令(没有值):

  1. 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
  2. 使用css配合v-cloak可以解决网速慢时页面展示出{{xxXx]}的问题。
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <title>v-cloak指令</title>
    <style>
        [v-cloak]{
            display:none;
        }
    </style>

</head>

<body>
<div id="root">
    <h1 v-cloak>你好,{{name}}</h1>
</div>

<script type="text/javascript" src="js/vue.js" ></script>
</body>


<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: "#root",
        data: {
            name: '崔浩然',
            str:'<h3>你好啊</h3>'
        }

    })
</script>

</html>

15.4 v-once指令

v-once指令:

  1. v-once所在节点在初次动态渲染后,就视为静态内容了。
  2. 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<!DOCTYPE html>
<html lang="en">
<head>

  <meta charset="UTF-8">
  <title>v-once指令</title>
  <style>
    [v-cloak]{
      display:none;
    }
  </style>

</head>

<body>
<div id="root">
  <h2 v-once> 初始的n值是{{n}}</h2>
  <h2> 当前的n值是{{n}}</h2>
  <button @click="n++">n加一</button>
</div>

<script type="text/javascript" src="js/vue.js" ></script>
</body>


<script type="text/javascript">
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      n:1
    }

  })
</script>

</html>

15.5v-pre指令

v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

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

  <meta charset="UTF-8">
  <title>v-once指令</title>
  <style>
    [v-cloak]{
      display:none;
    }
  </style>

</head>

<body>
<div id="root">
  <h2 v-pre>VUe简单</h2>
  <h2 v-once> 初始的n值是{{n}}</h2>
  <h2> 当前的n值是{{n}}</h2>
  <button @click="n++">n加一</button>
</div>

<script type="text/javascript" src="js/vue.js" ></script>
</body>


<script type="text/javascript">
  Vue.config.productionTip = false
  new Vue({
    el: "#root",
    data: {
      n:1
    }

  })
</script>

</html>

16自定义指令

<!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>自定义指令</title>
  <script src="js/vue.js"></script>
</head>
<body>
<!--
    需求:
        1.定义一个v-big指令,和v-text功能相似,但是会把绑定的数值放大10倍。
        2.定义一个v-fbind指令,和v-bind功能类似,但是可以让其绑定的input元素默认获取焦点。
 -->
<!--
    自定义指令总结:
       1.定义语法:
           1.局部指令:
               new Vue({
                   diretives:{指令名:配置对象}
               })
               或者
               new Vue({
                   diretives(){}
               })
           2.全局指令
               Vue.diretive(指令名,配置对象) 或者 Vue.diretive(指令名,回调函数)

       2.配置对象中常用的3个回调:
               1.bind:指令与元素成功绑定时调用。
               2.inserted:指令所在元素被插入页面时调用。
               3.update:指令所在模板结构被重新解析时调用。

       3.备注:
               1.指令定义时不加v-,但是使用时加v-2.指令名如果是多个单词,要是用kebab-case命名方式,不要使用camelCase
 -->
<div id="root">
  <h2>当前的n值:<span v-text='n'></span></h2>
  <h2>放大10倍后的n值是:<span v-big='n'></span></h2>
  <button @click="n++">点我n+1</button><hr>
  <input type="text" v-fbind:value="n">
</div>

<script>


  //定义全局指令与全局函数:
  //全局函数
  Vue.directive('big',function(element,binding){
    element.innerText = binding .value * 10
    console.log(binding)
  })

  //全局指令
  Vue.directive('fbind',{
    //指令与元素成功绑定时(一上来)
    bind(element,binding){
      element.value = binding.value
    },
    //指令所在元素被插入元素时
    inserted(element,binding){
      element.focus()
    },
    //指令所在模板被重新解析时
    update(element,binding){
      element.value = binding.value
    }
  })


  new Vue({
    el:'#root',
    data:{
      n:1
    },
    directives:{
      //big何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
      //  big(element,binding){
      //     element.innerText = binding.value * 10
      //     console.log(binding)
      //  },
      //  fbind:{
      //      //指令与元素成功绑定时(一上来)
      //      bind(element,binding){
      //         element.value = binding.value
      //      },
      //      //指令所在元素被插入元素时
      //      inserted(element,binding){
      //          element.focus()
      //      },
      //      //指令所在模板被重新解析时
      //      update(element,binding){
      //         element.value = binding.value
      //      }
      //  }
    }
  })
</script>
</body>
</html>

17生命周期

生命周期:
1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
2.是什么:Vue在关健时刻帮我们调用的一些特殊名称的函数。
3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
4.生命周期函数中的this指向是vm或组件实例对象。

17.1引出生命周期

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>引出生命周期</title>
</head>

<body>
<div id="root">
    <h2 :style="{opacity}">VUe简单</h2>
</div>
<script type="text/javascript" src="js/vue.js"></script>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            opacity: 1
        },
        methods:{
            // change(){
            //     setInterval(()=>{
            //         this.opacity-=0.01
            //         if(this.opacity<=0)
            //             this.opacity=1
            //     },16)
            // }
        },
        //vue完成模板的解析并把真实的DOM元素放入页面后调用mounted
        mounted(){
            setInterval(()=>{
                this.opacity-=0.01
                if(this.opacity<=0)
                    this.opacity=1
            },16)
        }
    })
    // setInterval(()=>{
    //   vm.opacity-=0.01
    //   if(vm.opacity<=0)
    //     vm.opacity=1
    // },16)
</script>

</html>

17.2分析生命周期

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>分析生命周期</title>
</head>

<body>
<div id="root">
    <h2>当前n值为{{n}}</h2>
    <button @click="add">n++</button>
    <button @click="bye">点我销毁vm</button>
</div>
<script type="text/javascript" src="js/vue.js"></script>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            n: 1
        },
        methods: {
            add() {
                this.n++
            },
            bye(){
                this.$destroy()
            }
        },
        beforeCreate() {
            console.log(' beforeCreate')
        },
        created() {
            console.log('created')
        },
        beforeMount() {
            console.log(' beforeMount')
        },
        mounted() {
            console.log(' mounted')
        },
        beforeUpdate() {
            console.log(' beforeUpdate ')
        },
        updated(){
            console.log('updated')
            // debugger
        },
        beforeDestroy(){
            console.log('beforeDestroy')
        },
        destroyed(){
            console.log('destroyed')
        }
    })

</script>

</html>

17.3总结生命周期

在这里插入图片描述

18非单文件组件

Vue中使用组件的三大步骤:
1.定义组件(创建组件)
2.注册组件
3.使用组件(写组件标签)

    1.如何定义一个组件
        1.使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但是也有一点区别:
        区别如下:
            1.el不要写,why?最终所有的组件都需要经过一个vm管理,由vm中的el决定服务哪个容器。
            2.data必须写成函数,why?避免组件被重复使用,数据存在引用关系。
        备注:使用template可以配置组件结构

    2.如何注册组件?
        1.局部注册:靠new Vue()的时候传入components选项
        2.全局注册:靠Vue.component('组件名',组件)

    3.编写组件标签
        <school></school>

18.1基本使用

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

    -->
    <meta charset="UTF-8">
    <title>非单文件组件</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
<!--    第三部编写组件标签-->
    <hello></hello>
    <school></school>
    <student></student>
</div>
<div id="root2"><school></school></div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false

    //第一步:创建school组件
    const school = Vue.extend({
        // el: "#root", //一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器
        template: `
         <div>
            <h1>学校名称:{{ schoolName }}</h1>
            <h1>学校地址:{{ address }}</h1>
            <hr>
          </div>

        `,
        data() {
            return {
                schoolName: '齐大',
                address: '齐齐哈尔',
            }
        }
    })
jad
    const student = Vue.extend({
        template: `
          <div>
            <h1>学生名称:{{ studentName }}</h1>
            <h1>学生年龄:{{ age }}</h1>
            <hr>
          </div>

        `,
        data() {
            return {
                studentName: '崔浩然',
                age: 21
            }
        }
    })
    const hello=Vue.extend({
        template:`
        <div>你好{{name}}</div>`,
        data(){
            return{
                name:'Tom'
            }
        }
    })

    Vue.component("hello",hello)
    new Vue({
        el: '#root',
        //第二步:注册组件(局部注册)
        components: {
            school: school,
            student: student
        }
    })

    new Vue({
        el: '#root2',
        //第二步:注册组件(局部注册)
        components: {
            school: school,
            student: student
        }
    })

    function data() {
        return {
            a: 1,
            b: 2
        }

    }

    const x1 = data()
    const x2 = data()
    // new Vue({
    //     el: "#root",
    //     data: {
    //         schoolName: '齐大',
    //         address: '齐齐哈尔',
    //         studentName: '崔浩然',
    //         age: 21
    //     },
    //     methods: {
    //         showInfo(e) {
    //             console.log(e.target.value)
    //         }
    //     }
    // })
</script>

</html>

18.2几个注意点

几个注意点:
1.关于组件名:
一个单词组成:
第一种写法:首字母小写,school。
第二种写法:首字母大写,School。
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):需要Vue脚手架支持。
备注:
1.组件名尽可能回避HTML中已有的元素名称,例如,H2,h2都不行。
2.可以使用name配置项指定组件在开发者工具中呈现的名字。

        2.关羽组件标签:
            1.第一种写法:<school></school>
            2.第二种写法:<school/>
            备注:不适用脚手架时,<school/>会导致后续组件不能渲染。

        3.一个简写方式:
            const school = Vue.extend(options) 可以简写为: const school = options

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

  -->
  <meta charset="UTF-8">
  <title>非单文件组件</title>
  <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
  <h1> {{msg}}</h1>
  <school1></school1>

</div>

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

  //第一步:创建school组件
  const school = Vue.extend({
    template: `
         <div>
            <h1>学校名称:{{ schoolName }}</h1>
            <h1>学校地址:{{ address }}</h1>
            <hr>
          </div>

        `,
    data() {
      return {
        schoolName: '齐大',
        address: '齐齐哈尔',
      }
    }
  })
  new Vue({
    el:'#root',
    data:{
      msg:'欢迎学习vue'
    },
    components:{
      school1:school
    }
  })


</script>

</html>

18.3组件嵌套

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>组件的嵌套</title>
  <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
  <h1> {{msg}}</h1>
  <school1></school1>

</div>

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

  const student = Vue.extend({
    template: `
          <div>
            <h1>学生名称:{{ studentName }}</h1>
            <h1>学生年龄:{{ age }}</h1>
            <hr>
          </div>

        `,
    data() {
      return {
        studentName: '崔浩然',
        age: 21
      }
    }
  })
  const school = Vue.extend({
    template: `
         <div>
            <h1>学校名称:{{ schoolName }}</h1>
            <h1>学校地址:{{ address }}</h1>
            <hr>
            <student></student>
          </div>

        `,
    data() {
      return {
        schoolName: '齐大',
        address: '齐齐哈尔',
      }
    },
    components:{
      student
    }
  })
  new Vue({
    el:'#root',
    data:{
      msg:'欢迎学习vue'
    },
    components:{
      school1:school
    }
  })


</script>

</html>

18.4VueComponents

关于VueComponent:

  1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
  2. 我们只需要写成或者,Vue解析时会帮我们创建school组件的实例对象。 即Vue帮助我们执行的:new VueComponent(options)。
  3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent。
  4. 关于this的指向:
    1.在组件配置中:
    data函数,methods中的函数,watch中的函数,computed中的函数 它们的this均是{VueComponent实例对象}。
    2.new Vue()配置中:
    data函数,methods中的函数,watch中的函数,computed中的函数,它们的this均是{Vue实例对象}
  5. VueComponent的实例对象,以后简称vc(也可以称为:组件实例对象)
    Vue的实例对象,以后简称vm

18.5 一个重要的内置关系

VueComponent.prototype.proto === Vue.prototype

Vue和VueComponent的关系
在这里插入图片描述

<!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>一个重要的内置关系</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
        2.为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性,方法。
     -->
    <div id="root"></div>

    <script>
        //定义一个构造函数
        function Demo(){
            this.a = 1
            this.b = 2
        }

        //创建一个Demo实例对象
        const d = new Demo()

        console.log(Demo.prototype)//显式原型属性

        console.log(Demo.__proto__)//隐式原型属性
        new Vue({
            el:'#root',
        })
    </script>
</body>
</html>

19单文件组件

app.vue

app.vue:它是所有组件的父组件

<template>
<School></School>
  <Student></Student>
</template>

<script>
import School from "./School.vue";
import Student from "./Student.vue";

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

<style scoped>

</style>


main.js

它是整个vue程序的入口

import App from "./App.vue";

new Vue({
    el: "root",

    template: `<App></App>`,
    components: {
        App
    },
})

其他子组件

school组件

<template>
  //组件结构
  <div class="demo">
    <h1>学校名称:{{ schoolName }}</h1>
    <h1>学校地址:{{ address }}</h1>
    <button @click="showName">点我提示学校名</button>
    <hr>
  </div>
</template>

<script>
export default {
  name: "School",
  data() {
    return {
      schoolName: '齐大',
      address: '齐齐哈尔'
    }
  },
  methods:{
    showName(){
      alert(this.schoolName)
    }
  }
}
</script>

<style scoped>
  .demo{
    background:cadetblue;
  }
</style>

student组件

<template>
  <div>
    <h1>学生名称:{{ name }}</h1>
    <h1>学生年龄:{{ age }}</h1>
    <hr>
  </div>
</template>

<script>
export default {
  name: "Student",
  data(){
    return {
      name:"崔浩然",
      age:21
    }
  }
}
</script>

<style scoped>

</style>

html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单文件组件</title>
</head>
<body>
<div id="root"></div>

<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>

20脚手架的使用

20.1初始化脚手架

20.1.1说明
  1. Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)
  2. 最新的版本是 4.x
  3. 文档:Vue CLI
20.1.2具体步骤
  1. 如果下载缓慢请配置 npm 淘宝镜像:npm config set registry http://registry.npm.taobao.org
  2. 全局安装@vue/cli:npm install -g @vue/cli
  3. 切换到你要创建项目的目录,然后使用命令创建项目:vue create xxxx
  4. 选择使用vue的版本
  5. 启动项目:npm run serve
  6. 暂停项目:Ctrl+C

查看vue的配置需要在控制台输入vue inspect > output.js

20.1.3脚手架的结构

脚手架结构文件:

.文件目录
├── 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: 包版本控制文件

关于不同版本的vue:

 -vue.js与vue.runtime.xxx.js的区别:
    (1).vue.js是完整版的vue,包含:核心功能+模板解析器
    (2).vue.runtime.xxx.js是运行版的vue,只包含:核心功能,没有模板解析器.
 -因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
    render函数接收到的createElement函数去指定具体内容

20.2ref 与 props

=====ref:

1.作用:用于给节点打标识

2.读取方式:this.$refs.xxxxxx

====props
1.作用:用于父组件给子组件传递数据

2.读取方式一: 只指定名称

props: [‘name’, ‘age’, ‘setName’]
3.读取方式二: 指定名称和类型

props: {
name: String, age: Number,
setNmae: Function

}
4.读取方式三: 指定名称/类型/必要性/默认值

props: {
name: {type: String, required: true, default:xxx},

}

20.3混入

1.Vue 插件是一个包含install 方法的对象

2.通过install 方法给Vue 或Vue 实例添加方法, 定义全局指令等

20.4插件

1.Vue 插件是一个包含install 方法的对象

2.通过install 方法给Vue 或Vue 实例添加方法, 定义全局指令等

20.5Todo-list 案例

组件化编码流程(通用)

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

2.展示动态数据:

2.1.数据的类型、名称是什么?

2.2.数据保存在哪个组件? 3.交互——从绑定事件监听开始

20.6Vue 中的自定义事件

绑定事件监听

触发事件

20.7全局事件总线

20.7.1理解

1.Vue 原型对象上包含事件处理的方法

1)$on(eventName, listener): 绑定自定义事件监听

2)$emit(eventName, data): 分发自定义事件

3)$off(eventName): 解绑自定义事件监听

4)$once(eventName, listener): 绑定事件监听, 但只能处理一次

2.所有组件实例对象的原型对象的原型对象就是Vue 的原型对象

1)所有组件对象都能看到Vue 原型对象上的属性和方法

2)Vue.prototype. b u s = n e w V u e ( ) , 所 有 的 组 件 对 象 都 能 看 到 bus = new Vue(), 所有的组件对象都能看到 bus=newVue(),bus 这个属性对象
3.全局事件总线

1)包含事件处理相关方法的对象(只有一个)

2)所有的组件都可以得到

3.7.2指定事件总线对象

3.7.3绑定事件

3.7.4分发事件

3.7.5解绑事件

3.8消息订阅与发布

3.8.1理解

1.这种方式的思想与全局事件总线很相似

2.它包含以下操作:

(1)订阅消息 --对应绑定事件监听

(2)发布消息 --分发事件

(3)取消消息订阅 --解绑事件监听

3.需要引入一个消息订阅与发布的第三方实现库: PubSubJS

3.8.2使用PubSubJS

1.在线文档: https://github.com/mroderick/PubSubJS

2.下载: npm install -S pubsub-js

3.相关语法

(1)import PubSub from ‘pubsub-js’ // 引 入

(2)PubSub.subscribe(‘msgName’, functon(msgName, data){ })

(3)PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用

(4)PubSub.unsubscribe(token): 取消消息的订阅

3.9过度与动画

3.9.1效果

3.9.2vue 动画的理解

1.操作css 的trasition 或animation

2.vue 会给目标元素添加/移除特定的class

3.过渡的相关类名:

1.xxx-enter-active: 指定显示的transition

2.xxx-leave-active: 指定隐藏的transition

3.xxx-enter/xxx-leave-to: 指定隐藏时的样式

3.9.3基本过渡动画的编码

1.在目标元素外包裹

2.定义class 样式

a)指定过渡样式: transition

b)指定隐藏时的样式: opacity/其它

第 4 章:Vue 中的 ajax

4.1解决开发环境 Ajax 跨域问题

使用代理服务器

4.2github 用户搜索案例

4.2.1效果

4.2.2接口地址

https://api.github.com/search/users?q=xxx
4.3vue 项目中常用的 2 个 Ajax 库

4.3.1axios

通用的Ajax 请求库, 官方推荐,使用广泛
4.3.2vue-resource

vue 插件库, vue1.x 使用广泛,官方已不维护。

4.4slot 插槽

4.4.1效果

效果一(不使用插槽):
效果二(默认插槽):

效果三(具名插槽):

效果三(作用域插槽):

4.4.1理解

父组件向子组件传递带数据的标签,当一个组件有不确定的结构时, 就需要使用slot 技术,注意:插槽内容是在父组件中编译后, 再传递给子组件的。
4.4.2分类

1.默认插槽
2.命名插槽
3.作用域插槽

第 5 章:vuex

5.1理解 vuex

5.1.1vuex 是什么

1.概念:专门在Vue 中实现集中式状态(数据)管理的一个Vue 插件,对vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
2.Github 地址: https://github.com/vuejs/vuex

5.1.2什么时候使用 Vuex

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

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

5.1.3案例

5.1.4Vuex 工作原理图

5.2vuex 核心概念和 API

5.2.1state

1.vuex 管理的状态对象

2.它应该是唯一的

3.示例代码:

5.2.2actions

1.值为一个对象,包含多个响应用户动作的回调函数

2.通过commit( )来触发mutation 中函数的调用, 间接更新state

3.如何触发actions 中的回调?

在组件中使用: $store.dispatch(‘对应的 action 回调名’) 触发

4.可以包含异步代码(定时器, ajax 等等)

5.示例代码:

5.2.3mutations

1.值是一个对象,包含多个直接更新state 的方法

2.谁能调用mutations 中的方法?如何调用?

在action 中使用:commit(‘对应的 mutations 方法名’) 触发
3.mutations 中方法的特点:不能写异步代码、只能单纯的操作state

4.示例代码:

5.2.4getters

1.值为一个对象,包含多个用于返回数据的函数
2.如何使用?—— $store.getters.xxx
3.示例代码:

5.2.5modules

1.包含多个module
2.一个module 是一个store 的配置对象
3.与一个组件(包含有共享数据)对应

第 6 章:vue-router

6.1相关理解

6.1.1vue-router 的理解

vue 的一个插件库,专门用来实现SPA 应用

6.1.2对SPA 应用的理解

1.单页Web 应用(single page web application,SPA)。

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

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

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

6.1.3路由的理解

1.什么是路由?

1.一个路由就是一组映射关系(key - value)

2.key 为路径, value 可能是function 或component

2.路由分类

1.后端路由:

1)理解:value 是function, 用于处理客户端提交的请求。

2)工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据。
2.前端路由:

1)理解:value 是component,用于展示页面内容。

2)工作过程:当浏览器的路径改变时, 对应的组件就会显示。

6.2基本路由

6.2.1效果

6.2.2总结: 编写使用路由的 3 步

1.定义路由组件

2.注册路由

3.使用路由

6.3嵌套(多级)路由

6.4路由传参

6.5编程式路由导航

相关 API:
1.this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)

2.this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)

3.this.$router.back(): 请求(返回)上一个记录路由

4.this.$router.go(-1): 请求(返回)上一个记录路由

5.this.$router.go(1): 请求下一个记录路由

第 7 章:Vue UI 组件库

7.1移动端常用UI 组件库

1.Vant https://youzan.github.io/vant

2.Cube UI https://didi.github.io/cube-ui

3.Mint UI http://mint-ui.github.io

7.2PC 端常用UI 组件库

1.Element UI https://element.eleme.cn

2.IView UI https://www.iviewui.com

Vue3快速上手

1.Vue3简介

2.Vue3带来了什么

1.性能的提升

  • 打包大小减少41%

  • 初次渲染快55%, 更新渲染快133%

  • 内存减少54%

2.源码的升级

  • 使用Proxy代替defineProperty实现响应式

  • 重写虚拟DOM的实现和Tree-Shaking

3.拥抱TypeScript

  • Vue3可以更好的支持TypeScript

4.新的特性

  1. Composition API(组合API)

    • setup配置
    • ref与reactive
    • watch与watchEffect
    • provide与inject
  2. 新的内置组件

    • Fragment
    • Teleport
    • Suspense
  3. 其他改变

    • 新的生命周期钩子
    • data 选项应始终被声明为一个函数
    • 移除keyCode支持作为 v-on 的修饰符

一、创建Vue3.0工程

1.使用 vue-cli 创建

官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve

2.使用 vite 创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite

vite官网:https://vitejs.cn

  • 什么是vite?—— 新一代前端构建工具。
  • 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。
  • 传统构建 与 vite构建对比图

## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev

二、常用 Composition API

官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html

1.拉开序幕的setup

  1. 理解:Vue3.0中一个新的配置项,值为一个函数。
  2. setup是所有Composition API(组合API)“ 表演的舞台 ”
  3. 组件中所用到的:数据、方法等等,均要配置在setup中。
  4. setup函数的两种返回值:
    1. 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
    2. 若返回一个渲染函数:则可以自定义渲染内容。(了解)
  5. 注意点:
    1. 尽量不要与Vue2.x配置混用
      • Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。
      • 但在setup中不能访问到Vue2.x配置(data、methos、computed…)。
      • 如果有重名, setup优先。
    2. setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

2.ref函数

  • 作用: 定义一个响应式的数据
  • 语法: const xxx = ref(initValue)
    • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
    • JS中操作数据: xxx.value
    • 模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>
  • 备注:
    • 接收的数据可以是:基本类型、也可以是对象类型。
    • 基本类型的数据:响应式依然是靠Object.defineProperty()getset完成的。
    • 对象类型的数据:内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数。

3.reactive函数

  • 作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
  • 语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

4.Vue3.0中的响应式原理

vue2.x的响应式

  • 实现原理:

    • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。

    • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

      Object.defineProperty(data, 'count', {
          get () {}, 
          set () {}
      })
      
  • 存在问题:

    • 新增属性、删除属性, 界面不会更新。
    • 直接通过下标修改数组, 界面不会自动更新。

Vue3.0的响应式

  • 实现原理:

    • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。

    • 通过Reflect(反射): 对源对象的属性进行操作。

    • MDN文档中描述的Proxy与Reflect:

      • Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

      • Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

        new Proxy(data, {
        	// 拦截读取属性值
            get (target, prop) {
            	return Reflect.get(target, prop)
            },
            // 拦截设置属性值或添加新属性
            set (target, prop, value) {
            	return Reflect.set(target, prop, value)
            },
            // 拦截删除属性
            deleteProperty (target, prop) {
            	return Reflect.deleteProperty(target, prop)
            }
        })
        
        proxy.name = 'tom'   
        

5.reactive对比ref

  • 从定义数据角度对比:
    • ref用来定义:基本类型数据
    • reactive用来定义:对象(或数组)类型数据
    • 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象
  • 从原理角度对比:
    • ref通过Object.defineProperty()getset来实现响应式(数据劫持)。
    • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
  • 从使用角度对比:
    • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
    • reactive定义的数据:操作数据与读取数据:均不需要.value

6.setup的两个注意点

  • setup执行的时机

    • 在beforeCreate之前执行一次,this是undefined。
  • setup的参数

    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
    • context:上下文对象
      • attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
      • slots: 收到的插槽内容, 相当于 this.$slots
      • emit: 分发自定义事件的函数, 相当于 this.$emit

7.计算属性与监视

1.computed函数

  • 与Vue2.x中computed配置功能一致

  • 写法

    import {computed} from 'vue'
    
    setup(){
        ...
    	//计算属性——简写
        let fullName = computed(()=>{
            return person.firstName + '-' + person.lastName
        })
        //计算属性——完整
        let fullName = computed({
            get(){
                return person.firstName + '-' + person.lastName
            },
            set(value){
                const nameArr = value.split('-')
                person.firstName = nameArr[0]
                person.lastName = nameArr[1]
            }
        })
    }
    

2.watch函数

  • 与Vue2.x中watch配置功能一致

  • 两个小“坑”:

    • 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
    • 监视reactive定义的响应式数据中某个属性时:deep配置有效。
    //情况一:监视ref定义的响应式数据
    watch(sum,(newValue,oldValue)=>{
    	console.log('sum变化了',newValue,oldValue)
    },{immediate:true})
    
    //情况二:监视多个ref定义的响应式数据
    watch([sum,msg],(newValue,oldValue)=>{
    	console.log('sum或msg变化了',newValue,oldValue)
    }) 
    
    /* 情况三:监视reactive定义的响应式数据
    			若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
    			若watch监视的是reactive定义的响应式数据,则强制开启了深度监视 
    */
    watch(person,(newValue,oldValue)=>{
    	console.log('person变化了',newValue,oldValue)
    },{immediate:true,deep:false}) //此处的deep配置不再奏效
    
    //情况四:监视reactive定义的响应式数据中的某个属性
    watch(()=>person.job,(newValue,oldValue)=>{
    	console.log('person的job变化了',newValue,oldValue)
    },{immediate:true,deep:true}) 
    
    //情况五:监视reactive定义的响应式数据中的某些属性
    watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
    	console.log('person的job变化了',newValue,oldValue)
    },{immediate:true,deep:true})
    
    //特殊情况
    watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person的job变化了',newValue,oldValue)
    },{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
    

3.watchEffect函数

  • watch的套路是:既要指明监视的属性,也要指明监视的回调。

  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

  • watchEffect有点像computed:

    • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
    • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
    //watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
    watchEffect(()=>{
        const x1 = sum.value
        const x2 = person.age
        console.log('watchEffect配置的回调执行了')
    })
    

8.生命周期

vue2.x的生命周期 lifecycle_2
vue3.0的生命周期 lifecycle_2

1

  • Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
    • beforeDestroy改名为 beforeUnmount
    • destroyed改名为 unmounted
  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
    • beforeCreate===>setup()
    • created=======>setup()
    • beforeMount ===>onBeforeMount
    • mounted=======>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated =======>onUpdated
    • beforeUnmount ==>onBeforeUnmount
    • unmounted =====>onUnmounted

9.自定义hook函数

  • 什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。

  • 类似于vue2.x中的mixin。

  • 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。

10.toRef

  • 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。

  • 语法:const name = toRef(person,'name')

  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。

  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

三、其它 Composition API

1.shallowReactive 与 shallowRef

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)。

  • shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。

  • 什么时候使用?

    • 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
    • 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

2.readonly 与 shallowReadonly

  • readonly: 让一个响应式数据变为只读的(深只读)。
  • shallowReadonly:让一个响应式数据变为只读的(浅只读)。
  • 应用场景: 不希望数据被修改时。

3.toRaw 与 markRaw

  • toRaw:
    • 作用:将一个由reactive生成的响应式对象转为普通对象
    • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。
  • markRaw:
    • 作用:标记一个对象,使其永远不会再成为响应式对象。
    • 应用场景:
      1. 有些值不应被设置为响应式的,例如复杂的第三方类库等。
      2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。

4.customRef

  • 作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。

  • 实现防抖效果:

    <template>
    	<input type="text" v-model="keyword">
    	<h3>{{keyword}}</h3>
    </template>
    
    <script>
    	import {ref,customRef} from 'vue'
    	export default {
    		name:'Demo',
    		setup(){
    			// let keyword = ref('hello') //使用Vue准备好的内置ref
    			//自定义一个myRef
    			function myRef(value,delay){
    				let timer
    				//通过customRef去实现自定义
    				return customRef((track,trigger)=>{
    					return{
    						get(){
    							track() //告诉Vue这个value值是需要被“追踪”的
    							return value
    						},
    						set(newValue){
    							clearTimeout(timer)
    							timer = setTimeout(()=>{
    								value = newValue
    								trigger() //告诉Vue去更新界面
    							},delay)
    						}
    					}
    				})
    			}
    			let keyword = myRef('hello',500) //使用程序员自定义的ref
    			return {
    				keyword
    			}
    		}
    	}
    </script>
    

5.provide 与 inject

  • 作用:实现祖与后代组件间通信

  • 套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据

  • 具体写法:

    1. 祖组件中:

      setup(){
      	......
          let car = reactive({name:'奔驰',price:'40万'})
          provide('car',car)
          ......
      }
      
    2. 后代组件中:

      setup(props,context){
      	......
          const car = inject('car')
          return {car}
      	......
      }
      

6.响应式数据的判断

  • isRef: 检查一个值是否为一个 ref 对象
  • isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
  • isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
  • isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理

四、Composition API 的优势

1.Options API 存在的问题

使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。

2.Composition API 的优势

我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。

五、新的组件

1.Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

2.Teleport

  • 什么是Teleport?—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。

    <teleport to="移动位置">
    	<div v-if="isShow" class="mask">
    		<div class="dialog">
    			<h3>我是一个弹窗</h3>
    			<button @click="isShow = false">关闭弹窗</button>
    		</div>
    	</div>
    </teleport>
    

3.Suspense

  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验

  • 使用步骤:

    • 异步引入组件

      import {defineAsyncComponent} from 'vue'
      const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
      
    • 使用Suspense包裹组件,并配置好defaultfallback

      <template>
      	<div class="app">
      		<h3>我是App组件</h3>
      		<Suspense>
      			<template v-slot:default>
      				<Child/>
      			</template>
      			<template v-slot:fallback>
      				<h3>加载中.....</h3>
      			</template>
      		</Suspense>
      	</div>
      </template>
      

六、其他

1.全局API的转移

  • Vue 2.x 有许多全局 API 和配置。

    • 例如:注册全局组件、注册全局指令等。

      //注册全局组件
      Vue.component('MyButton', {
        data: () => ({
          count: 0
        }),
        template: '<button @click="count++">Clicked {{ count }} times.</button>'
      })
      
      //注册全局指令
      Vue.directive('focus', {
        inserted: el => el.focus()
      }
      
  • Vue3.0中对这些API做出了调整:

    • 将全局的API,即:Vue.xxx调整到应用实例(app)上

      2.x 全局 API(Vue3.x 实例 API (app)
      Vue.config.xxxxapp.config.xxxx
      Vue.config.productionTip移除
      Vue.componentapp.component
      Vue.directiveapp.directive
      Vue.mixinapp.mixin
      Vue.useapp.use
      Vue.prototypeapp.config.globalProperties

2.其他改变

  • data选项应始终被声明为一个函数。

  • 过度类名的更改:

    • Vue2.x写法

      .v-enter,
      .v-leave-to {
        opacity: 0;
      }
      .v-leave,
      .v-enter-to {
        opacity: 1;
      }
      
    • Vue3.x写法

      .v-enter-from,
      .v-leave-to {
        opacity: 0;
      }
      
      .v-leave-from,
      .v-enter-to {
        opacity: 1;
      }
      
  • 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

  • 移除v-on.native修饰符

    • 父组件中绑定事件

      <my-component
        v-on:close="handleComponentEvent"
        v-on:click="handleNativeClickEvent"
      />
      
    • 子组件中声明自定义事件

      <script>
        export default {
          emits: ['close']
        }
      </script>
      
  • 移除过滤器(filter)

    过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值