vue3基础 ---- 上

目录

一.vue3介绍

1. 官网初识

2.环境搭建

2-1 线上尝试

2-2 CDN使用

2-3 Vue CLI

2-4 Vite

二.vue3基础

1.模板语法

1-1 我的第一个vue应用 

1-2 应用背后的真相

1-3 模板语法-新的皮肤来了

1-4 Todolist-来个案例

1-5 点击变心案例 - 是变色

1-6 v-html- 模板的陷阱

 2.class与style

2-1 class的绑定-方法太多了

2-2 style的绑定-同上

3.条件渲染

3-1 条件渲染-生或死的选择

 4.列表渲染

4-1 v-for列表渲染 - 影分身术

4-2 key设置 - 性能的保障

4-3 数组变动侦测

4-4 模糊搜索案例 


一.vue3介绍

1. 官网初识

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

https://cn.vuejs.org/

2.环境搭建

2-1 线上尝试

2-2 CDN使用

通过 CDN 使用 Vue 时,不涉及“构建步骤”。这使得设置更加简单,并且可以用于增强静态的 HTML 或与后端框架 集成。但是,你将无法使用单文件组件 (SFC) 语法。

2-3 Vue CLI

Vue CLI 是官方提供的基于 Webpack 的 Vue 工具链,它现在处于维护模式。我们建议使用 Vite 开始新的项目,除 非你依赖特定的 Webpack 的特性。在大多数情况下,Vite 将提供更优秀的开发体验。

2-4 Vite

Vite 是一个轻量级的、速度极快的构建工具,对 Vue SFC 提供第一优先级支持。作者是尤雨溪,同时也是 Vue 的 作者!

要使用 Vite 来创建一个 Vue 项目,非常简单:

$ npm init vue@latest

这个命令会安装和执行 create-vue,它是 Vue 提供的官方脚手架工具。跟随命令行的提示继续操作即可。

二.vue3基础

1.模板语法

1-1 我的第一个vue应用 

<body>
    <div id="box">
        {
   
   {10+20}}
        {
   
   {name}}
    </div>
</body>
<script>
    var app = Vue.createApp({
        data() {
            return {
                name: "贾公子"
            }
        }
    }).mount("#box")
</script>

推荐使用的 IDE 是 VSCode,配合 Vue 语言特性 (Volar) 插件。该插件提供了语法高亮、TypeScript 支持,以 及模板内表达式与组件 props 的智能提示。

Volar 取代了我们之前为 Vue 2 提供的官方 VSCode 扩展 Vetur。如果你之前已经安装了 Vetur,请确保在 Vue 3 的项目中禁用它。

1-2 应用背后的真相

(1)Object.deneProperty

无法监听数组的改变, 无法监听class改变, 无法监听Map Set结构。


    var obj = {}
    var obox = document.getElementById("box")
    Object.defineProperty(obj, "myname", {
        get() {
            console.log("有人访问了")
            return obox.innerHTML
        },
        set(value) {
            console.log("有人改变我了", value)
            obox.innerHTML = value
        }
    })

    obj.myname = '贾公子'
    console.log(obj.myname);

proxy 代理

访问代理对象进行拦截 支持数组的拦截

    var obj = {
    }
    var obox = document.getElementById("box")
    var vm = new Proxy(obj, {
        get(target, key) {
            console.log("get")
            return target[key]
        },
        set(target, key, value) {
            console.log("set")
            target[key] = value
            obox.innerHTML = value
        }
    })
    obj.a = 100
    vm.a = 200
    console.log(obj.a);
    console.log(vm.a);

1-3 模板语法-新的皮肤来了

 (1)最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):

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

双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。

(2)双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令: template

注意disbale不为false都是禁用

<div v-bind:id="dynamicId"></div>

v-bind 指令指示 Vue 将元素的 id attribute 与组件的 dynamicId 属性保持一致。如果绑定的值是 null 或者 undened ,那么该 attribute 将会从渲染的元素上移除。

(3)表达式的支持

{
   
   { number + 1 }}
{
   
   { ok ? 'YES' : 'NO' }}
{
   
   { message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>

(4)指令

<a v-on:click="doSomething"> ... </a>
<!-- 简写 -->
<a @click="doSomething"> ... </a>

1-4 Todolist-来个案例


<!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="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="box">
        <input type="text" v-model="mytext">
        <button @click="handleAdd">add</button>
        <ul>
            <li v-for="data,index in datalist">
                {
   
   {data}}
                <button @click="handleDel(index)">del</button>
            </li>
        </ul>
    </div>
    <script>
        var obj = {
            data() {
                return {
                    mytext: "",
                    datalist: ["11", "22", "33"],
                }
            },
            methods: {
                handleAdd(ev) {
                    this.datalist.push(this.mytext)
                },
                handleDel(index) {
                    this.datalist.splice(index, 1)
                }
            }
        }
        var app = Vue.createApp(obj).mount("#box")
    </script>
</body>

</html>

1-5 点击变心案例 - 是变色

<!--
* @作者: kerwin
-->
<!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="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
        .active {
            background-color: red;
        }
    </style>
</head>

<body>
    <div id="box">
        <ul>
            <li v-for="data,index in datalist" @click="handleclick(index)" :class="current===index?'active':''">
                {
   
   {data}}
            </li>
        </ul>
    </div>
    <script>
        var obj = {
            data() {
                return {
                    datalist: ["11", "22", "33"],
                    current: 0
                }
            },
            methods: {
                handleclick(index) {
                    this.current = index
                }
            }
        }
        var app = Vue.createApp(obj).mount("#box")
    </script>
</body>

</html>

1-6 v-html- 模板的陷阱

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:

<p>Using text interpolation: {
   
   { rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

 2.class与style

2-1 class的绑定-方法太多了

对象写法

data() {
  return {
    classObject: {
      active: true,
      'text-danger': false
    }
  }
}
<div :class="classObject"></div>

数组写法

data() {
    return {
        activeClass: 'active',
        errorClass: 'text-danger'
    }
}
<div :class="[activeClass, errorClass]"></div>

2-2 style的绑定-同上

对象写法

     data() {
            return {
                styleObject: {
                    color: 'red',
                    fontSize: '130px'
                }
            }
        }
        <div :style="styleObject">11</div>

数组写法


<body>
    <div id="box">
        <div :style="arr">11</div>
        <div @click="handleAjax">请求</div>
    </div>

</body>
<script>
    var obj = {
        data() {
            return {
                arr: [{
                    width: "200px",
                    height: "200px",
                    backgroundSize: "cover"
                }],
            }
        },
        methods: {
            handleAjax() {
                this.arr.push({
                    backgroundImage: "url(https://pic.maizuo.com/usr/movie/862ab6736237acd11599e5eecbbc83d7.jpg?x-ossprocess=image/quality,Q_70)"
                })
            },
        },
    }
    var app = Vue.createApp(obj).mount("#box")
</script>

3.条件渲染

3-1 条件渲染-生或死的选择

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被 渲染。

相比之下, v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说, v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 vshow 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

template包装 不会多数据结构

<body>
    <div id="box">
        <ul>
            <li v-for="item,index in datalist">
                {
   
   {item.title}}
                <div v-if="item.state===0">
                    未付款
                </div>
                <div v-else-if="item.state===1">
                    未发货
                </div>
                <div v-else-if="item.state===2">
                    已发货
                </div>
                <div v-else>
                    已完成
                </div>
            </li>
        </ul>
    </div>

</body>
<script>
    var obj = {
        data() {
            return {
                datalist: [
                    {
                        state: 0,
                        title: "111"
                    },
                    {
                        state: 1,
                        title: "222"
                    },
                    {
                        state: 2,
                        title: "333"
                    }
                ]
            }
        },

    }
    var app = Vue.createApp(obj).mount("#box")
</script>

 4.列表渲染

4-1 v-for列表渲染 - 影分身术

v-for与对象

小括号

解构赋值

in===of(js迭代器)

<body>
    <div id="box">
      <li v-for="(value,key,index) of myObject">
         {
   
   {key}}-- {
   
   { value }}--{
   
   {index}}
      </li>
    </div>

</body>
<script>
    var obj = {
        data() {
            return {
                myObject: {
                    title: 'How to do lists in Vue',
                    author: 'Jane Doe',
                    publishedAt: '2016-04-10'
                }
            }
        }
    }
    var app = Vue.createApp(obj).mount("#box")
</script>

v-for和v-if的优先级

永远不要把 v-if 和 v-for 同时用在一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)

如果避免出现这种情况,则在外层嵌套 template (页面渲染不生成dom节点),再这一层进行 v-if 判断,然后再内部进行 v-for 循环

<template v-for="(item) in textValue">
      <div  :key="item.text" v-if="item.show" >{
   
   {item.text}}</div>
</template>

4-2 key设置 - 性能的保障

Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对 应的块提供一个唯一的 key attribute:

key就是一个标识,被使用在Vue中。再详细一点,key被使用在Vue中的虚拟DOM中,并不会出现在真实DOM中。

1.以列表的形式展示一组人员信息

<body>
    <div id="box">
        <h2>人员列表</h2>
        <ul>
            <li v-for="(p,index) in persons">
                {
   
   {p.name}}-{
   
   {p.age}}
            </li>
        </ul>

    </div>

</body>
<script>
    var obj = {
        data() {
            return {
                persons: [
                    { 'id': '001', 'name': '张三', 'age': '18' },
                    { 'id': '002', 'name': '李四', 'age': '19' },
                    { 'id': '003', 'name': '王五', 'age': '20' }
                ],
                msg: '11'
            }

        }
    }

    var app = Vue.createApp(obj).mount("#box")
</script>

这个html文件在浏览器中打开如下图所示。

image-20211011224230413

而上述示例html文件中并没有使用到key,似乎也没有问题。当然,单纯地展示数据,不写key是不会存在问题的。

现在我们为上述示例加上key,这里以每条数据的id为key

<li v-for="(p,index) in persons" :key="p.id">
    {
   
   {p.name}}-{
   
   {p.age}}
</li>

加上key的展示结果和上图结果一模一样。

image-20211011224928540

而如果我们在浏览器上查看元素,不会看到key的存在。

image-20211011225246624

截至目前,我们可以得到两个结论:

1. 只做数据展示用,不写key是没有任何影响的;

2.key不会出现在真实DOM中

实际上,即使不写key,Vue在生成真实DOM时,也用到了key,默认是数据索引(index)

我们把key替换为index,展示的数据不会产生任何改变。

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

2 修改一下上述示例

在展示人员信息的基础上显示索引,并且添加一个按钮,功能是在头部添加人员信息

对上述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>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="box">
        <h2>人员列表</h2>
        <button @click="add">添加一个老刘</button>
        <ul>
            <li v-for="(p,index) in persons">
                {
   
   {p.name}}-{
   
   {p.age}}-{
   
   {index}}
            </li>
        </ul>

    </div>

</body>
<script>
    var obj = {
        data() {
            return {
                persons: [
                    { 'id': '001', 'name': '张三', 'age': '18' },
                    { 'id': '002', 'name': '李四', 'age': '19' },
                    { 'id': '003', 'name': '王五', 'age': '20' }
                ],

            }

        },
        methods: {
            add() {
                const p = { 'id': '004', 'name': '老刘', 'age': '40' }
                this.persons.unshift(p)
            }
        }

    }

    var app = Vue.createApp(obj).mount("#box")
</script>

</html>
 
 

我们可以看到,张三、李四、王五的索引分为别0,1,2

image-20211011230442273

点击按钮,添加一个新人物,这个时候索引发生了变化,新添加的人物“老刘”变为了索引0,似乎对,也似乎不对

image-20211011230815984

当然,单纯地讨论索引,这里一点问题也没有,下面举一个新例子,来说说“不对“在哪里

3 再修改一下示例

不展示索引了,改为输入框,在每个人物后面的输入框内写上人物的姓,观察新插入数据后原始数据的变化

<li v-for="(p,index) in persons" :key="index">
    {
   
   {p.name}}-{
   
   {p.age}}
    <input type="text">
</li>

实际效果就是下图这样

image-20211011231349758

到这里,似乎没有什么不对,接下来就是见证奇迹的时刻

添加老刘,出现了问题,和我们预想的不一样。

image-20211011231548484

这是key为index的情况,如果修改为数据的唯一标识,则不会产生这样的问题。

<li v-for="(p,index) in persons" :key="p.id">
    {
   
   {p.name}}-{
   
   {p.age}}
    <input type="text">
</li>

诶,这就是我们想要的。

image-20211011231848647
列表内有输入内容,后续操作破坏了原始顺序,如果以index作为key,就会产生错误DOM

4,key的实现原理

要解释key的实现原理,就要引入Vue一个十分重要的概念——【虚拟DOM】。

给出一组数据,Vue要把这些数据渲染到页面上,首先要生成【虚拟DOM】,然后根据【虚拟DOM】去生成【真实的DOM】。如果数据发生了改变,Vue会生成【新的虚拟DOM】,注意,这个【新的虚拟DOM】并不会直接生成【新的真实DOM】,否则虚拟DOM一点用处也没有了。

Vue的操作是,拿根据新的数据生成的【新的虚拟DOM】与之前的【真实的DOM】去做比较,如果相同,直接延用即可(“拿来主义”);如果不同,则生成新的DOM对象。

在这个过程中key扮演了很重要的角色。

根据最后一个示例进行剖析。

key为index的情况。

根据数据生成【真实DOM】的流程如下:(注意,下图的真实DOM中输入框里的内容为生成页面后手动添加)

在这里插入图片描述

然后,添加人物“老刘”,获取到一组新数据

在这里插入图片描述

Vue拿新数据生成【新的虚拟DOM】


在生成真实DOM,就需要用新生成的虚拟DOM和原来的真实DOM作比较(一条一条分析)

在这里插入图片描述

对比第一条,key为0,找到旧DOM中key为0的数据,发现“老刘-40”和“张三-18”不同,渲染新的数据“老刘-40”到页面上;再往后,发现同为输入框,不必重新渲染,直接使用原来真实DOM的内容。第一条内容就出现了,而这个输入框还携带有张三的姓。

在这里插入图片描述

对比第二条,key为1,找到旧DOM中key为1的数据,发现“张三-18”和“李四-19”不同,渲染新的数据“张三-18”到页面上;再往后,发现同为输入框,不必重新渲染,直接使用原来真实DOM的内容。第二条内容就出现了,而这个输入框还携带有李四的姓

在这里插入图片描述

之后同理。

回顾这个过程,key是作为虚拟DOM中对象的唯一标识,标识出了数据的“身份信息”,Vue在虚拟DOM中会根据这个“身份标识”去对比内容,设计的初衷是为了节省资源开支,不必渲染重复的部分。在本示例中,不但带来了效率问题,还渲染出了错误的DOM,后果非常严重。

2. key为id的情况。
直接进入添加“老刘”后的新旧DOM对比。

在这里插入图片描述

对比第一条,key为‘004’,发现在旧DOM中并不存在,直接生成“老刘-40”和新的输入框。

对比第二条,key为‘001’,发现旧DOM中key为‘001’的数据相同,直接将“张三-18”和输入框拿过来使用。

……

最后生成正确的DOM,节省了资源开支。

总结
推荐使用数据的唯一标识作为key,比如id,身份证号,手机号等等,通常这些数据由后端提供。

后续操作不破坏原来数据顺序的话,使用index作为key也没有任何问题。

4-3 数组变动侦测

vue3

Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  •  splice()
  • sort()
  • reverse()

对于一些不可变 (immutable) 方法,例如 filter() , concat() 和 slice() ,这些都不会更改原数组,而总是返回一个 新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的

vue2

一、数组
1.  不能监听的情况
 直接通过下标赋值  arr[i] = value ,直接修改数组长度 arr.length = newLen

2.  替代做法

(1)修改值

  • 1. Vue.set(arr, index, newvalue)
  • 2. vm.$set(arr, index, newvalue)
  • 3. arr.splice(index, 1, newvalue)

(2) 修改数组长度, arr.splice(newLen)

调用数组的pop、push、shift、unshift、splice、sort、reverse等方法时是可以监听到数组的变化的vue内部相当于重写了数组的原型,劫持了这七个方法

二、对象
不能监听的情况 属性的新增和删除

obj.newkey=newvalue

delete obj.key

2. 替代做法
  新增

1. Vue.set(obj, newkey, newvalue)
2. vm.$set(obj, newkey, newvalue)
3. obj = Object.assign({}, obj, {newkey1: newvalue1, newkey2: newvalue2})

  删除

1. Vue.delete(obj, key)
2. vm.$delete(obj, key)


三、分析 vue 2 无法监听数组和对象的这些变化的原因


首先,vue2是通过Object.defineProperty(obj, key, value)这种方式监听数据的

1. 对于数组
Object.defineProperty()是可以对数组实现监听操作的,但是vue并没有实现这个功能,因为数组长度不定而且数据可能会很多,如果对每一个数据都实现监听,性能代价太大

但是注意:数组中的元素是引用类型时是会被监听的

2. 对象
Object.defineProperty()针对的是对象的某个属性,而且这个操作在vue的初始化阶段就完成了,所以新增的属性无法监听,通过set方法新增对象就相当于初始化阶段的数据响应式处理

vue 3是通过proxy直接代理整个对象来实现的,而不是像Object.defineProperty针对某个属性。所以,只需做一层代理就可以监听同级结构下的所有属性变化,包括新增属性和删除属性

4-4 模糊搜索案例 

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="box">
        <input type="text" v-model="mytext" />
        <ul>
            <li v-for="data in filterList()" :key="data">
                {
   
   {data}}
            </li>
        </ul>
    </div>
    <script>
        var obj = {
            data() {
                return {
                    mytext: "",
                    datalist: ["aaa", "abb", "aab", "bcc", "abc", "bcd", "add", "acd"]
                }
            },
            methods: {
                filterList(evt) {
                    return this.datalist.filter(item => item.includes(this.mytext))
                }
            }
        }
        Vue.createApp(obj).mount("#box")
    </script>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/qq_63358859/article/details/131340423
今日推荐