Vue 技术知识汇总:第 1 章 Vue 核心

第 1 章:Vue 核心

1.1 Vue 简介

1.1.1 介绍与描述

​ Vue 是一套用于构建用户界面的渐进式JavaScript框架。


1.1.2 Vue 的特点

  1. 采用组件化模式,提高代码复用率、且让代码更好维护。

  2. 声明式编码,让编码人员无需直接操作DOM,提高开发效率。

  3. 使用虚拟DOM监听数据的变化,采用双向数据绑定,尽量复用DOM节点

  • 遵循 MVVM 模式
  • 编码简洁,体积小,运行效率高,适合移动/PC端开发
  • 它本身只关注 UI ,也可以引入其它第三方库开发项目

1.2 Vue 安装

1.2.1 <script> 引入

直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量。

  <!-- 引入vue.js文件 -->
  <script src="./vue.js"></script>

1.2.2 CDN 引入

使用 CDN 方式引入:

  <!-- CDN引入 -->
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>

1.2.3 NPM 安装

  项目初始化:npm init -y  // 初始化 package.json 文件
  执行命令:npm i vue@2.6.14 --save / npm i vue@2.6.14 -S

1.3 初识 Vue

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初识Vue</title>
</head>
<body>
    <!--
      初识Vue:
        1. 想让 Vue 工作,就必须创建一个 Vue 实例,且要传入一个配置对象
        2. root 容器里的代码依然符合 html 规范,只不过混入了一些特殊的 Vue 语法
        3. root 容器里的代码被称为【Vue 模板】
        4. Vue 实例和容器是一一对应的
        5. 真实开发中只有一个Vue实例,并且会配合着组件一起使用
        6. `{{xxx}}` 中的 `xxx` 要写js表达式,且 `xxx` 可以自动读取到data中的所有属性
        7. 一旦 data 中的数据发生改变,那么页面中用到该数据的地方也会自动更新
    -->
    
    <!-- 准备好一个容器 -->
    <div id="root">
        <h1>你好,{{name}}</h1>
    </div>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <script>
        // 创建Vue实例
        new Vue({
            el: '#root', // el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            data:{ // data中用于存储数据,数据供el所指定的容器去使用
                name:'张三' 
            }
        })
    </script>
</body>
</html>

注意事项:

  • 不要把 vue 挂载在 html 和 body 标签上,挂载在正常的元素上
  • vue 实例只能作用于一个元素节点上,所以建议使用 id 选择器

1.4 模板语法

1.4.1 模板的理解

html 中包含了一些 JS 语法代码,语法分为两种,分别为:

  • 插值语法(双括号表达式)
  • 指令(以 v- 开头)

1.4.2 插值语法

vue 提供的 {{ }} 语法,专门用来解决 v-text 会覆盖默认文本内容的问题。这种 {{ }} 语法的专业名称是插值表达式(英文名为:Mustache)。

  • 功能:用于解析标签体内容
  • 语法:{{xxx}},xxx 会作为 js 表达式解析
<!-- 使用 {{ }} 插值表达式,将对应的值渲染到元素的内容节点中 -->
<!-- 同时保留元素自身的默认值 -->
<p>姓名:{{username}}</p>
<p>性别:{{gender}}</p>

<script>
	const vm = new Vue({
        el:'#app',
        data:{
            username:'张三',
            gender:'女'
		}
    })
</script>

1.4.3 指令语法

  • 功能:解析标签属性、解析标签体内容,绑定事假
  • 举例:v-bind:href = "xxx",xxx 会作为 js 表达式被解析
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        Vue模板语法有2大类:
          1.插值语法:
            功能:用于解析标签体内容。
            写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
          2.指令语法:
            功能:用于解析标签(包括:标签属性、标签体内容、绑定事件...)。
            举例:v-bind:href="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式,
                  且可以直接读取到data中的所有属性。
     -->

    <div id="root">
        <h1>插值语法</h1>
        <h3>你好,{{name}}</h3>
        <hr/>
        <h1>指令语法</h1>
        <a v-bind:href="url">百度一下,你就知道</a>
        <a :href="game.url">4399小游戏,等你来玩</a>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                name:'张三',
                url:'http://www.baidu.com',
                game:{
                    url:'http://www.4399.com'
                }
            }
        })
    </script>
</body>
</html>

1.4.4 指令的概念

指令(Directives)是 vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。

vue 中的指令按照不同的用途可以分为如下 6 大类:

1. 内容渲染指令 
2. 属性绑定指令 
3. 事件绑定指令
4. 双向绑定指令
5. 条件渲染指令
6. 列表渲染指令 

注意:指令是 vue 开发中最基础、最常用、最简单的知识点。


1.5 数据绑定

1.5.1 单向数据绑定

  • 语法:v-bind:href="xxx" 或简写为 :href
  • 特点:数据只能从 data 流向页面

数据驱动视图:页面数据发生变化时,页面会自动重新渲染!
数据驱动视图


1.5.2 双向数据绑定

在填写表单时,双向数据绑定可以辅助开发者在不操作 DOM 的前提下,自动把用户填写的内容同步到数据源中。

  • 语法:v-model:value="xxx" 或简写为 v-model="xxx"
  • 特点:数据不仅能从 data 流向页面,还能从页面流向 data

示例图如下:

在这里插入图片描述

注意:数据驱动视图和双向数据绑定的底层原理是 MVVM(Mode 数据源、View 视图、ViewModel 就是 vue 的实例)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        Vue中有2种数据绑定的方式:
          1.单向绑定(v-bind):数据只能从data流向页面。
          2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
        备注:
          1.双向绑定一般都应用在表单类元素上(如:input、select等)
          2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
     -->

    <!-- 准备好一个容器 -->
    <div id="root">
        <!-- 普通写法 -->
        单向数据绑定:<input type="text" v-bind:value="name">
        双向数据绑定:<input type="text" v-model:value="name">
        <!-- 简写 -->
        单向数据绑定:<input type="text" :value="name">
        双向数据绑定:<input type="text" v-model="name">

        <!-- 如下代码时错误的,因为v-model只能应用在表单类元素(输入类元素)上 -->
        <h2 v-model:x="name">你好</h2>
    </div>

    <script>
        new Vue({
            el: '#root',
            data: {
                name: '张三'
            }
        })
    </script>
</body>
</html>

1.5.3 指令修饰符

为了方便对用户输入的内容进行处理,vue 为 v-model 指令提供了 3 个修饰符,分别是:

修饰符作用实例
.number自动将用户的输入值转为数值类型<input v-model.number="age">
.trim自动过滤用户输入的首尾空白字符<input v-model.trim="msg">
.lazy在"change"时而非"input"时更新<input v-model.lazy="msg">

实例用法如下:

<input type="text" v-model.number="n1">+
<input type="text" v-model.number="n2">=
<span>{{n1 + n2}}</span>

1.5.4 el与data的两种写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>el与data的两种写法</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        el与data的2种写法:
          1.el有2种写法
            (1) new Vue的时候配置el属性。
            (2) 想创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
          2.data有2种写法
            (1) 对象式
            (2) 函数式
            如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
          3.一个重要的原则:
            由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
     -->

     <div id="root">
        <h1>你好,{{name}}</h1>
     </div>

     <script>
        // el的两种写法
        // const v = new Vue({
        //     // el:'#root', // 第一种写法
        //     data:{
        //         name:'张三'
        //     }
        // })
        // console.log(v)
        // v.$mount('#root') // 第二种写法

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

            // data的第二种写法:函数式
            data(){
                console.log('@@@',this) // 此处this是Vue实例对象
                return{
                    name:'张三'
                }
            }
        })
     </script>
</body>
</html>

1.5.5 MVVM 模型

MVVM 是 vue 实现数据驱动视图双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel, 它把每个 HTML 页面都拆分成了这三个部分,如图所示:

  • M:模型(Model) :对应 data 中的数据
  • V:视图(View) :模板
  • VM:视图模型(ViewModel) : Vue 实例对象

在这里插入图片描述

在 MVVM 概念中: Model 表示当前页面渲染时所依赖的数据源。 View 表示当前页面所渲染的 DOM 结构。 ViewModel 表示 vue 的实例,它是 MVVM 的核心。


1.5.6 MVVM 的工作原理

ViewModel 作为 MVVM 的核心,是它把当前页面的数据源(Model)和页面的结构(View)连接在了一起。
在这里插入图片描述

  • 数据源发生变化时,会被 ViewModel 监听到,VM 会根据最新的数据源自动更新页面的结构

  • 表单元素的值发生变化时,也会被 VM 监听到,VM 会把变化过后最新的值自动同步到 Model 数据源中


1.6 事件处理

1.6.1 绑定监听

vue 提供了 v-on 事件绑定指令,用来辅助程序员为 DOM 元素绑定事件监听。语法格式如下:

  • 语法:v-on:事件类型="事件方法名"
  • 简写:@事件类型="事件方法名"

注意:原生DOM对象有 onclick、oninput、onkeyup 等原生事件,替换为 vue 的事件绑定形式后, 分别为:v-on:click、v-on:input、v-on:keyup


通过 v-on 绑定的事件处理函数,需要在 methods 节点中进行声明:

	<div id="app">
		<!-- 
			语法:
				v-on:事件类型="事件方法名"
			简写:
				@事件类型="事件方法名"
		-->
		<button v-on:click="fn">点击</button>
		<button v-on:click="fn()">点击</button>
		<button v-on:click="fn(666)">点击</button>
		<button @click="fn(666)">点击</button>
	</div>
    <script>
        // 实例化vue
        new Vue({
            el:'#app',
            data:{  // 数据
            },
            methods:{ // 方法
                fn(num){
                    console.log(num);
                    console.log('我被点击了');
                } 
            }
        });
    </script>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件的基本使用</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        事件的基本使用:
          1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名
          2.事件的回调需要配置在methods对象中,最终会在vm上
          3.methods中配置的函数,不需要用箭头函数!否则this就不是vm了
          4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
          5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参
     -->
    <!-- 准备好一个容器 -->
    <div id="root">
        <h2>你好,{{name}}</h2>
        <button v-on:click="showInfo1">点我提示信息(不传参)</button>
        <button @click="showInfo2($event,66)">点我提示信息(传参)</button>
    </div>
    <script>
        const vm = new Vue({
            el:'#root',
            data:{
                name:'张三'
            },
            methods:{
                showInfo1(event){
                    console.log(event);
                    alert('这是第一条提示信息');
                },
                showInfo2(number){
                    console.log(number);
                    console.log(this); // 此处this是vm
                    alert('这是第二条提示信息');
                }
            }
        })
    </script>
</body>
</html>

1.6.2 $event

$event 是 vue 提供的特殊变量,用来表示原生的事件参数对象 event。$event 可以解决事件参数对象 event 被覆盖的问题

两种方式:

  • 隐式获取:不需要传递任何参数,在形参中直接获取 event 事件源对象
  • 显式获取:实参中通过 $event 传递,在形参中直接接收

注意事项:如果传递多个参数同时获取事件源对象,需要通过显式来获取

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <!-- 隐式获取event对象 -->
        <button @click="getEvent">隐式获取event事件对象</button>
        <!-- 显示获取event事件对象 -->
        <button @click="getEvent($event)">显示获取event事件对象</button>
        <!-- 参数中传递多个参数同时获取事件源对象 -->
        <button @click="getParam(10,$event,20)">传递多个参数</button>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {},
            methods: {
                getEvent(e) {
                    console.log(e);
                },
                getParam(num1, num2, e) {
                    console.log(num1)
                    console.log(num2)
                    console.log(e)
                }
            }
        })
    </script>
</body>
</html>

1.6.3 事件修饰符

在事件处理函数中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。因此,vue 提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。常用的 5 个事件修饰符如下:

事件修饰符说明
.prevent阻止事件默认行为(例如:阻止 a 连接的跳转、阻止表单的提交等)
.stop阻止事件冒泡
.capture以捕获模式触发当前的事件处理函数
.once绑定的事件只触发1次
.self只有在 event.target 是当前元素自身时触发事件处理函数
.passive事件的默认行为立即执行,无需等待事件回调执行完毕
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件修饰符</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
    <style>
        *{
            margin-top:20px;
        }
        .demo1{
            height:50px;
            background-color: skyblue;
        }
        .box1{
            padding:5px;
            background-color: skyblue;
        }
        .box2{
            padding:5px;
            background-color: orange;
        }
        .list{
            width: 200px;
            height:200px;
            background-color: peru;
            overflow: scroll;
        }
        li{
            height: 100px;
        }
    </style>
</head>
<body>
    <!-- 
        Vue中的事件修饰符:
            1.prevent:阻止默认事件(常用)
            2.stop:阻止事件冒泡(常用)
            3.once:事件只触发一次(常用)
            4.capture:使用事件的捕获模式
            5.self:只有event.target是当前操作的元素时才触发事件
            6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕
     -->

     <!-- 准备好一个容器 -->
     <div id="root">
        <h2>欢迎来到{{name}}</h2>
        <!-- 阻止默认事件(常用) -->
        <a href="http://www.baidu.com" @click.prevent="showInfo">百度一下,你就知道</a>

        <!-- 阻止事件冒泡(常用) -->
        <div class="demo1" @click="showInfo">
            <button @click.stop="showInfo">点我提示信息</button>
        </div>

        <!-- 事件只触发一次(常用) -->
        <button @click.once="showInfo">点我提示信息(触发一次)</button>

        <!-- 使用事件的捕获模式 -->
        <div class="box1" @click.capture="showMsg(1)">
            box1
            <div class="box2" @click="showMsg(2)">box2</div>
        </div>

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

        <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕 -->
        <ul class="list" @scroll.passive="demo">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
     </div>
     <script>
        new Vue({
            el:'#root',
            data:{
                name:'清华大学'
            },
            methods:{
                showInfo(e){
                    alert('你好,张三');
                },
                showMsg(n){
                    console.log(n);
                },
                demo(){
                    console.log('@');
                }
            }
        })
     </script>
</body>
</html>

1.6.4 按键修饰符

在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符

  • .enter:回车键 – 13
  • .left:左键 – 37
  • .up:上键 – 38
  • .right:右键 – 39
  • .down:下键 – 40
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <!-- 
            1.Vue中常用的按键别名:
	            回车 => enter
	            删除 => delete(捕获“删除”和“退格”键)
	            退出 => esc
	            空格 => space
	            换行 => tab(特殊:必须配合keydown使用)
	            上 => up
	            下 => down
	            左 => left
	            右 => right
        
        	2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

        	3.系统修饰键(用法特殊):ctrl、alt、shift、meta
            	(1) 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
            	(2) 配合keydown使用:正常触发事件。
        
        	4.也可以使用keyCode去指定具体的按键(不推荐)

        	5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
         -->
        <input type="text" placeholder="回⻋" @keydown.enter="enter">
        <input type="text" placeholder="回⻋" @keydown.13="enter">
        <hr>
        <input type="text" placeholder="左键" @keydown.left="left">
        <input type="text" placeholder="左键" @keydown.37="left">
        <hr>
        <input type="text" placeholder="上键" @keydown.up="up">
        <input type="text" placeholder="上键" @keydown.38="up">
        <hr>
        <input type="text" placeholder="右键" @keydown.right="right">
        <input type="text" placeholder="右键" @keydown.39="right">
        <hr>
        <input type="text" placeholder="下键" @keydown.down="down">
        <input type="text" placeholder="下键" @keydown.40="down">
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {},
            methods: {
                enter() {
                    console.log('回⻋');
                },
                left() {
                    console.log('left');
                },
                up() {
                    console.log('up');
                },
                right() {
                    console.log('right');
                },
                down() {
                    console.log('down');
                }
            }
        })
    </script>
</body>
</html>

1.7 计算属性与监视

1.7.1 计算属性-computed

计算属性指的是通过一系列运算之后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或 methods 方法使用。

  • 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性
  • 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算

实例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例_计算属性实现</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        计算属性:
            1.定义:要用的属性不存在,要通过已有的属性计算得来。
            2.原理:底层借助了Object.defineproperty方法提供的getter和setter。
            3.get函数什么时候执行?
                (1)初次读取时会执行一次。
                (2)当依赖的数据发生改变时会再次被调用。
            4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
            5.备注:
                1.计算属性最终会出现在vm上,直接读取使用即可。
                2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
     -->
    <!-- 准备好一个容器 -->
    <div id="root">
        姓:<input type="text" v-model="firstName"><br/>
        名:<input type="text" v-model="lastName"><br/>
        全名:<span>{{fullName}}</span>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三'
            },
            computed:{
                // 完整写法
                // fullName:{
                //     // 当有人读取fullName时,get就会被调用,且返回值就作为fullName的值。
                //     // get什么时候被调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
                //     get(){
                //         console.log('get被调用了',this);
                //         return this.firstName + this.lastName
                //     },
                //     // set什么时候被调用?当fullName被修改时。
                //     set(value){
                //         console.log('set',value);
                //         const arr = value.split('-')
                //         this.firstName = arr[0]
                //         this.lastName = arr[1]
                //     }
                // }
                // 只读不改简写
                fullName(){
                    console.log('get被调用了');
                    return this.firstName + this.lastName
                }
            }
        })
    </script>
</body>
</html>

1.7.2 监视属性-watch

watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。


普通监听:

监听一般的数据类型:监听 data 数据的改变,从而做出相应的操作

  • 1、当被监视的属性变化时,回调函数自动调用,进行相关操作
  • 2、该方法中系统自动注入两个参数newValue,oldValue
  • 3、在普通监听中可以获取最新值和旧值
  • 4、监视的属性必须存在,才能进行监视
  • 5、监视的两种写法:
    • (1) new Vue时传入 watch 配置
    • (2) 通过 vm.$watch 监视

案例一:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例_监视属性</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        监视属性watch:
          1.当被监视的属性变化时,回调函数自动调用,进行相关操作
          2.监视的属性必须存在,才能进行监视
          3.监视的两种写法:
            (1)new Vue时传入watch配置
            (2)通过vm.$watch监视
     -->

    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
        <!-- <button @click="isHot = !isHot">切换天气</button> -->
        <button @click="changeWeather">切换天气</button>
    </div>
    <script>
        const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
            x:1
        },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot:{
                immediate:true, // 初始化时让handler调用一下
                // 当isHot发生改变时,handler会被调用
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue);
                }
            }
        }
    })
    vm.$watch('info',{
        immediate:true, // 初始化时让handler调用一下
        // 当isHot发生改变时,handler会被调用
        handler(newValue,oldValue){
            console.log('info被修改了',newValue,oldValue);
        }
    })
    </script>
</body>
</html>

案例二:

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <input type="text" v-model="name">
        <div>{{name}}</div>
        <hr>
        <input type="text" v-model="age">
        <div>{{age}}</div>
        <hr>
        <input type="text" v-model="arr[1]">
        <div>{{arr[1]}}</div>
        <hr>
        <input type="text" v-model="obj.name">
        <div>{{obj.name}}</div>
    </div>

    <script>
        // 3.实例化vue
        new Vue({
            el: '#app',
            data: {
                name: '张三',
                age: 18,
                arr: ['长沙', '臭豆腐', '橘子洲', '糖油粑粑'],
                obj: {
                    name: '张三'
                }
            },
            // watch 监听data数据
            watch: {
                /**
                  1.系统会自动注入两个参数:newVal和oldVal
                  2.在普通监听中是可以获取到新值和旧值
                  3.数组只有新值,没有旧值
                **/
                name(newVal, oldVal) {
                    console.log(newVal, oldVal);
                },
                age(newVal, oldVal) {
                    console.log(newVal, oldVal);
                },
                // 只有新值,没有旧值
                arr(newVal) {
                    console.log(newVal);
                },
                obj(newVal, oldVal) {
                    console.log(newVal);
                }
            }
        })
    </script>
</body>
</html>

深度监听:

如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选项,代码示例如下:

const vm = new Vue({
    el: '#app',
    data: {
        info:{ username: 'admin' }
    },
    watch: {
        info: {
            //   handler 是固定写法,表示当username的值变化时,自动调用handler处理函数
            hanlder(newVal) {
                console.log(newVal.username)
            },
            deep: true
        }
    }
})
  • Vue 中的 watch 默认不监测对象内部值的改变(一层)
  • 配置 deep:true 可以监测对象内部值改变(多层)

备注:
(1) Vue 自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以。
(2) 使用 watc h时根据数据的具体结构,决定是否采用深度监视。

案例一:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例_深度监视</title>
    <!-- 引入Vue -->
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        深度监视:
            (1)Vue中的watch默认不监测对象内部值的改变(一层)
            (2)配置deep:true可以监测对象内部值改变(多层)
        备注:
            (1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
            (2)使用watch时根据数据的具体结构,决定是否采用深度监视。
     -->
    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="changeWeather">切换天气</button>
        <hr>
        <h2>a的值是:{{numbers.a}}</h2>
        <button @click="numbers.a++">点击a++</button>
    </div>
    <script>
        const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
            numbers:{
                a:1,
                b:1
            }
        },
        computed:{
            info(){
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot:{
                immediate:true, // 初始化时让handler调用一下
                // 当isHot发生改变时,handler会被调用
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue);
                }
            },
            // 简写
            /*
                isHot(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue);
                }
            */
            numbers:{
                deep:true,
                handler(){
                    console.log('numbers改变了')
                }
            }
        }
    })
    // 简写
    vm.$watch('isHot',(newValue,oldValue)=>{
        console.log('isHot被修改了',newValue,oldValue);
    })
    </script>
</body>
</html>

案例二:

  • 监听对象只能使用深度监听
  • 深度监听的方法必须是handler
  • 必须是deep: true作为深度监听
  • 在深度监听中无法监听旧值,因为初始设计中没有保存旧值
  • 深度监听只能获取最新值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>
<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <input type="text" v-model="person.name">
        <div>{{person.name}}</div>
    </div>
    <script>
        // 3.实例化vue
        new Vue({
            el: '#app',
            data: {
                person: {
                    name: '张三'
                }
            },
            /**
             * 监听对象必须是深度监听
             * 深度监听的方法必须是handler
             * 必须是deep:true
             * 在深度监听中无法监听旧值,因为初始化设计没有旧值
             * 在深度监听中只能获取新值
            **/
            watch: {
                person: {
                    handler(newVal) {
                        console.log(newVal)
                        console.log(this.person.name)
                    },
                    deep: true, //深度 默认false
                }
            }
        })
    </script>
</body>
</html>

监听对象单个属性:

如果只想监听对象中单个属性的变化,则可以按照如下的方式定义 watch 侦听器:

const vm = new Vue({
    el: '#app',
    data: {
        info:{ username: 'admin' }
    },
    watch: {
        'info.username': {
            hanlder(newVal) {
                console.log(newVal)
            }
        }
    }
})

1.7.3 computed 与 watch 的区别

  • computed 能完成的功能,watch 都可以完成。
  • watch 能完成的功能,computed 不一定能完成,例如:watch 可以进行异步操作。

两个重要的小原则:
1. 所被Vue管理的函数,最好写成普通函数,这样 this 的指向才是vm或组件实例对象。
2. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。


1.7.4 computed 与 methods 的区别

相同点:

  • 都可以执行操作
  • 结果都是一致的

不同点:

  • methods:调用几次,就执行几次,当数据发生改变时,再次被执行
  • computed:computed 有缓存功能,不管调用几次,最终使用的都是第一次的执行结果。当数据发生改变时,再次执行一次。

应用场景:

  • methods 中执行的一般是事件操作
  • computed 用来执行一些复杂的逻辑操作,并且有返回值

1.8 class 与 style 绑定

在应用界面中,某个(些)元素的样式是变化的,class/style 绑定就是专门用来实现动态样式效果的技术。

class样式:
语法:class="xxx" xxx可以是字符串、对象、数组。

字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

style样式:
语法:

  • :style="{fontSize: xxx}" 其中xxx是动态值。
  • :style="[a,b]" 其中a、b是样式对象。

案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绑定样式</title>
    <script src="../js/vue.js"></script>
</head>
<body>
    <!-- 
        绑定样式:
            1.class样式
                写法:class="xxx" xxx可以是字符串、对象、数组。
                    字符串写法适用于:类名不确定,要动态获取。
                    对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
                    数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
            2.style样式
                :style="{fontSize: xxx}" 其中xxx是动态值。
                :style="[a,b]" 其中a、b是样式对象。
     -->
    <div id="root">
        <!-- 绑定class样式--字符串写法,适用于:样式类名不确定,需要动态指定 -->
        <div class="basic" :class="mood" @click="changeMood">{{name}}</div><br/>

        <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
        <div class="basic" :class="classArr">{{name}}</div><br/>

        <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
        <div class="basic" :class="classObj">{{name}}</div><br/>

        <!-- style--对象写法 -->
        <div class="basic" :style="styleObj">{{name}}</div><br/>

        <!-- 绑定style样式--数组写法 -->
        <div class="basic" :style="styleArr">{{name}}</div><br/>
    </div>
    <script>
        const vm = new Vue({
            el:'#root',
            data:{
                name:'张三',
                mood:'normal',
                classArr:['box1','box2','box3'],
                classObj:{
                    box1:false,
                    box2:false
                },
                styleObj:{
                    fontSize:'40px',
                    color:'red'
                },
                styleObj2:{
                    backgroundColor:'orange'
                },
                styleArr:[
                    {
                        fontSize:'40px',
                        color:'blue'
                    },
                    {
                        backgroundColor:'gray'
                    }
                ]
            }
        })
    </script>
</body>
</html>

1.9 条件渲染

1.9.1 条件渲染指令

条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:v-ifv-show

1.9.1.1 v-if
  • v-else:v-if 可以单独使用,或配合 v-else 指令一起使用
  • v-else-if:v-else-if 指令,顾名思义,充当 v-if 的 “else-if 块”,可以连续使用

适用于:切换频率较低的场景。
特点:不展示的 DOM 直接被移除。

<div id="app">
    <!-- 
        v-if="表达式" 
        v-else-if="表达式" 
        v-else="表达式" 
        以上三个指令在使用过程中,不能出现其他的内容,一旦出现,则指令不再生效
     -->
    <div v-if="score < 60"> 不及格 </div>
    <!--<div>score的值为:{{score}}</div>-->
    <div v-else-if="score >= 60 && score < 80"> 及格 </div>
    <div v-else="score >= 80"> 优秀 </div>
</div>

<script>
    // 3. 实例化vue
    new Vue({
        el:'#app',
        data:{ 
            score:60,
        }
    })
</script>

注意:v-else-ifv-else 指令必须配合 v-if 指令一起使用,否则它将不会被识别,且要求结构不能被“打断”。


1.9.1.2 v-show
  • 语法:v-show="表达式"
  • 适用于:切换频率较高的场景。
  • 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>

    <div id="app">
        <div v-show="score >= 60 && score < 80">(测试v-show)及格</div>
    </div>

    <script> 
        new Vue({
            el:'#app',
            data:{ 
                score: 90,
            }
        });
        
    </script>
    
</body>
</html>

1.9.2 v-if 与 v-show 的区别

实现原理不同:

  • v-if 指令会动态地创建或移除 DOM 元素,从而控制元素在页面上的显示与隐藏;

  • v-show 指令会动态为元素添加或移除 style=“display: none;” 样式,从而控制元素的显示与隐藏;

使用 v-if 时,元素可能无法获取到,而使用 v-show 一定可以获取到。


性能消耗不同:

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此:

  • 如果需要非常频繁地切换,则使用 v-show 较好

  • 如果在运行时条件很少改变,则使用 v-if 较好


1.10 列表渲染

1.10.1 v-for

vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。v-for 指令需要使用 item in items 形式的特殊语法,其中:

  • items 是待循环的数组
  • item 是被循环的每一项
data:{
	list:[
		{id: 1, name: 'zs'},
		{id: 2, name: 'ls'},
	]
}

//---------------------------------------------------

<ul>
    <li v-for="item in list">姓名是:{{item.name}}</li>
</ul>

1.10.2 index 索引

v-for 指令还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items,示例代码如下:

data:{
	list:[
		{id: 1, name: 'zs'},
		{id: 2, name: 'ls'},
	]
}

//---------------------------------------------------

<ul>
    <li v-for="(item,index) in list">姓名是:{{item.name}},索引是:{{index}}</li>
</ul>

注意:v-for 指令中的 item 项index 索引都是形参,可以根据需要进行重命名。例如:(user, i) in userlist


1.10.3 key

当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。

为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的 key 属性

用户列表区域
<ul>
    加 key 属性的好处:
    1. 正确维护列表的状态
    2. 复用现有的 DOM 元素,提升渲染的性能
    <li v-for="user in userlist" :key="user.id">
    	<input type="checkbox">
        姓名:{{user.name}}
    </li>
</ul>

key 的注意事项:

  1. key 的值只能是字符串数字类型

  2. key 的值必须具有唯一性(即:key 的值不能重复)

  3. 建议把数据项 id 属性的值作为 key 的值(因为 id 属性的值具有唯一性)

  4. 使用 index 的值当作 key 的值没有任何意义(因为 index 的值不具有唯一性)

姓名是:{{item.name}},索引是:{{index}}

```

注意:v-for 指令中的 item 项index 索引都是形参,可以根据需要进行重命名。例如 (user, i) in userlist


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

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

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

            2.旧虚拟DOM中未找到与新虚拟DOM相同的key:
                创建新的真实DOM,随后渲染到页面。

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

1.11 内容渲染指令

内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:

  • v-text
  • {{ }}
  • v-html

1.11.1 v-text

用法示例:

<!-- 把 username 对应的值,渲染到第一个 p 标签中-->
<p v-text="username"></p>

<!-- 把 gender 对应的值,渲染到第二个 p 标签中 -->
<!-- 注意:第二个p标签中,默认的文本“性别”会被gender的值覆盖掉 -->
<p v-text="gender">性别</p>

<script>
	const vm = new Vue({
        el:'#app',
        data:{
            username:'张三',
            gender:'女'
		}
    })
</script>

注意:v-text 指令会覆盖元素内默认的值


1.11.2 v-html

​ v-text 指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素, 则需要用到 v-html 这个指令:

<!-- 假设 data中定义了名为 discription 的数据,数据的值为包含HTML 标签的字符串: -->
<!-- '<h5 style="color: red;">我在黑马程序员学习vue.js课程。</h5>' -->

<p> v-html="discription"></p>

<script>
	const vm = new Vue({
        el:'#app',
        data:{
            username:'zs',
            gender:'男',
            discription: '<h5 style="color: red;">我在黑马程序员学习vue.js课程。</h5>'
		}
    })
</script>

1.11.3 v-once

v-once:只渲染一次,当前元素及以下的所有子元素都只渲染一次

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src='./vue.js'></script>
</head>
<body>

    <!-- 2. 创建DOM元素 -->
    <div id="app" v-once>
        <button @click="changeName('朱天旭')">点击修改name的值</button>
        <div>name的值为:{{name}}</div>
    </div>

    <script>
        // 3.实例化vue
        new Vue({
            el:'#app',
            data:{ 
                name:'朱砂痣'
            },
            methods:{ 
                changeName(name){
                    console.log(name)
                    this.name = name;
                }
            }
        })
    </script>    
</body>
</html>

1.12 $set

在 vue 中,并不是任何时候数据都是双向绑定的。

由于 JavaScript 的限制,Vue不能检测对象属性的添加或删除

从文档得知,当数据没有被双向绑定的时候,我们就需要使用set了。


1.12.1 set 用法

解决数据没有被双向绑定我们可以使用 vm.$set 实例方法,

该方法是全局方法 Vue.set 的一个别名。

方法一:this.$set(目标对象, 索引值, 需要赋的值)

方法二:Vue.set(目标对象,下标/属性,值/属性值)

length 的问题还需要用 splice 方法。

vm.items.splice(newLength)

1.12.2 $set 操作数组

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <div>{{arr}}</div>
        <button @click="add">添加'🚀'</button>
    </div>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                arr: ['🍎', '🍇', '🍑', '🍌']
            },
            methods: {
                add() {
                    // 系统函数
                    // this.arr.push('🚀');
                    // this.arr[4] = '🚀'; // 不可取

                    // 方式一 this.$set(目标,下标,添加的值)
                    this.$set(this.arr,4,'🚀');

                    // 方式二:Vue.set(目标,下标,添加的值)
                    // Vue.set(this.arr, 4, '🚀');
                    console.log(this.arr);
                }
            }
        })
    </script>
</body>

</html>

1.12.3 $set 操作对象

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <div>{{person}}</div>
        <button @click="addSex">添加性别</button>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                person: {
                    name: '张三',
                    age: 20,
                    hobby: ['吃饭', '睡觉', '打豆豆'],
                }
            },
            methods: {
                addSex() {
                    // this.person.sex = '男'; //不可取

                    // 方式一:this.$set(目标,属性,添加的值)
                    // this.$set(this.person,'sex','男');

                    // 方式二:Vue.set(目标,属性,添加的值)
                    Vue.set(this.person, 'sex', '男');
                    console.log(this.person);
                }
            }
        })
    </script>
</body>

</html>

1.12.4 $set 操作数组对象

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <button @click="getData">显示数据</button>
        <ul>
            <li v-for="(item,index) in list" :key="item.id">
                {{item.name}} === {{item.sex}} <button @click="addSex(index)">添加性别</button>
            </li>
        </ul>
    </div>
    <script>
        let arr = [
            { id: 1, name: '张三' },
            { id: 2, name: '李斯' }
        ]
        new Vue({
            el: '#app',
            data: {
                list: []
            },
            methods: {
                getData() {
                    this.list = arr;
                },
                addSex(index) {
                    // this.list[index].sex = '男';

                    // 方式一:this.$set(目标,属性/下标,添加的值)
                    // let obj = this.list[index];      // {id:1,name:'张三'}
                    // obj.sex = '男';                  // {id:1,name:'张三',sex:'男'}
                    // this.$set(this.list,index,obj); // [{id:1,name:'张三',sex:'男'}]

                    // 方式二:Vue.set(目标,属性/下标,添加的值)
                    // let obj = this.list[index]; 
                    // obj.sex = '男'; 
                    // Vue.set(this.list, index, obj);

                    // 方式三:
                    let obj = this.list[index];
                    obj.sex = '男';
                    this.list.splice(index, 1, obj);
                    console.log(this.list);
                }
            }
        })
    </script>
</body>

</html>

1.13 过滤器

1.13.1 概念

过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式v-bind 属性绑定。
过滤器应该被添加在 JavaScript 表达式的尾部,由 “管道符” 进行调用,示例代码如下:

<!-- 在双花括号中通过“管道符”调用 capitalize 过滤器,对 message 的值进行格式化 -->
<p>{{message | capitalize}}</p>

<!-- 在 v-bind 中通过“管道符”调用 formatId 过滤器,对 rawId 的值进行格式化 -->
<div v-bind:id="rawId | formatId"></div>

1.13.2 定义过滤器

在创建 vue 实例期间,可以在 filters 节点中定义过滤器,示例代码如下:

  • 每一个过滤器的方法为自定义
  • 系统自动注入一个参数:要过滤的对象
  • 每一个过滤器方法中必须有return,其返回的结果被方法名所接收
const vm = new Vue({
    el:'#app',
    data:{
        message:'hello vue.js',
        info:'title info'
    },

    filters:{   // 在 filters 节点下定义“过滤器”
        capitalize(str){    // 把首字母转为大写的过滤器
            return str.charAt(0).toUpperCase() + str.slice(1)
        }
    }
})

1.13.3 全局过滤器

filters 节点下定义的过滤器,称为“私有过滤器”,因为它只能在当前 vm 实例所控制的 el 区域内使用
如果希望在多个 vue 实例之间共享过滤器,则可以按照如下的格式定义全局过滤器

// 全局过滤器 - 独立于每个 vm 实例之外
// Vue.filter() 方法接收两个参数:
// 第 1 个参数,是全局过滤器的“名字”
// 第 2 个参数,是全局过滤器的“处理函数”

Vue.filter('capitalize',(str)=>{
    return str.charAt(0).toUpperCase() + str.slice(1) + '~~'
})

1.13.4 连续调用多个过滤器

过滤器可以串联地进行调用,例如:

<!-- 把 message 的值,交给 filterA进行处理 -->
<!-- 把 filterA 处理的结果,再交给 filterB 进行处理 -->
<!-- 最终把 filterB 处理的结果,作为最终的值渲染到页面上 -->
{{ message | filterA | filterB }}

示例代码如下:

<!-- 串联调用多个过滤器 -->
<p>{{text | capitalize | maxLength}}</p>

<script>
// 全局过滤器 – 首字母大写
Vue.filter('capitalize', (str) =>{
    return str.charAt(O).toUpperCase() + str.slice(1) + '~~'
})

// 全局过滤器 – 控制文本的最大长度
Vue.filter('maxLength', (str) => {
    if (str.length <= 10) return str
    return str.slice(011) + '...'
})
</script>

1.13.5 过滤器传参

过滤器的本质是 JavaScript 函数,因此可以接收参数,格式如下:

<!-- arg1 和 arg2 是传递给 filterA 的参数 -->
<p>{{ message | filterA(arg1,arg2) }}</p>

<script>
// 过滤器处理函数的形参列表中:
// 第 1 个参数:永远都是"管道符"前面待处理的值
// 从第 2 个参数开始,才是调用过滤器时传递过来的 arg1 和 arg2 参数
    
Vue.filter('filterA',(msg,arg1, arg2) => {
    // 过滤器的代码逻辑...
})
    
</script>

示例代码如下:

<!-- 调用 maxLength 过滤器时传参 -->
<p>{{text | capitalize | maxLength(5)}}</ p>

<script>
// 全局过滤器 - 首字母大写
Vue.filter('capitalize', (str) =>{
return str.charAt(O).toUpperCase() + str.slice(1) + '~~'})

//全局过滤器 – 控制文本的最大长度
Vue.filter('maxLength', (str, len = 10) => {
    if(str.length <= len) return str
    return str.slice(0,len) + '...'
})
</script>

1.13.6 封装时间过滤器

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>
    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <ul>
            <li v-for="item in news" :key="item.id">
                <div>新闻标题: {{item.title}}</div>
                <div>发布时间:{{item.time | timeFilter('x-x-x x:x:x')}}</div>
                <div>发布时间:{{item.time | timeFilter('x-x-x')}}</div>
            </li>
        </ul>
    </div>

    <script>
        // 时间过滤器
        // 时间格式:xx/xx/xx x:x:x || xxx-xx-xx
        Vue.filter('timeFilter', (e, type) => {
            let date = new Date(e);
            let y = date.getFullYear();
            let m = (date.getMonth() + 1 + '').padStart(2, '0');
            let d = (date.getDate() + '').padStart(2, '0');
            let h = (date.getHours() + '').padStart(2, '0');
            let i = (date.getMinutes() + '').padStart(2, '0');
            let s = (date.getSeconds() + '').padStart(2, '0');

            if (type === 'x-x-x x:x:x') {
                return `${y}-${m}-${d} ${h}:${i}:${s}`;
            } else if (type === 'x-x-x') {
                return `${y}-${m}-${d}`;
            }
        })

        // 3.实例化vue
        new Vue({
            el: '#app',
            data: {
                news: [
                    { id: 1, title: '哈萨克斯坦首都街头飘扬中国红', time: 1663224746000 },
                    { id: 2, title: '超六成专科生月薪低于5000元', time: 1665224746000 },
                    { id: 3, title: '公安部:车检周期10月1日起放宽', time: 1667224746000 },
                ]
            }
        })
    </script>
</body>

</html>

1.14 生命周期

1.14.1 定义

生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。
生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行

注意:生命周期强调的是时间段,生命周期函数强调的是时间点

image-20220918195840246

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJl0JwL9-1666016537531)(图片/image-20220921195005642.png)]


1.14.2 钩子函数

  • beforeCreate

    /* 
        创建之前
        什么都是undefined  
        不能操作元素          
    */
    beforeCreate(){
        console.group('==beforeCreate==');
        console.log('el的值',this.$el);
        console.log('data的值',this.$data);
        console.log('name的值',this.name);
        console.groupEnd();
    }
    
  • created

    /* 
        创建完成
        1.不能操作元素
        2.el还是undefined
        3.此时数据已经存在
        4.作用:实现异步请求
    */
     created(){
        console.group('==created==');
        console.log('el的值',this.$el);
        console.log('data的值',this.$data);
        console.log('name的值',this.name);
        console.groupEnd();
    }
    
  • beforeMount

    /* 
        挂载之前:beforeMount
        1.找到el挂载点
        2.此时数据已经存在
        3.实现异步请求
        4.可以操作元素
        5.视图中数据未解析
    */
    beforeMount(){
        console.group('==beforeMount==');
        console.log('el的值',this.$el);
        console.log('data的值',this.$data);
        console.log('name的值',this.name);
        console.groupEnd();
    }
    
  • mounted(重点)

    /* 
        挂载完成:mouted
        1.数据已经获取
        2.元素挂载点找到
        3.可以操作元素节点
        作用:异步请求 轮播图  定时器  延时器 订阅等等
      */
     mounted(){
        console.group('==mounted==');
        console.log('el的值',this.$el);
        console.log('data的值',this.$data);
        console.log('name的值',this.name);
        console.log(document.querySelector('h2'));
        console.groupEnd();
    },
    
  • beforeUpdate

    /* 
        更新之前
        数据已经是最新数据,指的是视图再次更新之前
     */
     beforeUpdate(){
        console.group('==beforeUpdate==');
        console.log('name的值',this.name);
        console.groupEnd();
    },
    
  • updated

    /* 
        更新完成
        数据已经是最新数据,指的是视图更新完成
     */
    updated(){
        console.group('==updated==');
        console.log('name的值',this.name);
        console.groupEnd();
    }
    
  • beforeDestroy

    /* 
        销毁之前
        作用:销毁数据
    */
     beforeDestroy(){
        console.group('==beforeDestroy==');
        console.groupEnd();
    }
    
  • destroyed

     /* 
    	销毁完成
    */
     destroyed(){
        console.group('==destroyed==');
        console.groupEnd();
    }
    

1.15 template 和 render 优先级问题

当 el、template、render 三个选项同时存在时,优先级:render > template > el

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

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!-- 1. 引入vue.js -->
    <script src="./vue.js"></script>
</head>

<body>

    <!-- 2. 创建DOM元素 -->
    <div id="app">
        <h2> {{name}}</h2>
    </div>

    <script>
        /**
         * 当el,template,render三个选项同时存在时,存在优先级 render > template > el
        */
        new Vue({
            el: '#app',
            template: '<h2>朱砂痣</h2>',
            /**
             *  钩子函数:
             *  系统自动注入一个参数:createElement 
             *  返回值 返回创建的元素信息
             */
            render(createElement) {
                /*
                    参数一:创建的元素节点
                    参数二:内容
                */
                return createElement('h2', '创建的标签')
            },
            data: {
                name: '张三丰'
            },
            methods: {

            }
        })
    </script>

</body>

</html>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值