Vue2基础速通

news2025/1/14 0:52:48

Vue基础速通

前言

  欢迎来到知识汲取者的个人博客!在这篇文章中,我将为你介绍Vue.js的基础知识,帮助你快速入门并掌握Vue开发的基本技巧。Vue.js是一个流行的JavaScript框架,被广泛用于构建现代化、交互式的Web应用程序。它采用了MVVM(Model-View-ViewModel)架构模式,通过数据驱动视图的方式实现了高效的前端开发。在这篇文章中,我们将从Vue.js的核心概念开始,包括Vue实例、组件、指令和响应式数据等。我会详细解释每个概念的作用和用法,并通过实际的代码示例帮助你理解和运用这些概念。如果你是初学者,相信通过本文的学习,一定可以让你熟练掌握Vue的基础语法,理解Vue中的一些常见概念。
PS:对于文章一些描述不当、存在错误的地方,还请大家指出,笔者不胜感激

相关推荐

  • Vue2官方文档
  • Vue3官方文档

1、Vue概述

  • Vue是什么

    Vue (发音为 /vjuː/,类似 view) 是一款基于MVVM思想用于构建用户界面的渐进式 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。

    Vue官网:

    • Vue2:Vue.js (vuejs.org)
    • Vue3:Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

    Vue的亲爹:尤雨溪

    image-20221014213323236

    没想到吧😃,Vue亲爹是如此的年轻帅气,和我们以往对于哪些某一领域的开创者的印象是很不一样的,不像其他的大部分创始人都是大胡子老头,这个Vue的创始人看着好亲切(没错它是一个华人),而且它本科是计算机,硕士读的是美术设计(没想到吧)!难怪Vue是如此的优美,堪称一件精致的艺术品😆,同样的Vue也如同它本人一样,也是如此的年轻

    题外话:他之前是任职于Google,之后又加盟了阿里,现在是全职维护Vue,它的目标是让Vue成为最强的JavaScripted框架

  • 什么是MVVM

    MVVM(Model-View-ViewModel)是一种架构模式,是MVC模式的改进版。MVVM实现了数据的双向绑定1,解决了MVC模式只能实现模型到视图的单向展示。

    • Mode:数据模型,泛指后端进行的各种业务逻辑处理和数据操控
    • View:视图,是用户界面(可以理解为平时浏览的网页),用于展示数据
    • ViewModel:视图模型,是由前端开发人员组织生成和维护的视图数据层,用于Model和View的数据交换。在这一层,前端开发者从后端获取得到Model数据进行转换出来,做二次封装,以生成符合View层使用预期的视图数据模型

    image-20220812082254644

    个人理解:其实MVVM就是在MVC的MV之间添加了一个中间层VM,VM实时监听DOM,一旦网页中的数据发生了改变,VM就会立马反馈给Model,然后Model也发生改变。这让我想起来一个大佬说过的一句话”计算机中任何问题,都可以通过添加一个中间层来进行解决“

  • 什么是渐进式

    渐进式就是可以自底向上逐层地应用,即:既可以简单应用(只需要引入一个简单的核心库),又可以复杂应用(引入各种各样的Vue插件),也就是说Vue的应用是具有层次的

  • Vue的特点

    • 轻量灵活易上手。Vue只注重视图层,核心库只有5Kb,提供 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API,使开发者更加容易理解,能够更快上手
    • 组件化。Vue采用组件化模式2进行编码,提高代码的复用率,且代码具有更好的可维护性
    • 声明式。Vue采用声明式编码3,让开发人员无需直接操作DOM,提高开发效率
    • 响应性。Vue会自动跟踪 JavaScript 状态变化并在改变发生时响应式地更新 DOM,并且面对数据的动态变化时,Vue使用了虚拟DOM+Diff,尽可能复用DOM结点
  • Vue和其它JS框架的关系:

    • 借鉴Angular的模板数据绑定技术
    • 借鉴React的组件化虚拟DOM技术
  • Vue周边库:

    vue-resource、axios、vue-router(路由)、vue-cli(vue脚手架)、vueX(状态管理)、element-ui(基于vue的PC端UI组件库)

  • Vue的发展历程

    image-20221014214659564

    详情请参考:Vue.js的发展历程

2、快速入门

下载并引入Vue.js
关闭警告提示
编写Vue代码
  • Step1:下载并引入Vue.js

    image-20221015101946156

    • vue.js:是开发版。它包含完整的警告和调试模式
    • vue.min.js:是生产版。它删除了警告,是vue.js的压缩版,大小只有37.36KB

    具体下载可以去官网

    image-20221015103722213

  • Step2:关闭提示

    温馨提示:这一步并不是必须的

    1)Google安装Vue插件:解决上面①的警告,同时让Vue的开发更加丝滑

    2)配置productionTip属性:productionTip是Vue的全局属性之一,用于判断是否需要进行警告提示,它在Vue2中是默认取值true,开启提示,所以需要将他设置成false(在Vue3中已经默认取值为false了)

    image-20221015104611184

    3)设置网页Log:

    image-20221015124614200


    image-20221015124744062

    注意:如果favicon.ico图片不在项目的根目录下,则Liver Server无法识别,这时候log无法显示,此时如果任然想要log效果,可以通过<link rel="shortcut icon" href="" type="image/x-icon">标签进行引入

  • Step3:编写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>初识Vue</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <!-- Step0: 创建容器 -->
        <div id="root">
            <h1>Hello,{{name}}!</h1>
        </div>
    
        <script>
            //Step1: 设置Vue全局配置,并创建Vue对象
            Vue.config.productionTip = false; //关闭Vue的警告提示
            new Vue({
                //Step1: 让容器和Vue建立联系。使用el指定当前Vue示例为哪个容器服务,值通常是CSS选择器字符串
                /*
                写法一:你找到容器给Vue对象用
                el: document.getElementById('root')
                */
                //写法二:让Vue对象自己去找容器,并使用(推荐使用)
                el: '#root',
                //Step2: 进行数据绑定。data中存储的数据提供给建立了联系的容器进行使用(暂时写成对象的形式)
                data: {
                    name: 'Vue'
                }
            });
        </script>
    </body>
    
    </html>
    

    image-20221015135900184

    总结:

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

    注意区分js表达式js代码(语句)

    • js表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:

      • a
      • a+b
      • f()
      • x === y ? ‘a’ : ‘b’
    • js代码(语句)

      • if(){}
      • for(){}

      js表达式是js代码的子集,它属于特殊的js代码

3、模板语法

Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上

Vue的模板语法分为插值语法指令语法

  • 插值语法{{JS表达式}}

    作用:用于解析标签体内容

        <div id="root">
            <h1>hello,{{name}}</h1>
        </div>
        <!-- 引入开发板版Vue.js -->
        <script src="./js/vue.js"></script>
        <script>
            new Vue({
                el: '#root',
                data: {
                    name: 'Vue'
                }
            });
        </script>
    
  • 指令语法v-xxx:

    作用:用于解析标签(解析标签属性、解析标签体内容、绑定事件……)

        <div id="root">
            <a v-bind:href="url">点击跳转至百度1</a>
            <!-- 简写方式(不是所有的指令都能简写) -->
            <a :href="url">点击跳转至百度2</a>
        </div>
        <!-- 引入开发板版Vue.js -->
        <script src="./js/vue.js"></script>
        <script>
            new Vue({
                el: '#root',
                data: {
                    url: 'http://www.baidu.com'
                }
            });
        </script>
    

    推荐阅读:

    • v-bind详细用法

    • Vue指令大全

总结

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

4、数据绑定

示例代码

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据绑定</title>
    <!-- 引入开发板版Vue.js -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        单向绑定数据: <input type="text" v-bind:value="value1"> <br> 
        双向绑定数据: <input type="text" v-model:value="value2">
        <!--
			v:model的简写形式:
			<input type="text" v-model="value2"> 
		-->
    </div>

    <script>
        new Vue({
            el: '#root',
            data: {
                value1: '单向数据绑定',
                value2: '双向数据绑定'
            }
        });
    </script>
</body>

</html>
  • 单向数据绑定:改变data中的数据会影响页面中的数据,反之不会

    v-bind就是单向数据绑定,示例如下:

    image-20221015145855109

    image-20221015145912192

  • 双向数据绑定:改变data中的数据会影响页面中的数据,同时如果改变页面中的数据也会影响data中的数据

    v-model就是双向数据绑定,示例如下:

    image-20221015150057177

    注意v-model只能用于表单类(能进行输入,拥有value值)标签上,比如:input、复选框等,而h1~6、p等标签使用就会直接报错!

总结

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

5、el和data的两种写法

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el和data的两种写法</title>
    <!-- 引入开发板版Vue.js -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h1>Hello,{{name}}!</h1>
    </div>

    <script>
        const vue = new Vue({
            /*
            el的第一种写法:
             el: '#root',
             */
            /*
            data的第一种写法:对象式
            data: {
                name: 'Vue'
            }
            */
            //data的第二种写法:函数式
            /*
            data: function() {
                //注意这里一定要使用普通函数进行声明,不能使用箭头函数
                return {
                    name: 'Vue'
                }
            }
            */
            //简写:
            data() {
                console.log(this); //这个函数是由Vue对象进行调用的
                return {
                    name: 'Vue'
                }
            }
        });
        //el的第二种写法:通过Vue的对象内置的mount函数关联容器(这种方式十分灵活)
        setTimeout(() => {
            vue.$mount('#root');
        }, 1000);
    </script>
</body>

</html>

总结

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

拓展:MVVM

MVVM模型
1. M:模型(Model) :data中的数据
2. V:视图(View) :模板代码
3. VM:视图模型(ViewModel):Vue实例

观察发现:

  1. data中所有的属性,最后都出现在了vm身上。
  2. 2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。

推荐阅读:箭头函数与普通函数的区别详解

6、数据代理

所谓数据代理(也叫数据劫持),通过一个对象代理对另一个对象属性的操作。指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。比较典型的是 Object.defineProperty() 和 ES2015 中新增的 Proxy 对象。另外还有已经被废弃的 Object.observe(),他被废弃的原因就是由于Proxy的出现

PS:这个思想类似设计模式中的代理模式,而Vue中的双向数据绑定就是用到了数据代理,这和Spring中AOP使用到动态代理是一致的,都是一种代理

示例

问题描述:通过对num操作来改变Person对象中的age属性

当使用Object的defineProperty方法对Person的age属性进行数据代理时,age属性默认将不会被枚举、修改、删除

<!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>
</head>

<body>

    <script>
        let number = 18;
        let person = {
            name: '张三',
            gender: '男',
        };
        Object.defineProperty(person, 'age', {
            // value: 18,
            // enumerable:true, //控制属性是否可以枚举,默认值是false
            // writable: true, //控制属性是否可以被修改,默认值是false
            // configurable:true //控制属性是否可以被删除,默认值是false

            //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
            get() {
                console.log('有人读取age属性了')
                return number
            },

            //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
            set(value) {
                console.log('有人修改了age属性,且值是', value)
                number = value
            }
        });
        console.log(person);
        //遍历person对象所有的属性名
        console.log(Object.keys(person));
    </script>
</body>

</html>

备注:当我这样写getter和setter时,writableconfigurable属性无效了,因为当我们此时修改age,他会执行number = value,value没有修改成功,但是却修改了number;而获取age时,返回的是number,此时相当于间接改变了age

image-20221015164226817

知识拓展:Vue中的数据代理

在Vue中,data底层是利用了数据代理与View中的数据进行绑定。data中的数据是存储在Vue对象的_data属性中的,但是如果只是这样,就会导致想访问Vue中的某个data的值,就需要Vue对象._data.属性名来获取,这样显得很繁琐,所以Vue直接对_data进行数据代理,直接可以通过Vue对象.属性名来获取data的属性

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

7、事件处理

事件处理需要用到v-on指令,同时还需要搭配methos一起使用

7.1 快速入门

通过点击事件修改h1中的值

<!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>事件处理1</title>
    <!-- 引入开发版的Vue -->
    <script src="./js/vue.js"></script>
</head>
<div id="root">
    <h1>{{name}}</h1>
    <button v-on:click="changeName()">点我更换名字</button>
</div>

<body>
    <script>
        Vue.config.productionTip = false; //关闭Vue的警告提示
        const vm = new Vue({
            el: '#root',
            data: {
                name: '张三'
            },
            methods: {
                changeName(e) {
                    console.log(this); //此处的this代表vm
                    console.log(e.target); //<button>点我更换名字</button>
                    vm.name = "李四";
                }
            }
        });
    </script>
</body>

</html>

430482200207096891

7.2 事件修饰

  • prevent:阻止事件的默认行为,相当于 event.preventDefault() 常用
  • stop :阻止事件冒泡 ,相当于event.stopPropagation()常用
  • once:事件只触发一次 (常用
  • capture:开启事件的捕获模式
  • self:只有event.target是当前操作元素时,才触发事件(可用来阻止事件冒泡)
  • passive:事件的默认行为立即执行,无需等待事件回调再执行
  • native:vue中如果你想在某个组件的根元素上绑定事件,需要使用native修饰符示例

测试前四个事件修饰关键字

<!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>
    <!-- 引入开发版的Vue -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h1>测试prevent</h1>
        <a v-on:click.prevent="jump()" href="http://www.baidu.com">点击跳转至{{name}}</a>
        <!--简写: <a @click.prevent="jump()" href="http://www.baidu.com">点击跳转至{{name}}</a> -->
        <h1>测试stop</h1>
        <div @click="showMsg(1)">
            <button>div1</button>
            <div @click="showMsg(2)">
                <button>div2</button>
                <div @click.stop="showMsg(3)">
                    <button>div3</button>
                </div>
            </div>
        </div>
        <h1>测试once</h1>
        <a @click.prevent.once="jump()" href="http://www.baidu.com">点击跳转至{{name}}</a>
        <h1>测试capture</h1>
        <!-- 事件冒泡由内往外,事件捕获由外往内,先事件捕获,再事件冒泡 -->
        <div @click.capture="showMsg(1)">
            <button>div1</button>
            <div @click="showMsg(2)">
                <button>div2</button>
                <div @click="showMsg(3)">
                    <button>div3</button>
                </div>
            </div>
        </div>
        <h1>测试self</h1>
        <div @click="showMsg(1)">
            <button>div1</button>
            <div @click.self="showMsg(2)">
                <button>div2</button>
                <div @click="showMsg(3)">
                    <button>div3</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                name: '百度'
            },
            methods: {
                jump() {
                    alert("将要跳转至" + this.name);
                },
                showMsg(number) {
                    console.log(number);
                }
            }
        })
    </script>
</body>

</html>

测试一:点击超链接不跳转

测试二:点击div3按钮,再控制台只输出div3;点击div2仍然冒泡

测试三:第一个点击超链接,不跳转;第二次点击,事件不生效,直接跳转到百度

测试四:点击div3,开启了事件捕获的再事件捕获阶段事件就执行了,所以顺序是div1、div3、div2

image-20221015204517661

7.3 键盘事件

  • keyup:用于绑定事件,用于按下并释放某个键时触发绑定事件
  • keydown:用于绑定事件,用于按下某个键时触发绑定事件
  • key:获取按键的名称
  • keyCode :获取按键的编码
  • keyName :获取按键的名称(少部分)

Vue常用按键别名:回车:enter 、删除:delete、退出:esc、空格:space、换行:tab、上\下\左\右:up\down\left\right

需要注意的是:除上述Vue自定义按键,其它的按键,如果是一个单词就直接是按键名,需要首字母大写,比如:Alt、Enter、Shift……

如果是多个单词,测试采用小写字母加-连接,比如:caps-lock(大小写转换键)。同时对于一些特殊的按键是无法绑定事件的,比如:调整音量的按键(F1,F2)、调整亮度的按键(F5,F6)……当使用tab键时,需要搭配keydown使用,因为tab键具有特殊功能,使用tab键会切换焦点,所以@keyup.tab是用于无法触发事件的!系统修饰键:CtryAltShiftMeta(Win)这四个键,搭配@keyup,需要在按下系统修饰键的同时,按下其他非系统修饰键,然后再释放,事件才会被触发;搭配@keydown使用,正常触发事件

//给按键起别名(这里给回车键Enter起别名)
Vue.config.keyCodes.huiche = 13;
//系统修饰符还能接一个其它键
@keyup.ctry.y//只有当按下Ctry+y后释放y才能触发事件

示例

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>键盘事件</title>
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <input @keyup="showCode" type="text" placeholder="请输入">
    </div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            methods: {
                showCode(e) {
                    //当按下回车(出车的编码是13),就打印输出input中的内容
                    // if (e.keyCode != 13) return;//可以使用@keyup.enter替代
                    console.log(e.target.value);
                    console.log(e.key, e.keyCode);
                }
            }
        });
    </script>
</body>

</html>

备注e.target.value的值不等于e.keyCode,e.target.value只会展示按下字母和数字的按键的,而e.keyCode会展示几乎所有的按键编码(好像只有一些特殊的按键,如:Fn等不会展示编码)

image-20221015222558243

8、计算属性

  • 计算属性是什么?

    计算属性是Vue对插值表达式的一种优化,通过computed关键字将一个属性进行计算,然后再赋值给Vue对象,让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>计算属性1</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            姓: <input type="text" v-model="firstName"> <br>
            名: <input type="text" v-model="secondName"> <br>
            <!-- slice函数截取firstName前三个字符 -->
            全名:<span>{{firstName.slice(0,3)}}-{{secondName}}</span>
        </div>
    </body>
    <script>
        const vm = new Vue({
            el:'#root',
            data:{
            firstName:'张',
            secondName:'三'
            }
        })
    </script>
    </html>
    

    效果展示:

    430482200207096891

  • 方式二:使用methods进行实现

    <!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>计算属性2</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            姓: <input type="text" v-model="firstName"> <br> 
            名: <input type="text" v-model="secondName"> <br>
            <!-- 注意函数的调用一定不能省略小括号 -->
            全名:<span>{{fullName()}}</span>
        </div>
    </body>
    <script>
        const vm = new Vue({
            el: '#root',
            data: {
                firstName: '张',
                secondName: '三'
            },
            methods: {
                //当firstName或secondName发生改变时,fullName函数就会被调用
                fullName() {
                    return this.firstName.slice(0, 3) + '-' + this.secondName;
                }
            }
        })
    </script>
    
    </html>
    
  • 方式三:使用计算属性实现

    备注:计算属性底层也是使用数据代理实现的,需要注意的是计算属性属于Vue对象(可以直接通过Vue调用),但不属于_data

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>计算属性3</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            姓: <input type="text" v-model="firstName"> <br> 
            名: <input type="text" v-model="secondName"> <br> 
            全名:<span>{{fullName}}</span>
        </div>
    </body>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                firstName: '张',
                secondName: '三'
            },
            computed: {
                fullName: {
                    //get的调用时机:1)初次调用,get被调用 2)所依赖的data数据发生改变时get被调用(不改变就直接使用缓存) 
                    get() { 
                        // console.log(this);//此处的this是Vue
                        return this.firstName + '-' + this.secondName;
                    },
                    //set方法,用于对fullName这个计算属性进行修改 
                    set(value) {
                        console.log("set方法被调用了");
                        const arr = value.split("-");
                        this.firstName = arr[0];
                        this.secondName = arr[1];
                    }
                }
            }
        });
    </script>
    
    </html>
    

    知识拓展

    • methods实现和计算属性实现的比较使用计算属性实现性能更高,因为计算属性使用了缓存技术,当同一时间内调用同一个计算属性,且这段时间内该计算不发生该改变,不需要执行get方法,而是直接去缓存中取数据,避免了重复计算;而methods就需要重复调用方法

      image-20221015232206979

      image-20221015232535268

    • 计算属性的简写形式:

              computed: {
                  /*fullName: {
                      get() {
                          return this.firstName + '-' + this.secondName;
                      }
                  }*/
                  //简写:只针对只读不写的计算属性,也就是只有get函数的计算属性
                  /*fullName: function() {
                      return this.firstName + '-' + this.secondName;
                  }*/
                  //进一步简写:
                  fullName() {
                      return this.firstName + '-' + this.secondName;
                  }
              }
      

总结

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

9、监视属性

  • 什么是监视属性?

    也称侦听属性,是指使用watch对于属性进行监控,类似于Java中的监听器

  • 监视属性的作用?

    通过检测属性的改变,触发相应的事件

示例

实现应该天气切换效果

使用监视属性:点击跳转

<!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>
    <!-- 引入开发版Vue -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>天气很{{info}}</h2>
        <button @click="changeWeather()">切换天气</button>
    </div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                isHot: true
            },
            computed: {
                info() {
                    return this.isHot ? "热" : "冷";
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot;
                }
            },
        });
    </script>
</body>

</html>

效果展示:

430482200207096891

注意事项

  1. 这里可以直接将方法代码直接写在@click=""中,但是需要注意的是直接写在Vue的指令中,用到的变量或方法只会从Vue对象中寻早,如果Vue中没有找到就会到Vue原型中找;如果是写在方法methods中则会默认在Window对象中寻找,当使用this时才会到Vue对象中寻找,示例:

    image-20221017154440957

    对于第二个按钮,效果和第一个按钮是一致的;但是对于第三个按钮,运行不会报错,但在触发点击事件后就会报错alert方法不存在!原因是由于alert函数是属于Window对象中的,并不是Vue对象中的,在这里使用thiswindow关键字也无效

    最终建议如果是一些简单是语句,且只用到Vue对象或Vue原型中的属性,可以直接在使用第二个按钮的写法,对于复杂的语句最好使用第一个按钮的写法。所有的Vue函数都必须使用普通函数的形式

9.2 快速入门

示例

前面的案例我们学到了函数的两种写法,现在就让我们看看使用监视属性后的效果吧

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>监视属性2</title>
    <!-- 引入开发版Vue -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>天气很{{info}}</h2>
        <button @click="changeWeather()">切换天气</button>
    </div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                isHot: true
            },
            computed: {
                info() {
                    return this.isHot ? '热' : '冷';
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot;
                }
            },
            //方式一:
            /*  watch: {
                 isHot: {
                     //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                     immediate: true,
                     //当isHot属性发生改变时,handler函数就被调用
                     handler(newValue, oldValue) {
                         console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                     }
                 }
             } */
        });
        //方式二:(方式一中的isHot其实也是需要加引号的,只是简写了)
        vm.$watch('isHot', {
            immediate: true,
            handler(newValue, oldValue) {
                console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
            }
        });
    </script>
</body>

</html>

效果展示:

image-20221018205348380

9.2 深度监视

  • 什么是深度监视?

    深度监视是指对于多层次结构的属性,其中某一个属性发生改变时,就能得知该属性发生了改变。

    比如:numbers={a:1,b:{c:2,e:3}},numbers中的b属性中的c属性发生了改变时,我们能立刻得知numbers发生了改变的这一过程

  • 深度监视有什么用?

    监控属性的改变,可以做出相应的事件

示例

使用深度监视检测多层次结构中属性的变化

<!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>监视属性2</title>
    <!-- 引入开发版Vue -->
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h2>天气很{{info}}</h2>
        <button @click="changeWeather()">切换天气</button>
        <hr>
        <h2>a的值是:{{numbers.a}}</h2>
        <button @click="numbers.a++">点我让a值加1</button>
        <button @click="numbers={a:666,b:888}">点我改变numbers的地址</button>
    </div>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                isHot: true,
                numbers: {
                    a: 1,
                    b: 2
                }
            },
            computed: {
                info() {
                    return this.isHot ? '热' : '冷';
                }
            },
            methods: {
                changeWeather() {
                    this.isHot = !this.isHot;
                }
            },
            watch: {
                isHot: {
                    //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                    immediate: true,
                    //当isHot属性发生改变时,handler函数就被调用
                    handler(newValue, oldValue) {
                        console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                    }
                },
                //监视多级结构中某个属性的变化
                'numbers.a': {
                    handler(newValue, oldValue) {
                        console.log('a未修改前:' + oldValue + ';' + 'a修改后:' + newValue);
                    }
                },
                //不开启深度监视,只有当numbers的地址发生改变时,才会调用handler函数
                /* numbers: {
                    handler() {
                        console.log('numbers的地址发生了改变');
                    }
                }, */
                //Vue默认能够检测多层次数据结构的改变,但是watch函数默认不能检测
                numbers: {
                    //开启watch函数的深度检测,当numbers中的属性或地址发生改变时,调用handler函数
                    deep: true,
                    handler() {
                        console.log('numbers中的属性发生了改变');
                    }
                }
            }
        });
    </script>
</body>

</html>

效果展示:

image-20221018212436867

9.3 知识拓展

主要拓展三个点:

  1. 深度监视的简写形式
  2. 使用深度监视实现前面计算属性的案例
  3. 监视属性和计算属性的比较
  • 深度监视的简写形式:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>监视属性4</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            <h2>天气很{{info}}</h2>
            <button @click="changeWeather()">切换天气</button>
        </div>
        <script>
            Vue.config.productionTip = false;
            const vm = new Vue({
                el: '#root',
                data: {
                    isHot: true
                },
                computed: {
                    info() {
                        return this.isHot ? '热' : '冷';
                    }
                },
                methods: {
                    changeWeather() {
                        this.isHot = !this.isHot;
                    }
                },
                watch: {
                    //完整写法:
                    /* isHot: {
                        //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                        // immediate: true,
                        //开启watch的深度监视
                        // deep: true,
                        //当isHot属性发生改变时,handler函数就被调用
                        handler(newValue, oldValue) {
                            console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                        }
                    } */
                    //简写:(只需要handler时才能使用!)
                    isHot(newValue, oldValue) {
                        console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                    }
    
                }
            });
            //完整写法
            /*  vm.$watch('isHot', {
                 //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                 // immediate: true,
                 //开启watch的深度监视
                 // deep: true,
                 //当isHot属性发生改变时,handler函数就被调用
                 handler(newValue, oldValue) {
                     console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                 }
             }); */
            //简写:(只需要handler时才能使用!)
            vm.$watch('isHot', function(newValue, oldValue) {
                console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
            });
        </script>
    </body>
    
    </html>
    

    备注:使用vm配置监听属性和直接在watch中配置监听属性,是等价的。简写的代价是只能调用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>监视属性4</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            <h2>天气很{{info}}</h2>
            <button @click="changeWeather()">切换天气</button>
        </div>
        <script>
            Vue.config.productionTip = false;
            const vm = new Vue({
                el: '#root',
                data: {
                    isHot: true
                },
                computed: {
                    info() {
                        return this.isHot ? '热' : '冷';
                    }
                },
                methods: {
                    changeWeather() {
                        this.isHot = !this.isHot;
                    }
                },
                watch: {
                    //完整写法:
                    /* isHot: {
                        //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                        // immediate: true,
                        //开启watch的深度监视
                        // deep: true,
                        //当isHot属性发生改变时,handler函数就被调用
                        handler(newValue, oldValue) {
                            console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                        }
                    } */
                    //简写:(只需要handler时才能使用!)
                    isHot(newValue, oldValue) {
                        console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                    }
    
                }
            });
            //完整写法
            /*  vm.$watch('isHot', {
                 //程序初识时就执行handler(换句话说,就是当我们加上这个属性,保存后就执行handler函数)
                 // immediate: true,
                 //开启watch的深度监视
                 // deep: true,
                 //当isHot属性发生改变时,handler函数就被调用
                 handler(newValue, oldValue) {
                     console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
                 }
             }); */
            //简写:(只需要handler时才能使用!)
            vm.$watch('isHot', function(newValue, oldValue) {
                console.log('isHot未修改前:' + oldValue + ';' + 'isHot修改后:' + newValue);
            });
        </script>
    </body>
    
    </html>
    

    效果展示:

    430482200207096891

  • 监视属性和计算属性的比较

    从上面那个案例,可以发现使用监视属性watch实现联动效果好像比计算属性computed要复杂的多,这么说是不是如果实现联动效果,是不是可以全部使用计算属性来实现?

    答案是否定的!在一些特殊的地方还是需要使用监视属性来实现,比如延迟动态改变属性值,具体见下面代码👇

    <!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>计算属性5</title>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    </head>
    
    <body>
        <div id="root">
            姓: <input type="text" v-model="firstName"> <br> 名: <input type="text" v-model="secondName"> <br> 全名:
            <span>{{fullName}}</span>
        </div>
    </body>
    <script>
        Vue.config.productionTip = false;
        const vm = new Vue({
            el: '#root',
            data: {
                firstName: '张',
                secondName: '三',
                fullName: '张-三'
            }
            /* ,
                    computed: {
                        fullName: function() {
                            //直接无效,因为fullName的Getter没有返回值,这个返回值给了setTimeout函数
                            setTimeout(() => {
                                return this.firstName.slice(0, 3) + '-' + this.secondName;
                            })
                        }
                    } */
            ,
            watch: {
                firstName(newValue) {
                    setTimeout(() => {
                            // console.log(this);//指向Vue
                            this.fullName = newValue.slice(0, 3) + '-' + this.secondName;
                        }, 1000)
                        //这里一定要使用箭头函数,否则this是指向window的(这和methods中的函数是相反的!)
                        /*
                          setTimeout(function() {
                             console.log(this);//指向window
                             this.fullName = newValue.slice(0, 3) + '-' + this.secondName;
                         }) */
                },
                secondName(newValue) {
                    this.fullName = this.firstName + '-' + newValue;
                }
            }
        });
    </script>
    
    </html>
    

    知识点:普通函数有自己的this,箭头函数没有自己的this,当使用箭头函数式,函数内部的this会从上一级依次寻找

总结

  1. computed能完成的功能,watch都可以完成
  2. watch能完成的功能,compute不一定能够完成,例如:watch可以进行异步操作(上面的延迟功能)
  3. 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm对象或组件实例对象
  4. 所有不被Vue管理的函数(例如:定时器的回调函数、Ajax的回调函数、Promise的回调函数……),最好写成箭头函数,这样this的指向才能是vm对象或组件的实例化对象

10、动态绑定样式

本小节主要学习:

  • 动态修改class属性
  • 动态修改style属性
  • 动态修改class属性

    实现方式::class=""

    <!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>
        <!-- 引入开发版Vue -->
        <script src="./js/vue.js"></script>
    
        <style>
            .zero {
                color: aqua;
            }
            
            .first {
                width: 100px;
                height: 100px;
                background-color: pink;
            }
            
            .second {
                width: 100px;
                height: 100px;
                border: 2px solid greenyellow;
                border-radius: 10px;
            }
            
            .third {
                color: red;
            }
        </style>
    </head>
    
    <body>
        <div id="app">
            <div class="zero" :class="style">
                你好,Vue
            </div>
            <button @click="changeStyle">随机切换一种样式</button>
            <button @click="addStyle">添加一种样式</button>
            <button @click="removeStyle">移除一种样式</button>
            <button @click="addAll">添加多个样式</button> {{i}}
        </div>
    
        <script>
            const vm = new Vue({
                el: '#app',
                data: {
                    i: 2,
                    arr: ['first', 'second', 'third'],
                    style: []
                },
                methods: {
                    changeStyle() {
                        //只有style只有一种样式时,才能进行随机切换
                        if (this.i == this.arr.length - 1) {
                            const index = Math.floor(Math.random() * 3); //index取值范围:0~1
                            this.style.splice(0, this.style.length); //清空数组
                            this.style.push(this.arr[index]);
                        }
                    },
                    addStyle() {
                        if (this.i > -1) {
                            this.style.push(this.arr[this.i]);
                            this.i--;
                        }
                    },
                    removeStyle() {
                        //从最后数组最后一个元素开始删
                        if (this.i < this.arr.length - 1) {
                            this.style.shift();
                            this.i++;
                        } else if (this.style.length != 0) {
                            this.style.splice(0, this.style.length); //清空数组
                        }
                    },
                    addAll() {
                        //注意,不能去掉{{i}},必须是一个动态的数据,使用{{}}符号
                        for (let j = 0; j < this.arr.length; j++) {
                            this.style[j] = this.arr[j];
                        }
                        this.i = -1;
                    }
                }
            });
        </script>
    </body>
    
    </html>
    

    效果展示:

    430482200207096891
  • 动态修改style属性

    实现方式::style

    注意事项:对于两个名字的style内置属性,需要切换成小驼峰的方式

        <div id="app">
            <!-- 不使用Vue,硬编码 -->
            <h1 style="font-size: 16px;">张三</h1>
            <!-- 方式一 -->
            <h1 :style="{fontSize: fSize+'px'}">张三</h1>
            <!-- 方式二 -->
            <h1 :style="fontSizeObj">张三</h1>
    
        </div>
    
        <script>
            let vm = new Vue({
                el: '#app',
                data: {
                    fSize: 36,
                    fontSizeObj: {
                        // 注意这里的fontSize不能随便命名,必须有对应的CSS属性
                        fontSize: '36px'
                    }
                }
            });
        </script>
    

    效果展示:

    image-20221208192157273

11、条件渲染

  • v-if="表达式":当表达式为false时,不显示,前端无法查看到DOM结构。可以搭配v-else-if="表达式"v-else使用

    注意事项:当我们搭配后面两个指令时,中间一定不要被其它标签打断

        <div v-if="n==1">1</div>
        <div v-else-if="m==2">2</div>
        <!-- 后面无法生效,当n变成3时还会报错 -->
        <div>@</div>
        <div v-else="n==3">3</div>
    

    可以搭配template标签使用,不会影响DOM结构

  • v-show="表达式":当表达式为false时,不显示(等价于display:none),DOM结构仍然存在,前端可以查看到DOM结构

显示、隐藏切换频率高的用v-show,切换频率低的用v-if。因为添加和删除DOM结构需要消耗时间

12、列表渲染

测试使用v-if指令,它可以遍历数组、JSON对象、数字、字符串

  <div id="app">
        <ul>
            <!-- 遍历数组(这里的in可以用of代替) -->
            <li v-for="p in persons" :key="p.id">
                {{p.name}}-{{p.age}}
            </li>
            <!-- 遍历数组 -->
            <li v-for="(p,index) in persons" :key="index">
                {{p}}-{{index}}
            </li>
            <!-- 遍历JSON对象 -->
            <li v-for="(val,key) in student" :key="key">
                {{val}}-{{key}}
            </li>
            <!-- 遍历指定次数 -->
            <li v-for="(number,index) in 3" :key="index">
                {{number}}-{{index}}
            </li>
            <!-- 遍历字符串 -->
            <li v-for="(str,index) in strs" :key="index">
                {{str}}-{{index}}
            </li>
        </ul>
    </div>

</body>
<script>
    new Vue({
        el: '#app',
        data: {
            persons: [{
                id: '1',
                name: '张三',
                age: 18
            }, {
                id: '2',
                name: '李四',
                age: 19
            }, {
                id: '3',
                name: '王五',
                age: 20
            }],
            student: {
                name: '张三',
                age: 18,
                gender: '男'
            },
            strs: 'abc'
        }
    });
</script>

效果展示:

image-20221208210015865

13、key的作用和原理

Vue中有虚拟DOM,能够实现DOM的复用,复用的核心算法是diff算法。

首先,使用了Vue的标签,会先将你写的标签转成虚拟DOM,暂存在内存中,然后再转成真实DOM(能够再浏览器中查看到的DOM);当你的代码(也就是你写的标签)发生改变时,会重新转成虚拟DOM,然后从内存中使用diff算法进行虚拟DOM对比,当发现两个虚拟DOM的id一致时,他就会直接使用之前的虚拟DOM,这就避免了DOM的转换所消耗的时间,大大提高代码效率。

显然由于这个原因,所以要保障key值的唯一性,否则Vue就无法进行有效的虚拟DOM对比

示例:

    <div id="app">
        <button @click.once="add">点击添加一个输入框</button>
        <ul>
            <!-- 遍历数组 -->
            <li v-for="(p,index) in persons" :key="index">
                {{p.id}}--{{p.name}}--{{index}}
                <input type="text">
            </li>
        </ul>
    </div>

</body>
<script>
    new Vue({
        el: '#app',
        data: {
            persons: [{
                id: '1',
                name: '张三',
                age: 18
            }, {
                id: '2',
                name: '李四',
                age: 19
            }, {
                id: '3',
                name: '王五',
                age: 20
            }]
        },
        methods: {
            add() {
                let person = {
                    id: '4',
                    name: '赵六',
                    age: '19'
                };
                //将这个JSON对象添加再数组的前面
                this.persons.unshift(person);
            }
        }
    });
</script>

结果展示:

image-20221208214316210

这是由于key的顺序发生了改变,我再添加一个新的输入框是,是将新的输入框添加再最前面的,而key是index,导致旧的虚拟DOM往后移了一位,产生了错位

image-20221208214530422

总结

面试题: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是没有问题的。

14、过滤

14.1 列表过滤

本小节主要实现:模糊查询、以及降序和升序排序

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>过滤器</title>

    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="app">
        <h2>人员列表</h2>
        <input type="text" placeholder="请输入要搜索的名字" v-model="keywords">
        <button @click="sortType=0">原始排序</button>
        <button @click="sortType=1">升序排序</button>
        <button @click="sortType=2">降序排序</button>
        <h2>使用监视属性实现模糊查询</h2>
        <ul>
            <li v-for="(p,index) in searchPersons" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>
        <hr>
        <h2>使用计算属性实现模式查询</h2>
        <ul>
            <li v-for="(p,index) in computedPersons" :key="p.id">
                {{p.name}}-{{p.age}}-{{p.sex}}
            </li>
        </ul>

    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                keywords: '',
                /* 0:原始排序;1:升序;2:降序 */
                sortType: 0,
                persons: [{
                    id: 1,
                    name: '马冬梅',
                    age: 23,
                    sex: '女'
                }, {
                    id: 2,
                    name: '周冬雨',
                    age: 18,
                    sex: '女'
                }, {
                    id: 3,
                    name: '周杰伦',
                    age: 33,
                    sex: '男'
                }, {
                    id: 4,
                    name: '周润发',
                    age: 31,
                    sex: '男'
                }],
                searchPersons: []
            },
            // 使用监视属性实现模糊查询
            watch: {
                keywords: {
                    // 初始化时,就调用handler方法(当keyWords为null时,返回0)
                    immediate: true,
                    handler(val) {
                        // 当val非null,且val不存在p.name中,就会返回-1
                        this.searchPersons = this.persons.filter((p) => {
                            return p.name.indexOf(val) != -1
                        });
                        //由于监视属性,必须要keywords发生变化,才会执行handler函数,所以无法实现排序功能
                        /* const arr = this.persons.filter((p) => {
                            return p.name.indexOf(val) != -1
                        })
                        if (this.sortType) {
                            //sortType!=0,进行排序
                            arr.sort((p1, p2) => {
                                return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                            })
                        }
                        this.searchPersons = arr */
                    }

                }
            },
            // 使用计算属性实现模式查询
            computed: {
                computedPersons() {
                    /* return this.persons.filter((p) => {
                        return p.name.indexOf(this.keywords) != -1
                    }) */
                    const arr = this.persons.filter((p) => {
                        return p.name.indexOf(this.keywords) != -1
                    });
                    if (this.sortType) {
                        //sortType!=0,进行排序
                        arr.sort((p1, p2) => {
                            return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age
                        })
                    }
                    return arr
                }
            }
        });
    </script>
</body>

</html>

效果展示:

备注:就实现方式而言,两相比较,使用计算属性更优

430482200207096891

14.2 过滤器

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.6/dayjs.min.js"></script>
</head>
<div id="app">
    当前时间戳:<input type="text" size="100" v-model="nowTime"><br/> 计算属性实现时间戳转换:
    <input type="text" v-model="computedTime" size="100"><br/> methods实现时间戳转换:
    <input type="text" v-model="methodsTime" @click="getMethodsTime" size="100"><br/> 过滤器实现时间戳转换(无参数):
    <span>{{nowTime | getFilterTime}}</span><br/> 过滤器实现时间戳转换(有参数):
    <span>{{nowTime | getFilterTime('YYYY-MM-DD HH:mm:ss')}}</span><br/> 多个过滤器:
    <span>{{nowTime | getFilterTime('YYYY-MM-DD HH:mm:ss') | secondFilter}}</span><br/> 搭配v-bind使用:
    <input type="text" :value="msg | secondFilter"><br>

</div>
<script>
    Vue.config.productionTip = false;
    // 全局过滤器
    Vue.filter('myFilter', function(val) {
        return dayjs(val).format(str)
    });
    const vm = new Vue({
        el: '#app',
        data: {
            nowTime: new Date,
            methodsTime: '',
            msg: '搭配v-bind使用过滤器'
        },
        computed: {
            computedTime() {
                return dayjs(this.nowTime).format('YYYY-MM-DD HH:mm:ss')
            }
        },
        mounted() {
            this.getMethodsTime();
        },
        methods: {
            getMethodsTime() {
                this.methodsTime = dayjs(this.nowTime).format()
            }
        },
        filters: {
            getFilterTime(val, str) {
                //当str为null时,format会使用dayjs默认的格式
                return dayjs(val).format(str)
            },
            secondFilter(val) {
                //先执行上面那个过滤器,执行后的结果通过val传入这个过滤器
                return val.slice(0, 4)
            }
        }
    });
</script>

<body>

</body>
</html>

效果展示:

image-20221210213326064

15、数据更新时的底层原理

本小节

  • 给对象新增一个属性失效,Vue无法探测到直接添加的属性的(这是因为Vue底层实现数据监视,是使用数据代理,而数据代理需要属性具有getter和setter,如果直接给一个数据新增一个属性,不会进行数据加工,也就是转到_data中,从而不会有getter和setter,所以也就是会逃避vue的检测),而想要之后添加属性,可以使用以下两个API

    • vue.set(target,attribute,val)

    • vm.$set(target,attribute,val)

注意:target不能是vm,也不能是data,必须是data中的一个属性

<div id="app">
    <button @click="addSex">给学生添加一个性别属性</button>
    <h3>学生姓名:{{student.name}}</h3>
    <h3>学生年龄:{{student.age}}</h3>
    <h3 v-if="student.sex">学生性别:{{student.sex}}</h3>
</div>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            student: {
                name: '张三',
                age: 18,
                teacher: {
                    name: '李四',
                    age: 32
                }
            }
        },
        methods: {
            addSex() {
                //错误示范:
                // this.student.sex = '男';

                //方式一:使用Vue的API
                Vue.set(this.student, 'sex', '男');

                //方式二:使用vm的API
                // this.$set(this.student, 'sex', '男');
            }
        }
    });
</script>

效果展示:略……

  • 修改数组的值失效,对于数组而言,只有调用数组自身方法时,Vue才能够监测到(因为数组的修改,无法自动新增getter和setter进行实现,所以Vue就写死规定,只有通过数组自带的七个方法进行数据修改,才能监测到),直接使用赋值号=修改数组,Vue并不能够进行监测。

    数组自身拥有的七个方法:push(向数组的末尾添加一个或多个元素,并返回新的长度)\pop(删除数组最后一个元素,并返回值)\shift(把数组的第一个元素从其中删除,并返回第一个元素的值)\unshift(向数组的开头添加一个或更多元素,并返回新的长度)\splice\(替换数组指定位置的元素)\sort\(排序数组)\reverse(反转数组)

    <div id="app">
        <button @click="addSex">给学生添加一个性别属性</button>
        <h3>学生姓名:{{student.name}}</h3>
        <h3>学生年龄:{{student.age}}</h3>
        <h3 v-if="student.sex">学生性别:{{student.sex}}</h3>
        <button @click="updateHobby">点击修改学生爱好</button>
        <h3>学生爱好:</h3>
        <ul>
            <li v-for="(h, index) in hobby" :key="index">{{h}}</li>
        </ul>
    
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                student: {
                    name: '张三',
                    age: 18,
                    teacher: {
                        name: '李四',
                        age: 32
                    }
                },
                hobby: ['抽烟', '喝酒', '烫头']
            },
            methods: {
                updateHobby() {
                    //错误示范,直接报错:Cannot set properties of undefined (setting '0')"
                    //this.student.hobby[0] = "学习";
                    //方式一:
                    this.student.hobby.splice(0, 1, '学习');
                    // 方式二:
                    Vue.set(this.student.hobby, 1, '学习');
                    //方式三:
                    // this.$set(this.student.hobby, 1, '学习');
                }
            }
        });
    </script>
    

效果展示:

image-20221210184436333

16、内置指令和自定义指令

拓展知识:

对于表单数据的收集:

  1. 对于复选框(checkbox),如果不设置vlaue,Vue默认是获取它的checked属性的值
  2. 对于单选框(radio),如果设置vlaue,Vue默认是无法得到单选框的值的,需要设置value
  3. 数据转成JSON字符串,使用API:JSON.stringify()
  4. 表单提交时想执行函数,可以直接再form标签上使用@submit="函数名",如果不想要表单提交,可以加后缀.prevent

  • v-model修饰符:
    • v-model.number:自动将前端输入的字符转成数字,可以搭配HTML的type="number"一起使用
    • v-model.trim:去掉输入框前后的空格,中间的空格无法去除
    • v-model.lazy:失去焦点,才收集数据(默认是实时收集数据的)

16.1 内置指令

内置指令介绍:

			我们学过的指令:
					v-bind	: 单向绑定解析表达式, 可简写为 :xxx
					v-model	: 双向数据绑定
					v-for  	: 遍历数组/对象/字符串
					v-on   	: 绑定事件监听, 可简写为@
					v-if 	 	: 条件渲染(动态控制节点是否存存在)
					v-else 	: 条件渲染(动态控制节点是否存存在)
					v-show 	: 条件渲染 (动态控制节点是否展示)
			v-text指令:
					1.作用:向其所在的节点中渲染文本内容。
					2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
			v-html指令:
					1.作用:向指定节点中渲染包含html结构的内容。
					2.与插值语法的区别:
								(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
								(2).v-html可以识别html结构。
					3.严重注意:v-html有安全性问题!!!!
								(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
								(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!	
			v-cloak指令(没有值):
					1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
					2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
			v-once指令:
					1.v-once所在节点在初次动态渲染后,就视为静态内容了。
					2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
			v-pre指令:
					1.跳过其所在节点的编译过程。
					2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

16.2 自定义指令

Vue中的指令本质就是一个函数,对于自定义指令,我们可以使用directives进行配置

  • 实现方式一:以函数的形式实现

    示例,定义一个v-big指令,和v-text功能类似,但会把绑定的值放大

  • 实现方式二:以对象的形式实现

    示例,定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。

如果想要拿到父元素并修改父元素的样式、让指令所在DOM获取焦点,只能通过方式二来实现。总的来讲:方式二的使用范围大于方式一,但方式一更加简便,且适合大部分常规操作,方式一使用的更加普遍

<!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>
    <script src="./js/vue.js"></script>
</head>
<div id="app">
    <!-- 原生v-text -->
    <h2>当前n的值是:<span v-text="n"></span></h2>
    <!-- 自定义v-big -->
    <h2>将n放大十倍后的值是:<span v-big="n"></span></h2>
    <button @click="n++">点我n值加1</button><br/>
    <!-- 原生v-bind -->
    <input type="text" :value="n"><br>
    <!-- 自定义v-fbind -->
    <input type="text" v-fbind="n"><br>
    <!-- 自定义的全局指令 -->
    <input type="text" v-big2="n"><br>
    <input type="text" v-f-bind2="n">
</div>

<body>
    <script>
        Vue.config.productionTip = false
            //全局指令
        Vue.directive('big2', function(element, binding) {
            element.value = binding.value * 10
        });
        Vue.directive('f-bind2', {
            bind(element, binding) {
                element.value = binding.value
            },
            inserted(element, binding) {
                element.focus()
            },
            update(element, binding) {
                element.value = binding.value
            }
        })

        const vm = new Vue({
            el: '#app',
            data: {
                n: 1
            },
            directives: {
                //方式一:使用函数。这种方式更加精简,但是对于一些细节无法处理
                big(element, binding) {
                    console.log(this) //注意,此处的this是window并不是vm
                        //element是指令所在的DOM(即span标签),binding是绑定对象,含有指令所在的DOM的所有属性
                    element.innerText = binding.value * 10
                        //备注:一旦模板发生更新(也就是id=app这个区域的DOM发生更新),big函数就会被执行
                },
                //错误演示,使用方式一无法使input标签默认获取焦点(这是由于指令的执行时机决定的)
                /* fbind(element, binding) {
                    element.innerText = binding.value
                    element.focus()
                } */
                //方式二:使用对象的形式实现
                fbind: {
                    //指令与元素成功绑定时执行(一上来就执行)。第一执行
                    bind(element, binding) {
                        element.value = binding.value
                    },
                    //指令所在DOM被展示到页面时执行,第二执行
                    inserted(element, binding) {
                        element.focus()
                    },
                    //模板发生更新时执行,第三执行
                    update(element, binding) {
                        element.value = binding.value
                    }
                }
            }
        })
    </script>
</body>

</html>

备注:

  1. 指令定义时,不要加v-,指令使用时,需要加v-
  2. 指令命名时,使用kebab-case方式,不要使用cameCase方式命名,使用kebab-case命名的指令,在定义时记得使用引号包裹

效果展示:

430482200207096891

17、Vue实例化和生命周期

共8个四队钩子方法,对应Vue的8个生命周期

image-20221214143346537

<!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>
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="app">
        <h2 :style="{opacity}">欢迎学习Vue</h2>
        <button @click="stop">停止渐变</button>
    </div>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                opacity: 1
            },
            //Vue还未实例化,还未进行数据代理,无法通过vm访问到data和methods
            beforeCreate() {
                console.log("beforeCreate" + this);
                // debugger;
            },
            //Vue实例化完成,进行了数据代理,可以通过vm访问到data和methods,但还未生成虚拟DOM
            created() {
                console.log("created" + this);
                // debugger;
            },
            //页面呈现的都是未经Vue编译的DOM,此时虚拟DOM已生成,但未加载到页面上
            beforeMount() {
                //注意:此处的DOM操作最终都会无效,可以看前面的图加以理解
                console.log("beforeMount" + this);
                document.querySelector('h2').innerHTML = "你好Vue";
                // debugger;
            },
            //Vue完成模板的==初次==解析并把真实的DOM元素放入页面后(即挂载完毕)调用mounted函数
            mounted() {
                console.log("mounted" + this)
                this.change();
            },
            //模板更新前(页面和数据没有保持同步,内存中的数据已发生变化,但是页面中的数据没有发生变化)
            beforeUpdate() {
                console.log("beforeUpdate" + this);
                // debugger;
            },
            //模板更新就调用updated钩子方法,页面和数据同步
            updated() {
                console.log("updated" + this);
                //https://v2.cn.vuejs.org/v2/api/#vm-destroy
                // this.$destroy()
                // debugger;
            },
            methods: {
                change() {
                    this.timer = setInterval(() => {
                        this.opacity -= 0.01
                        if (this.opacity <= 0) this.opacity = 1
                    })
                },
                stop() {
                    clearInterval(this.timer);
                }
            },
            beforeDestroy() {
                console.log("beforeDestroy" + this);
                // debugger;
            },
            destroyed() {
                console.log("destroyed" + this);
                // debugger;
            },
        });
        //外部调用定时器实现(定时器直接会被浏览器的JS引擎调用)
        /* setInterval(() => {
            vm.opacity -= 0.01
            if (vm.opacity <= 0) vm.opacity = 1
        }) */
    </script>
</body>

</html>

测试beforeCreate钩子方法的作用:

image-20221214144433824

测试created钩子方法的作用:

image-20221214144546648

测试beforeMount钩子方法的作用:

430482200207096891

各阶段:

image-20221214183804678

备注:mounted:发送ajax请求,启动定时器等异步任务;beforeDestory:做收尾工作,如:清除定时器

参考资料

  • 尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通:B站学习视频
  • 介绍 — Vue.js (vuejs.org):Vue2官方文档
  • 简介 | Vue.js (vuejs.org):Vue3官方文档
  • Vue.js 模板语法 | 菜鸟教程 (runoob.com)
  • Vue.js是什么?它有什么特点?:C语言网Vue教程
  • 编程风格之声明式与命令式的区别
  • 什么是MVVM?
  • vue中的挂载是什么意思?
  • (8条消息) 箭头函数与普通函数的区别详解
  • vue中data是干嘛的? 有几种写法 ? 有什么区别?

在此致谢(^_^ゞ


  1. 数据的双向绑定,指当View的数据发生改变时,Model的数据也会发生改变,反之亦然 ↩︎

  2. 组件化模式,就是将各个不同的部分进行封装,从而降低给部分的耦合度,这样每个部分成为一个组件,具有更高地移植性 ↩︎

  3. 原生的JS是命令式编码,它关注编程的实现步骤,需要一步一步地编写代码向程序下达命令;而声明式编码是告诉程序,你该干嘛,具体实现由程序自己实现 ↩︎

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

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

相关文章

【算法训练-链表 三】【判断】判断链表中是否有环、判断链表是否为回文链表

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【链表的相关判断】&#xff0c;使用【链表】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为…

【HTML5高级第二篇】WebWorker多线程、EventSource事件推送、History历史操作

文章目录 一、多线程1.1 概述1.2 体会多线程1.3 多线程中数据传递和接收 二、事件推送2.1 概述2.2 onmessage 事件 三、history 一、多线程 1.1 概述 前端JS默认按照单线程去执行&#xff0c;一段时间内只能执行一件事情。举个栗子&#xff1a;比方说古代攻城游戏&#xff0c…

animate.css与vue中的v-if/v-show如何一起使用

第一步:在已有的vue项目中安装animate.css npm install animate.css --save第二步&#xff1a;在 main.js 引入 import animate.css第三步&#xff1a;如果在vue中使用了v-if 或者v-show 的话就不能直接在元素上加入animate的class。我们应该在v-if/v-show的元素外层添加tran…

微服务整合Seata1.5.2+Nacos2.2.1+SpringBoot

文章目录 一、下载seata server二、客户端配置-application.yml三、初始Mysql数据库四、导入初始配置到nacos五、启动测试 本文以seata-server-1.5.2&#xff0c;以配置中心、注册中心使用Nacos&#xff0c;store.modedb&#xff08;mysql&#xff09;为例进行操作。 Seata简介…

vue-cli3项目本地启用https,并用mkcert生成证书

在项目根目录下的vue.config.js文件中&#xff1a; // vue.config.js module.exports {devServer: {host:dev.nm.cngc// 此处开启 https,并加载本地证书&#xff08;否则浏览器左上角会提示不安全&#xff09;https: {cert: fs.readFileSync(path.join(_dirname,./cert.crt)…

Linux查端口占用的几种方式

在Linux中&#xff0c;你可以使用以下几种方式来查看端口的占用情况。 一、使用netstat命令 #安装netstat yum -y install net-tools #检测端口占用 netstat -npl | grep 端口# 几种常规用法 netstat -ntlp //查看当前所有tcp端口 netstat -ntulp | grep 80 //查看所有80端…

科技成果鉴定测试报告一般包含哪些测试内容?

软件测评报告 一、科技成果评价是需要做第三方软件测评报告&#xff0c;一般是证明技术指标点是否完善&#xff0c;覆盖主要申报内容&#xff0c;应用软件项目科技成果鉴定测试内容&#xff1a; &#xff08;一&#xff09;是否完成合同或计划任务书要求的指标&#xff1b; …

Chaes恶意软件的新Python变种以银行和物流业为目标

银行和物流行业正遭受一种名为 "Chaes "恶意软件变种的攻击。 Morphisec 在与《黑客新闻》分享的一份新的详细技术报告中说&#xff1a;“Chaes”经历了重大的改版&#xff0c;从完全用 Python 重写&#xff0c;到整体重新设计和增强通信协议&#xff0c;导致传统防…

upload-labs1-21关文件上传通关手册

upload-labs文件上传漏洞靶场 目录 upload-labs文件上传漏洞靶场第一关pass-01&#xff1a;第二关Pass-02第三关pass-03&#xff1a;第四关pass-04&#xff1a;第五关pass-05&#xff1a;第六关pass-06&#xff1a;第七关Pass-07第八关Pass-08第九关Pass-09第十关Pass-10第十一…

TikTok运营秘籍:助力品牌增长

在数字化时代&#xff0c;TikTok已成为品牌推广的热门渠道。本文将分享关于TikTok运营的关键策略和技巧&#xff0c;助您快速引爆品牌增长。 一.了解TikTok特点与用户群体 理解TikTok平台的特点和用户群体是成功运营的基础。TikTok以短视频为主&#xff0c;追求创意、趣味和娱…

怎么做手机App测试?app测试详细流程和方法介绍

APP测试 1、手机APP测试怎么做&#xff1f; 手机APP测试&#xff0c;主要针对的是android和ios两大主流操作系统&#xff0c;主要考虑的就是功能性、兼容性、稳定性、易用性&#xff08;也就是人机交互&#xff09;、性能。 手机APP测试前的准备&#xff1a; 1.使用同类型的…

【AI】机器学习——朴素贝叶斯

文章目录 2.1 贝叶斯定理2.1.1 贝叶斯公式推导条件概率变式 贝叶斯公式 2.1.2 贝叶斯定理2.1.3 贝叶斯决策基本思想 2.2 朴素贝叶斯2.2.1 朴素贝叶斯分类器思想2.2.2 条件独立性对似然概率计算的影响2.2.3 基本方法2.2.4 模型后验概率最大化损失函数期望风险最小化策略 2.2.5 朴…

网络技术六:TCP/UDP原理

TCP/UDP原理 命令行操作基础 命令类型 常见设备管理命令 H3C路由交换产品连接方法 使用console线本地连接 协议Serial&#xff0c;接口com口&#xff0c;波特率9600 适用于设备的初次调试 使用Telnet远程访问 适用于设备上架配置好后的维护管理 使用SSH远程访问 数据传输…

【Hive SQL 每日一题】统计用户连续下单的日期区间

文章目录 测试数据需求说明需求实现 测试数据 create table test(user_id string,order_date string);INSERT INTO test(user_id, order_date) VALUES(101, 2021-09-21),(101, 2021-09-22),(101, 2021-09-23),(101, 2021-09-27),(101, 2021-09-28),(101, 2021-09-29),(101, 20…

【Java SE】抽象类与接口

目录 【1】抽象类 【1.1】抽象类概念 【1.2】抽象类语法 【1.3】抽象类特性 【1.4】抽象类的作用 【2】接口 【2.1】接口的概念 【2.2】语法规则 【2.3】接口使用 【2.4】接口特性 【2.5】实现多个接口 【2.6】接口间的继承 【2.7】接口使用实例 【2.8】Clonable …

React + ASP.NET Core 项目笔记一:项目环境搭建(一)

不重要的目录标题 前提条件第一步&#xff1a;新建文件夹第二步&#xff1a;使用VS/ VS code/cmd 打开该文件夹第三步&#xff1a;安装依赖第四步&#xff1a;试运行react第五步&#xff1a;整理项目结构 前提条件 安装dotnet core sdk 安装Node.js npm 第一步&#xff1a;新…

亚马逊云科技人工智能内容审核服务:大大降低生成不安全内容的风险

生成式人工智能技术发展日新月异&#xff0c;现在已经能够根据文本输入生成文本和图像。Stable Diffusion是一种文本转图像模型&#xff0c;可以创建栩栩如生的图像应用。通过Amazon SageMaker JumpStart&#xff0c;使用Stable Diffusion模型轻松地从文本生成图像。 尽管生成式…

科技云报道:AI时代,对构建云安全提出了哪些新要求?

科技云报道原创。 随着企业上云的提速&#xff0c;一系列云安全问题也逐渐暴露出来&#xff0c;云安全问题得到重视&#xff0c;市场不断扩大。 Gartner 发布“2022 年中国 ICT 技术成熟度曲线”显示&#xff0c;云安全已处于技术萌芽期高点&#xff0c;预期在2-5年内有望达到…

HTML emoji整理 表情符号

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>测试</title></head><body><div style"font-size: 50px;">&#128276</div><script>let count 0d…

树的基本定义

树的基本术语 一个节点包括一下内容 父节点的地址值值左节点的地址值右节点的地址值 如果没有父节点或者没有左右节点&#xff0c;那么这些节点对应的位置是 null 常见术语 节点—树中的元素常称为节点 边—根和它的子树根&#xff08;如果存在&#xff09;之间形成边的边可…