2023/1/6 Vue学习笔记-1

news2024/12/23 17:11:54

尝试 Vue.js 最简单的方法是使用 Hello World 例子。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue:

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

1 声明式渲染-引入Hello案例

Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。
下面一个demo讲解:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="root">
    <h1>Hello - {{ message }}</h1>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let app = new Vue({
        el: '#root', // el用于指定当前Vue实例为哪个容器服务。
        data: {
            message: 'zhaoshuai@inspur.com'
        }
    })
</script>

</body>
</html>

在这里插入图片描述
我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 app.message 的值,你将看到上例相应地更新。(如上)

注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。

除了文本插值,我们还可以像这样来绑定元素 attribute:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app-2">
  <span v-bind:title="bindMessage">
      <h1>鼠标悬停几秒钟查看此处动态绑定的提示信息!</h1>
  </span>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    let app2 = new Vue({
        el: '#app-2',
        data: {
            bindMessage: '页面加载于 ' + new Date().toLocaleString()
        }
    })
</script>
</body>
</html>

在这里插入图片描述
这里我们遇到了一点新东西。你看到的 v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title attribute 和 Vue 实例的 message property 保持一致”。

property是DOM中的属性,是JavaScript里的对象;
attribute是HTML标签上的特性,它的值只能够是字符串;

如果你再次打开浏览器的 JavaScript 控制台,输入 app2.message = ‘新消息’,就会再一次看到这个绑定了 title attribute 的 HTML 已经进行了更新。
注意:

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

在这里插入图片描述

2 模板语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。

在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

2.1 插值

文本

数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

<span>Message: {{ msg }}</span>

Mustache 标签将会被替代为对应数据对象上 msg property 的值。无论何时,绑定的数据对象上 msg property 发生了改变,插值处的内容都会更新。

2.2 指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML attribute:

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

在这里 href 是参数,告知 v-bind 指令将该元素的 href attribute 与表达式 url 的值绑定。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="app-3">
    <a v-bind:href="url">百度一下</a>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    let app3 = new Vue({
        el: "#app-3",
        data: {
            url: 'https://www.baidu.com/'
        }
    })
</script>
</body>
</html>

在这里插入图片描述

<div id="app-3">
    <a :href="url">百度一下</a>
</div>

2.3 Vue模板语法有两大类:

1.插值语法:
	功能:用于解析标签体内容。
	写法:{{xxx}},xxx是JS表达式,且可以直接读取到data中所有属性。
	起始标签和结束标签中间夹的内容就是标签体
2.指令语法:
	功能:用于解析标签(包括:标签属性、标签体内容、绑定事件......)。
	举例:v-bind:href="xxx" 或写为 :href="xxx" ,xxx同样为JS表达式。
	Vue中有很多指令,且形式都是 v-??? ,此处的v-bind只是例子

3 数据绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="app-1">
<!--    单向绑定(v-bind):数据只能从data流向页面-->
    单项数据绑定: <input type="text" v-bind:value="name"> 
</div>

<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    new Vue({
        el: '#app-1',
        data: {
            name: 'zhaoshuai-lc@inpsur.com'
        }
    })
</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述
(1)双向绑定一般都应用在表单类元素上(都有value值)(如input、select等)。
(2)v-model:value 可以简写为 v-model,因为 v-model默认收集的就是value的值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="app-1">
    <!--    单向绑定(v-bind):数据只能从data流向页面-->
    单项数据绑定: <input type="text" v-bind:value="name"><br/>
    <!--    双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data-->
    双向数据绑定:<input type="text" v-model:value="name"><br/>
<!-- 备注:
    (1)双向绑定一般都应用在表单类元素上(都有value值)(如input、select等)。
    (2)v-model:value 可以简写为 v-model,因为 v-model默认收集的就是value的值。-->
</div>

<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    new Vue({
        el: '#app-1',
        data: {
            name: 'zhaoshuai-lc@inpsur.com'
        }
    })
</script>
</body>
</html>

v-model:value 可以简写为 v-model,因为 v-model默认收集的就是value的值

    <div>简写</div>
    单向数据绑定:<input type="text" :value="name"><br/>
    双向数据绑定:<input type="text" v-model="name"><br/>

4 el && data

data与el的两种写法

1.el有2种写法
(1)new Vue时候配置el属性。
(2)先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
 2.data有2种写法
(1)对象式
(2)函数式
如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
3.一个重要原则:
 由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。

1 el 两种写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="app-1">
    <div>你好,{{ name }}</div>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    let vm = new Vue({
        // el: '#app-1', // 第一种
        data: {
            name: 'zhaoshuai-lc@inspur.com'
        }
    })
    console.info(vm)
    // 2秒之后再指定值
    setTimeout(() => {
        vm.$mount('#app-1') // 第二种
    }, 2000)

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

在这里插入图片描述

2 data 的两种写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--准备好一个容器-->
<div id="app-1">
    <div>你好,{{ name }}</div>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
    let vm = new Vue({
        el: '#app-1',
        // 对象的第一种写法 对象式
        /*        data: {
                    name: 'zhaoshuai-lc@inspur.com'
                }*/
        // 对象的第二种写法 函数式
        // 由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了,而是window。
        // data: function () { 替换为
        data() {
            console.info('@@@', this) // 此处的this是Vue实例对象
            return {
                name: 'zhaoshuai-lc@inspur.com'
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

5 MVVM

虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。
在这里插入图片描述

原型上有的东西,插值中都可以随便用,如“$options”、“$emit”、“_c”等。也就是说,并不是data里面有的,DOM才可以直接用,而是data中的东西,最终在实例里面(VM中),所以都能在模板(V)中直接使用。

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

6 Object.defineProperty

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    let person = {
        name: 'zhaoshuai-lc',
        sex: 'male'
    }
    Object.defineProperty(person, 'age', {
        value: 18
    })

    console.log(person)
    for (let personKey in person) {
        console.log(person[personKey])
    }
</script>
</body>
</html>

在这里插入图片描述
age 是不可以被枚举的
在这里插入图片描述

    Object.defineProperty(person, 'age', {
        value: 18,
        enumerable:true, //控制属性是否可以枚举,默认值为false
    })

在这里插入图片描述
可以被枚举,但是不可以被修改
在这里插入图片描述

    Object.defineProperty(person, 'age', {
        value: 18,
        enumerable:true, //控制属性是否可以枚举,默认值为false
        writable:true, //控制属性是否可以被修改,默认值为false
        configurable:true //控制属性是否可以被删除,默认值为false
    })

get() set()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    let number = 19
    let person = {
        name: 'zhaoshuai-lc',
        sex: 'male'
    }
    Object.defineProperty(person, 'age', {
        // 当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
        get() {
            console.log('有人读取age属性了')
            return number
        },

        // 当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
        set(value){
            console.log('有人修改了age属性,且值是',value)
            number = value
        }
    })
    console.info("person", person)
    console.info("number", number)
</script>
</body>
</html>

在这里插入图片描述

7 理解数据代理

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script type="text/javascript">
    let obj1 = {
        x: 100
    }
    let obj2 = {
        y: 200
    }
    Object.defineProperty(obj2, 'x', {
        get() {
            return obj1.x
        },
        set(value) {
            obj1.x = value
        }
    })

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

在这里插入图片描述

8 Vue中的数据代理

将鼠标放到实例中的数据上,可以看到也提示了“Invoke property getter”。也就是说当有人访问name的时候,getter就在工作。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
vm._data === data 为ture。也就是说_data完全来自于data
在这里插入图片描述
创建了实例对象vm——Vue收集data数据——拿到vm后,Vue往vm上添加name、address(通过getter)

在这里插入图片描述
也就是说,Vue通过数据代理,把_data中的数据放到vm上。目的就是为了编码更方便。
_data中的东西不是数据代理,而是做了一个数据劫持。相当于是把data里面的东西做了修改/升级,以便更好地完成响应式操作。

1.Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:更加方便操作data中的数据
3.基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作(读/写)data中对应的属性。

9 事件处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app-1">
    <button v-on:click="showInfo">{{ name }}</button>
</div>

<script type="text/javascript">
    new Vue({
        el: '#app-1',
        data() {
            return {
                name: '点我提示信息'
            }
        },
        methods: {
            showInfo() {
                alert('Hello-zhaoshuai-lc@inspur.com')
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="root">
    <div>{{ name }}</div>
    <!-- <button v-on:click="showInfo">点我提示信息</button> -->
    <button @click="showInfo1">点我提示信息1(不传参)</button>
    <button @click="showInfo2(66,$event)">点我提示信息2(传参)</button>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vm = new Vue({
        el: '#root',
        data: {
            name: 'zhaoshuai-lc'
        },
        methods: {
            showInfo1(event) {
                console.log(event.target.innerText)
                console.log(this) //此处的this指的是vm
                alert('hello-zhaoshuai-lc@inspur.com')
            },
            showInfo2(number, event) {
                console.log(event.target.innerText)
                alert('HELLO-zhaoshuai-lc@inspur.com')
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
事件的基本使用:

1.使用 v-on:xxx 或者 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了(指向window);
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或者组件实例对象;
5. @click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参。

10 时间修饰符

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
    <style>
        * {
            margin: 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: auto;
        }

        li {
            height: 100px;
        }
    </style>
</head>
<body>
<div id="event">
    <!-- 阻止默认事件(常用) -->
    <a href="https://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vmEvent = new Vue({
        el: '#event',
        data: {},
        methods: {
            showInfo() {
                alert("hello-zhaoshuai-lc@inspur.com")
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
    <style>
        * {
            margin: 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: auto;
        }

        li {
            height: 100px;
        }
    </style>
</head>
<body>
<div id="event">
    <!-- 阻止默认事件(常用) -->
    <a href="https://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>

    <!-- 阻止事件冒泡(常用) 冒泡指的是从里到外 -->
    <div class="demo1" @click="showInfo_2">
        <button @click.stop="showInfo_1">点我提示信息</button>
    </div>

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vmEvent = new Vue({
        el: '#event',
        data: {},
        methods: {
            showInfo_1() {
                alert("hello-zhaoshuai-lc@inspur.com")
            },

            showInfo_2() {
                alert("hello-2-zhaoshuai-lc@inspur.com")
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

<!-- 阻止事件冒泡(常用) 冒泡指的是从里到外 -->
    <div class="demo1" @click="showInfo_2">
        <button @click.stop="showInfo_1">点我提示信息</button>
    </div>

这是往外冒泡的点击事件:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
    <style>
        * {
            margin: 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: auto;
        }

        li {
            height: 100px;
        }
    </style>
</head>
<body>
<div id="event">
    <!-- 阻止默认事件(常用) -->
    <a href="https://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>

    <!-- 阻止事件冒泡(常用) 冒泡指的是从里到外 -->
    <div class="demo1" @click="showInfo_2">
        <button @click.stop="showInfo_1">点我提示信息</button>
    </div>

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

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vmEvent = new Vue({
        el: '#event',
        data: {},
        methods: {
            showInfo_1() {
                alert("hello-zhaoshuai-lc@inspur.com")
            },

            showInfo_2() {
                alert("hello-2-zhaoshuai-lc@inspur.com")
            },

            showInfo_3() {
                alert("hello-3-zhaoshuai-lc@inspur.com")
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

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

事件只会触发一次。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件处理</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
    <style>
        * {
            margin: 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: auto;
        }

        li {
            height: 100px;
        }
    </style>
</head>
<body>
<div id="event">
   
    <!-- 使用事件的捕获模式 -->
    <div class="box1" @click="showMsg(1)">
        div1
        <div class="box2" @click="showMsg(2)">
            div2
        </div>
    </div>

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vmEvent = new Vue({
        el: '#event',
        data: {},
        methods: {
            showMsg(msg) {
                console.log(msg)
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
冒泡的形式,从里到外调用(如上)

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

在这里插入图片描述
捕获的形式,从外到里调用(如上)

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

在这里插入图片描述

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

Vue中的事件修饰符:

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

11 键盘事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="key-event">
    <input type="text" placeholder="按下回车提示信息" @keyup.enter="showInfo">
</div>
<script type="text/javascript">
    new Vue({
        el: '#key-event',
        data: {},
        methods: {
            showInfo(e) {
                console.log(e.target.value)
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
1.Vue中常用的案件别名:

回车 => enter
删除 => delete(捕获“删除”和“退格”键)
推出 => esc
空格 => space
换行 => tab(特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right

打印其他键盘按键的别名以及code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="key-event">
    <input type="text" placeholder="按下回车提示信息" @keyup="showInfo">
</div>
<script type="text/javascript">
    new Vue({
        el: '#key-event',
        data: {},
        methods: {
            showInfo(e) {
                console.log(e.key, e.keyCode)
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
特别注意两个单词的 如 CapsLock:

<input type="text" placeholder="按下回车提示信息" @keyup.caps-lock="showInfo">

系统修饰键(用法特殊):ctrl、alt、shift、meta

配合keyup使用:按下修饰键的同时,再按下其它键,随后释放其它键,事件才被触发。
配合keydown使用:正常触发

修饰符可以连续写,如@click.prevent.stop,先阻止默认事件,后阻止冒泡
系统修饰键可以连续写,如@keyup.ctrl.y,也就是按下Ctrl+y事件

12 姓名案例引出计算属性

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。

复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
在这里插入图片描述
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="name-methods">
    姓:<input type="text" v-model="firstName"><br/>
    名:<input type="text" v-model="secondName"><br/>
    全名:<span>{{firstName.slice(0,3)}}-{{secondName}} </span>
</div>
<script type="text/javascript">
    new Vue({
        el: '#name-methods',
        data() {
            return {
                firstName: 'zhao',
                secondName: 'shuai-lc'
            }
        },
        methods: {}
    })
</script>
</body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="name-methods">
    姓:<input type="text" v-model="firstName"><br/>
    名:<input type="text" v-model="secondName"><br/>
    全名:<span>{{ fullName() }}</span>
</div>
<script type="text/javascript">
    new Vue({
        el: '#name-methods',
        data() {
            return {
                firstName: 'zhao',
                secondName: 'shuai-lc@inspur.com'
            }
        },
        methods: {
            fullName() {
                return this.firstName + '-' + this.secondName
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

13 计算属性

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

2.原理:底层借助了Object.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">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="name-calculate">
    姓:<input type="text" v-model="firstName"> <br/>
    名:<input type="text" v-model="lastName"> <br/>
    全名:<span>{{ fullName }}</span> <br/>

</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: '#name-calculate',
        data: {
            firstName: 'zhao',
            lastName: 'shuai-lc@inspur.com'
        },
        methods: {},
        computed: {
            fullName: {
                get() {
                    return this.firstName + '-' + this.lastName
                },
                set(value) {
                    const list = value.split('-');
                    this.firstName = list[0]
                    this.lastName = list[1]
                }
            }
        }
    })

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

在这里插入图片描述
get有什么作用?当有人读取了fullName时,get就会被调用,且返回值就作为fullName的值
get什么时候被调用?1.初次读取fullName时。2.所依赖的数据发生变化时。

1)vm._data里面时没有计算属性的。
在这里插入图片描述

2)计算属性中get函数的this,Vue已经维护好了,并把getter中的this指向调成了vm。
3)书写多次fullName但是getter只用了一次,说明Vue有缓存。如果用上集methods方法,则书写几次方法就调用几次,显然有弊端。

14 计算属性简写

确定了只读,不可以修改,才能使用简写方式。

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/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> <br/><br/>
</div>

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

    const vm = new Vue({
        el: '#root',
        data: {
            firstName: '张',
            lastName: '三'
        },
        computed: {
            // 简写
            fullName: function () {
                return this.firstName + '-' + this.lastName
            }
        }
    })
</script>
</body>
</html>

14 天气案例引入监视属性

在Vue开发者工具中,如果在页面中没用到该值,即使数据已经发生改变,Vue也不会更新数据。
可以在@click中直接写要执行的简单语句
如果需要在@click中直接写window方法,如写alert,需要在data中写window,然后@click=‘window.alert( )’。

<button @click="judgeHot = !judgeHot">切换天气</button>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="weather">
    <h1>今天天气很 - {{ info }}</h1>
    <!--    <button @click="changeWeather()">切换天气</button>-->
    <button @click="judgeHot = !judgeHot">切换天气</button>
</div>

<script type="text/javascript">
    new Vue({
        el: '#weather',
        data: {
            judgeHot: true
        },
        computed: {
            info() {
                return this.judgeHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.judgeHot = !this.judgeHot
            }
        }

    })
</script>

</body>
</html>

在这里插入图片描述

15 监视属性

监视属性watch:

1.当被监视的属性变化时,回调函数自动调用,进行相关操作
2.监视的属性必须存在,才能进行监视!
3.监视的两种写法:
1)new Vue时传入watch配置
2)通过vm.$watch监视
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="weather">
    <h1>今天天气很 - {{ info }}</h1>
    <button @click="changeWeather()">切换天气</button>
</div>

<script type="text/javascript">
    new Vue({
        el: '#weather',
        data: {
            judgeHot: true,
        },
        computed: {
            info() {
                return this.judgeHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.judgeHot = !this.judgeHot
            }
        },
        watch: {
            judgeHot: {
                // immediate:true, //初始化时让hander()调用一下, 默认为false
                immediate: false,
                // handler什么时候调用?当judgeHot发生改变时
                handler(newValue, oldValue) {
                    console.log('judgeHot 被修改了 ...', newValue, oldValue)
                }
            },

            info: {
                handler(newValue, oldValue) {
                    console.log('info 被修改了 ...', newValue, oldValue)
                }
            }
        }
    })
</script>

</body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="weather">
    <h1>今天天气很 - {{ info }}</h1>
    <button @click="changeWeather()">切换天气</button>
</div>

<script type="text/javascript">
    let vm = new Vue({
        el: '#weather',
        data: {
            judgeHot: true,
        },
        computed: {
            info() {
                return this.judgeHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.judgeHot = !this.judgeHot
            }
        }
    })

    vm.$watch('judgeHot', {
        handler(newValue, oldValue) {
            console.log('judgeHot 被修改了 ...', newValue, oldValue)
        }
    })
</script>

</body>
</html>

16 深度监视

深度监视:

1.Vue中的watch默认不监测对象内部值得改变(一层)。
2.配置deep:true可以监测对象内部值改变(多层)。

备注:
1.Vue自身可以监测对象内部值得改变,但Vue提供得watch默认不可以!
2.使用watch时根据数据得具体结构,决定是否采用深度监视。
默认不开启是为了提升效率
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="weather">
    <h3>a的值是:{{ numbers.a }}</h3>
    <button @click="autoIncrement()">点我让a+1</button>
</div>

<script type="text/javascript">
    let vm = new Vue({
        el: '#weather',
        data: {
            numbers: {
                a: 1,
                b: 2
            }
        },
        computed: {},
        methods: {
            autoIncrement() {
                return this.numbers.a++
            }
        },
        watch: {
            // 监视多级结构中某个属性的变化
            'numbers.a': {
                handler() {
                    console.log('a has changed ...')
                }
            }
        }
    })

</script>

</body>
</html>

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="weather">
    <h3>a的值是:{{ numbers.a }}</h3>
    <button @click="autoIncrementA()">点我让a+1</button>
    <h3>b的值是:{{ numbers.b }}</h3>
    <button @click="autoIncrementB()">点我让b+1</button>
    <br/><br/>
</div>

<script type="text/javascript">
    let vm = new Vue({
        el: '#weather',
        data: {
            numbers: {
                a: 1,
                b: 2
            }
        },
        computed: {},
        methods: {
            autoIncrementA() {
                return this.numbers.a++
            },
            autoIncrementB() {
                return this.numbers.b++
            }
        },
        watch: {
            // 监视多级结构中所有属性的变化
            numbers: {
                deep: true,
                handler() {
                    console.log('numbers has changed ...')
                }
            }
        }
    })

</script>

</body>
</html>

在这里插入图片描述

17 监视的简写形式

简写的前提是,如果不需要immediate、deep等的配置项,即配置项中只有handler的时候才可以简写。

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="root111">
    <h2>今天天气很{{ info }}</h2>
    <button @click="changeWeather">切换天气</button>
</div>

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

    const vm = new Vue({
        el: '#root111',
        data: {
            isHot: true
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot
            }
        },
        watch: {
            /*isHot:{
                handler(newValue,oldValue){
                    console.log('isHot被修改了',newValue,oldValue)
                }
            }*/

            isHot(newValue, oldValue) {
                console.log('isHot被修改了', newValue, oldValue)
            }
        }
    })

    vm.$watch('isHot', {
        handler(newValue, oldValue) {
            console.log('isHot 被修改了 ...', newValue, oldValue)
        }
    })
    //vm.$watch简写
    vm.$watch('isHot', function (newValue, oldValue) {
        console.log('isHot被修改了', newValue, oldValue)
    })
</script>
</body>
</html>

18 watch对比computed

两者都能实现的时候,选用computed比较简单,需要异步计算等比较复杂实现的时候用watch。

computed和watch之间的区别:

1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、Ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象。

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="watch-name">
    姓:<input type="text" v-model="firstName"> <br/><br/>
    名:<input type="text" v-model="lastName"> <br/><br/>
    全名:<span>{{ fullName }}</span>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vm = new Vue({
        el: '#watch-name',
        data: {
            firstName: 'zhao',
            lastName: 'shuai-lc@inspur.com',
            fullName: 'zhao#shuai-lc@inspur.com'
        },
        watch: {
            firstName(newValue, oldValue) {
                this.fullName = newValue + '#' + this.lastName
            },
            lastName(newValue, oldValue) {
                this.fullName = this.firstName + '#' + newValue
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="watch-name">
    姓:<input type="text" v-model="firstName"> <br/><br/>
    名:<input type="text" v-model="lastName"> <br/><br/>
    全名:<span>{{ fullName }}</span>
</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    let vm = new Vue({
        el: '#watch-name',
        data: {
            firstName: 'zhao',
            lastName: 'shuai-lc@inspur.com',
            fullName: 'zhao#shuai-lc@inspur.com'
        },
        watch: {
            firstName(val) {
                setTimeout(() => {
                    console.log(this) // vue
                    this.fullName = val + '-' + this.lastName
                }, 1000)

                setTimeout(function () {
                    console.log(this) // window
                    this.fullName = val + '-' + this.lastName
                }, 1000)

            },
            lastName(val) {
                this.fullName = this.firstName + '-' + val
            }
        }
    })
</script>
</body>
</html>

19 条件渲染

使用template可以使其里面的内容在html的结构中不变。
条件渲染:
1.v-if
写法:
(1)v-if=“表达式”
(2)v-else-if=“表达式”
(3)v-else
适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。

注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”。

2.v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉。
3.备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="conditional-rendering">
    <!-- 使用v-show做条件渲染 切换频率高-->
    <!--    <h1 v-show="judge">hello {{ name }}</h1>-->

    <!-- 使用v-if做条件渲染 切换频率低-->
    <!--    <h1 v-if="judge">hello {{ name }}</h1>-->

    <h2>当前的n值是:{{ n }}</h2>
    <button @click="n++">点我n+1</button>
    <!-- v-if和v-else-if -->
    <div v-if="n === 1">Angular</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>other</div>

    <!-- v-if与template结合 -->
    <template v-if="n === 1">
        <h2>你好</h2>
        <h2>尚硅谷</h2>
        <h2>北京</h2>
    </template>


</div>

<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el: '#conditional-rendering',
        data: {
            name: 'zhaoshuai-lc@inspur.com',
            judge: false,
            n: 1
        }
    })
</script>
</body>
</html>

20 列表渲染

v-for指令:
1.用于展示列表数据
2.语法:v-for=“(item,index) in xxx” :key=“yyy”
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <ul>
        <li v-for="item in personList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>
</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: 1001, name: 'zhaoshuai-la', age: 101},
                {id: 1002, name: 'zhaoshuai-lb', age: 102},
                {id: 1003, name: 'zhaoshuai-lc', age: 103}
            ]
        }
    })
</script>
</body>
</html>

在这里插入图片描述

    <ul>
        <li v-for="(a, b) in personList">
            {{ a }} - {{ b }}
        </li>
    </ul>

在这里插入图片描述
上面的key可以做一个替换:

    <ul>
        <li v-for="(item, index) in personList" :key="index">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

in 也可以替换为 of:

    <ul>
        <li v-for="(item, index) of personList" :key="index">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

除了数组还可以遍历对象:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <ul>
        <li v-for="(item, index) of personList" :key="index">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

    <ul>
        <li v-for="(key, value) of car" :key="key">
            {{ key }} - {{ value }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: 1001, name: 'zhaoshuai-la', age: 101},
                {id: 1002, name: 'zhaoshuai-lb', age: 102},
                {id: 1003, name: 'zhaoshuai-lc', age: 103}
            ],
            car: {
                name: '奥迪A8',
                price: '70万',
                color: '黑色'
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
测试遍历字符串:

  <ul>
      <li v-for="(char, index) of str" :key="index">
          {{ index }} - {{ char }}
      </li>
  </ul>
    
str: 'hello'

在这里插入图片描述

21 key作用与原理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <button @click.once="add">添加一个 zhaoshuai-ld</button>
    <ul>
        <li v-for="(item, index) of personList" :key="index">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: 1001, name: 'zhaoshuai-la', age: 101},
                {id: 1002, name: 'zhaoshuai-lb', age: 102},
                {id: 1003, name: 'zhaoshuai-lc', age: 103}
            ]
        },
        methods: {
            add() {
                let person = {id: 1004, name: 'zhaoshuai-ld', age: 104}
                this.personList.unshift(person)
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
看似没有问题,其实问题很大,如下:

遍历列表时key的作用(index作为key)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <button @click.once="add">添加一个 zhaoshuai-ld</button>
    <ul>
        <li v-for="(item, index) of personList" :key="index">
            {{ item.name }} - {{ item.age }}
            <input type="text">
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: 1001, name: 'zhaoshuai-la', age: 101},
                {id: 1002, name: 'zhaoshuai-lb', age: 102},
                {id: 1003, name: 'zhaoshuai-lc', age: 103}
            ]
        },
        methods: {
            add() {
                let person = {id: 1004, name: 'zhaoshuai-ld', age: 104}
                this.personList.unshift(person)
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

遍历列表时key的作用(id作为key)

    <ul>
        <li v-for="(item, index) of personList" :key="item.id">
            {{ item.name }} - {{ item.age }}
            <input type="text">
        </li>
    </ul>

在这里插入图片描述
在这里插入图片描述
面试题:react、Vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中key的作用:

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

2.对比规则:
(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:

 若虚拟DOM中内容没变,直接使用之前的真实DOM
 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM

(2)旧虚拟DOM中未找到与新虚拟DOM相同的key:

创建新的真实DOM,随后渲染到页面

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

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

4.开发中如何选择key?

(1)最好使用每条数据的唯一标识作为key,比如说id、手机号、身份证号、学号等唯一值。
(2)如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表中用于展示,使用index作为key是没有问题的。

22 列表过滤

用watch实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <input type="text" placeholder="请输入名字" v-model="keyWorld">
    <ul>
        <li v-for="(item, index) of filterPersonList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            keyWorld: '',
            personList: [
                {id: '001', name: '马冬梅', age: 19, sex: '女'},
                {id: '002', name: '周冬雨', age: 20, sex: '女'},
                {id: '003', name: '周杰伦', age: 21, sex: '男'},
                {id: '004', name: '温兆伦', age: 22, sex: '男'}
            ],
            filterPersonList: []
        },
        watch: {
            keyWorld: {
                immediate: true,
                handler(newValue, oldValue) {
                    this.filterPersonList = this.personList.filter((item) => {
                        return item.name.indexOf(newValue) !== -1
                    })
                }
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述
用computed实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <input type="text" placeholder="请输入名字" v-model="keyWorld">
    <ul>
        <li v-for="(item, index) of filterPersonList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            keyWorld: '',
            personList: [
                {id: '001', name: '马冬梅', age: 19, sex: '女'},
                {id: '002', name: '周冬雨', age: 20, sex: '女'},
                {id: '003', name: '周杰伦', age: 21, sex: '男'},
                {id: '004', name: '温兆伦', age: 22, sex: '男'}
            ]
        },
        computed: {
            filterPersonList() {
                return this.personList.filter((item) => {
                    return item.name.indexOf(this.keyWorld) !== -1
                })
            }
        }
    })
</script>
</body>
</html>

23 列表排序

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <input type="text" placeholder="请输入名字" v-model="keyWorld">
    <button @click="sortType = 2">升序</button>
    <button @click="sortType = 1">降序</button>
    <button @click="sortType = 0">原序</button>
    <ul>
        <li v-for="(item, index) of filterPersonList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    new Vue({
        el: '#v-for',
        data: {
            keyWorld: '',
            sortType: 0, // 0-原顺序 1-降序 2-升序
            personList: [
                {id: '001', name: '马冬梅', age: 19, sex: '女'},
                {id: '002', name: '周冬雨', age: 24, sex: '女'},
                {id: '003', name: '周杰伦', age: 55, sex: '男'},
                {id: '004', name: '温兆伦', age: 12, sex: '男'}
            ]
        },
        computed: {
            filterPersonList() {
                let filterList = this.personList.filter((item) => {
                    return item.name.indexOf(this.keyWorld) !== -1
                })
                // 判断是否需要排序
                if (this.sortType) {
                    filterList.sort((a, b) => {
                        return this.sortType === 1 ? b.age - a.age : a.age - b.age
                    })
                }
                return filterList
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

24 更新时的一个问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <button @click="updateMei">更新马冬梅的信息</button>
    <ul>
        <li v-for="(item, index) of personList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    let vm = new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: '001', name: '马冬梅', age: 19, sex: '女'},
                {id: '002', name: '周冬雨', age: 24, sex: '女'},
                {id: '003', name: '周杰伦', age: 55, sex: '男'},
                {id: '004', name: '温兆伦', age: 12, sex: '男'}
            ]
        },
        methods: {
            updateMei() {
                /*this.personList[0].name = '马保国'
                this.personList[0].age = 50
                this.personList[0].sex = '男'*/
                // ok 如上是起作用的

                this.personList[0] = {id: '001', name: '马保国', age: 50, sex: '男'}
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

25 Vue监测数据的原理_对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-school">
    学校名称:{{ name }} <br/>
    学校地址:{{ address }}
</div>
<script type="text/javascript">
    let vm = new Vue({
        el: '#v-school',
        data: {
            name: '北京大学',
            address: '北京'
        }
    })
</script>
</body>
</html>

在这里插入图片描述

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

    let data = {
        name: '尚硅谷',
        address: '北京',
    }

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

    // 准备一个vm实例对象
    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>
</body>
</html>

在这里插入图片描述
本次书写的代码为简化版,Vue更完善的点有:

如果要修改_data中的name,完整写法为 vm._data.name = ‘atguigu’ ,还可以直接简写为 vm.name = ‘atguigu’,因为Vue做了数据代理。

当对象中还有对象时,Vue也能做到有为其服务的getter和setter。Vue里面写了递归,有多少层就能写到多少层,直到那个东西不再是对象为止,对象在数组中也是如此。

Vue监测数据的原理,就是靠setter。

只要修改数据,Vue就会重新解析模板,生成虚拟DOM。

26 Vue.set()方法

(1)假设数组a中不存在对象b,Vue中访问a.b不会报错,只是不显示(Vue中默认undefined不显示),Vue中访问b会报错。

(2)Vue.set 只能给data里的某个对象追加属性,不能直接给data追加属性。

(3)向响应式对象中添加一个property,并确保这个新property同样是响应式的,且触发视图更新。
在这里插入图片描述

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-set">
    <h1>学校信息</h1>
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <hr/>
    <h1>学生信息</h1>
    <button @click="addSex">添加一个性别属性,默认值是男</button>
    <h2>姓名:{{ student.name }}</h2>
    <h2>性别:{{ student.sex }}</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>

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

    let vm = new Vue({
        el: '#v-set',
        data: {
            name: '北京大学',
            address: '北京',
            student: {
                name: 'tom',
                age: {
                    rAge: 40,
                    sAge: 29
                },
                friends: [
                    {name: 'jerry', age: 35},
                    {name: 'tony', age: 36}
                ]
            }
        },
        methods: {
            addSex() {
                // Vue.set(this.student,'sex','男')
                this.$set(this.student, 'sex', '男')
            }
        },
    })
</script>
</body>
</html>

27 Vue监测数据的原理_数组

原生Javascript数组使用的方法,例如push,就是从Array原型中找到的。可用 arr.push === Array.prototype.push 验证。

而Vue中的push却不等于 Array.prototype.push ,因为Vue中的push是经过包装的。

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="ddd">
    <h1>学生信息</h1>
    <h2>爱好:</h2>
    <ul>
        <li v-for="(item, index) in student.hobby" :key="index">
            {{ item }}
        </li>
    </ul>
</div>

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

    const vm = new Vue({
        el: '#ddd',
        data: {
            student: {
                name: 'tom',
                age: 18,
                hobby: ['抽烟', '喝酒', '烫头'],
                friends: [
                    {name: 'jerry', age: 35},
                    {name: 'tony', age: 36}
                ]
            }
        },
        methods: {
        },
    })
</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述
针对于上面的数组,有了解决方案:如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="v-for">
    <button @click="updateMei">更新马冬梅的信息</button>
    <ul>
        <li v-for="(item, index) of personList" :key="item.id">
            {{ item.name }} - {{ item.age }}
        </li>
    </ul>

</div>
<script type="text/javascript">
    let vm = new Vue({
        el: '#v-for',
        data: {
            personList: [
                {id: '001', name: '马冬梅', age: 19, sex: '女'},
                {id: '002', name: '周冬雨', age: 24, sex: '女'},
                {id: '003', name: '周杰伦', age: 55, sex: '男'},
                {id: '004', name: '温兆伦', age: 12, sex: '男'}
            ]
        },
        methods: {
            updateMei() {
                /*this.personList[0].name = '马保国'
                this.personList[0].age = 50
                this.personList[0].sex = '男'*/
                // ok 如上是起作用的

                // this.personList[0] = {id: '001', name: '马保国', age: 50, sex: '男'} 不起作用
                this.personList.splice(0,1, {id: '001', name: '马保国', age: 50, sex: '男'})
            }
        }
    })
</script>
</body>
</html>

在这里插入图片描述

28 总结Vue监视数据

<!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 type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.1/vue.js"></script>
</head>
<body>
<div id="ddd">
    <h1>学生信息</h1>

    <button @click="student.age++">年龄+1岁</button>
    <br/>
    <button @click="addSex">添加一个性别属性,默认值:男</button>
    <br/>
    <button @click="student.sex = '未知' ">修改性别</button>
    <br/>
    <button @click="addFriend">在列表首位添加一个朋友</button>
    <br/>
    <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button>
    <br/>
    <button @click="addHobby">添加一个爱好</button>
    <br/>
    <button @click="updateHobby">修改第一个爱好为:开车</button>
    <br/>
    <button @click="removeSmoke">过滤掉爱好中的抽烟</button>
    <br/>

    <h2>姓名:{{ student.name }}</h2>

    <h2 v-if="student.sex">性别:{{ student.sex }}</h2>

    <h2>年龄:{{ student.age }}</h2>

    <h2>爱好:</h2>
    <ul>
        <li v-for="(item, index) in student.hobby" :key="index">
            {{ item }}
        </li>
    </ul>

    <h2>朋友们:</h2>
    <ul>
        <li v-for="(item, index) in student.friends" :key="index">
            {{ item.name }}--{{ item.age }}
        </li>
    </ul>
</div>

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

    const vm = new Vue({
        el: '#ddd',
        data: {
            student: {
                name: 'tom',
                age: 18,
                hobby: ['抽烟', '喝酒', '烫头'],
                friends: [
                    {name: 'jerry', age: 35},
                    {name: 'tony', age: 36}
                ]
            }
        },
        methods: {
            addSex() {
                // Vue.set(this.student,'sex','男')
                this.$set(this.student, 'sex', '男')
            },
            addFriend() {
                this.student.friends.unshift({name: 'jack', age: 70})
            },
            updateFirstFriendName() {
                this.student.friends[0].name = '张三'
                this.student.friends[0].age = 5
            },
            addHobby() {
                this.student.hobby.push('学习')
            },
            updateHobby() {
                // this.student.hobby.splice(0,1,'开车')
                // Vue.set(this.student.hobby,0,'开车')
                this.$set(this.student.hobby, 0, '开车')
            },
            removeSmoke() {
                this.student.hobby = this.student.hobby.filter((h) => {
                    return h !== '抽烟'
                })
            }

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

Vue监视数据的原理:

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

2.如何监测对象中的数据?

 通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1)对象中后追加的属性,Vue默认不做响应式处理。
(2)如需给后添加的属性做响应式,请使用如下API:
  vm.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.$set()

特别注意:Vue.set() 和 vm.$set() 不能给 vm 或 vm的根数据对象添加属性!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144620.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式——建造者模式

文章目录模式理解基本概念使用示例建造者模式延展模式理解 建造者模式&#xff08;Builder Pattern&#xff09;&#xff1a;建造者模式是一种对象创建型模式。将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。这句话理解起来太抽象了&…

B. Dima and a Bad XOR(构造 + 异或性质)

Problem - 1151B - Codeforces 来自Kremland的学生Dima有一个大小为nm的非负整数矩阵a。 他希望从矩阵的每一行中选择一个整数&#xff0c;以便所选整数的按位互斥或严格大于0。帮助他! 形式上&#xff0c;他想选择一个整数序列c1,c2&#xff0c;…&#xff0c;cn(1≤cj≤m)&am…

Integer包装类详解(java)

文章目录&#x1f4d6;前言&#xff1a;&#x1f380;包装类概念&#xff1a;&#x1f380;包装类分类&#xff1a;&#x1f380;包装类integer介绍&#xff1a;&#x1f387;自动装箱和自动拆箱问题【⚠注意面试常考点】&#x1f387;Integer常用方法&#xff1a;&#x1f4d6…

2023真无线蓝牙耳机推荐:高性价比真无线蓝牙耳机各价位蓝牙耳机推荐!

2023年了&#xff0c;蓝牙耳机赛道依然很卷&#xff01;性价比是反映物品可买程度的一种量化的计量方式。现如今&#xff0c;蓝牙耳机市场上主打高性价比的不在少数&#xff0c;而高性价比的东西往往更能精准抓住用户“痛点”&#xff0c;从而受到了不少用户的欢迎。 既然高性…

面试20分钟就完事了,问的实在是太......

干了两年外包&#xff0c;本来想出来正儿八经找个互联网公司上班&#xff0c;没想到算法死在另一家厂子。 自从加入这家外包公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到11月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资…

Spring Boot整合Junit

系列文章目录 Spring Boot[概述、功能、快速入门]_心态还需努力呀的博客-CSDN博客 Spring Boot读取配置文件内容的三种方式_心态还需努力呀的博客-CSDN博客 该系列文章持续更新中~ 目录 系列文章目录 前言 一、搭建SpringBoot工程 二、引入starter-test起步依赖 三、编…

2022年全国研究生数学建模竞赛华为杯F题COVID-19疫情期间生活物资的科学管理问题求解全过程文档及程序

2022年全国研究生数学建模竞赛华为杯 F题 COVID-19疫情期间生活物资的科学管理问题 原题再现&#xff1a; 一、背景介绍   进入2022年以来全国范围内陆续出现了多次较大规模疫情爆发事件[1-2]。在大规模疫情爆发期间由于我国采用封闭式管理方式来实现疫情的快速清零&#x…

Vue组件之间的通信(组件之间的数据传递)

一、Vue组件之间的关系 父子关系&#xff1a;A组件和B组件、B组件和C组件、B组件和D组件​ 兄弟关系&#xff1a;C组件和D组件​ 隔代关系&#xff1a;A组件和C组件、A组件和D组件 二、父组件向子组件传递数据 通过props方式向子组件传递数据&#xff08;在子组件中添加props属…

为什么选型低代码平台时,需要注重私有化部署能力?

编者按&#xff1a;低代码平台&#xff0c;目前分为私有化部署和公有化部署&#xff0c;企业为什么倾向于选择私有化部署的低代码平台&#xff1f;本文从私有化部署的概念出发&#xff0c;分析了私有化部署的优势&#xff0c;并进一步介绍了支持私有化部署的老牌低代码平台。关…

工控安全-使用Metasploit攻击Modbus设备

文章目录实验内容环境介绍实验开始开启Modbus从站主机和从站服务利用Metasploit工具扫描Modbus从站中的ID访问从站2的寄存器数据修改从站4线圈值可选择的action实验内容 利用Metasploit工具针对Modbus协议进行攻击&#xff0c;读取Modbus从站寄存器数值以及修改Modbus从站寄存…

应届生学习Java八个月,offer年薪28W,这一年我经历了什么?

自我介绍 首页和大家介绍一下我&#xff0c;我叫 阿杆&#xff08;笔名及游戏名&#x1f923;&#xff09;&#xff0c;19级本科在读&#xff0c;双非院校&#xff0c;主修软件工程&#xff0c;学习方向是后端开发&#xff0c;主要语言Java、Python&#xff0c;今年秋招拿到了…

三、Gtk4-Widgets(1)

1 GtkLavel&#xff0c;GtkButton and GtkBox 1.1 GtkLabel 在前一节中&#xff0c;我们创建了一个窗口并将其显示在屏幕上。现在我们进入下一个主题&#xff0c;在这个窗口中添加部件。最简单的部件是GtkLabel。它是一个包含文本的部件。 1 #include <gtk/gtk.h>2 3 s…

spark sql 执行流程

最近学习了spark sql执行流程&#xff0c;从网上搜到了大都是sql解析、analyzer、optimizer阶段、sparkplan阶段&#xff0c;但是我比较好奇的是&#xff0c;这几个阶段是怎么串起来的&#xff0c;于是花了好几天着重从源码层面看看了看具体实现&#xff0c;写了几点自己认为应…

聊聊Mybatis的缓存

Mybatis缓存是内存中的数据&#xff0c;主要是对数据库查询结果的保存&#xff0c;使用缓存的好处是避免频繁与数据库进行交互&#xff0c;提升查询的响应速度。 数据库缓存扩展 聊到Mybatis缓存。我们可以扩展聊一下MySQL缓存。MySQL缓存其实与Mybatis类似&#xff0c;在查询…

物联网架构实例—Ubuntu 安装MongoDB及完全卸载

1.安装1.1.导入公钥wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -如果收到指示gnupg未安装的错误&#xff0c;则可以先执行&#xff1a;sudo apt-get install gnupg然后再执行一次导入公钥命令&#xff1a;wget -qO - https://www.mongo…

React(coderwhy)- 08(Hooks)

认识和体验Hooks 为什么需要Hook? ◼ Hook 是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09;。 ◼ 我们先来思考一下class组件相对于函数式组件有什么优势&#xff1f;比较常见的是下…

Exynos_4412——IIC总线概述

目录 一、IIC总线概述 1.1IIC总线简介 1.2IIC总线通信过程 1.3IIC总线寻址方式 二、IIC总线信号实现 2.1起始信号与停止信号 2.2字节传送与应答 2.3同步信号 三、典型IIC时序 四、小作业 一、IIC总线概述 1.1IIC总线简介 IIC总线IIC总线是Philips公司在八十年代初推…

[VP]河南第十三届ICPC大学生程序竞赛 L.手动计算

前言 传送门 : 题意 : 给定两个椭圆 的方程 , 要求 求出椭圆并集的面积之和 思路 : 本题很显然是积分 或者 计算几何的问题 对于积分的做法, 无非就是根据积分公式求出第一象限的面积 之后拓展到后面四个象限。(奈何我懒, 连两个椭圆的焦点都不想求更别提后面的积分公式了)…

Git遇到冲突?解决也太简单了

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store git冲突是开发过程中很难避免的&#xff0c;对很多git初学者来说也是比较有障碍和门槛的一部分知识。 我认为要想彻底理解一个问题&#xff0c;首先要清楚这个问题是怎么产生的&#xff0c;然后才可以…

大数据NiFi(八):NiFi集群页面的组件工具栏介绍

NiFi集群页面的组件工具栏介绍 一、处理器(Processor)