【前端开发——vue3】学习笔记(1)——vue2简介、setup概述、ref与reactive创建

1. Vue3简介

<img src="images/1695089947298-161c1b47-eb86-42fb-b1f8-d6a4fcab8ee2.png" alt="image.png" style="zoom:30%;" />

1.1. 【性能的提升】

  • 打包大小减少41%。
  • 初次渲染快55%, 更新渲染快133%。
  • 内存减少54%。

1.2. 源码的升级】

  • 使用Proxy代替defineProperty实现响应式。
  • 重写虚拟DOM的实现和Tree-Shaking。

1.3. 【拥抱TypeScript

  • Vue3可以更好的支持TypeScript。

1.4. 【新的特性】

  1. Composition API(组合API):
    • setup
    • ref与reactive
    • computed与watch
  2. 新的内置组件:
    • Fragment
    • Teleport
    • Suspense
  3. 其他改变:
    • 新的生命周期钩子
    • data 选项应始终被声明为一个函数
    • 移除keyCode支持作为 v-on 的修饰符

2. 创建Vue3工程

2.1. 【基于 vue-cli 创建】

点击查看官方文档

备注:目前vue-cli已处于维护模式,官方推荐基于 Vite 创建项目。

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version## 安装或者升级你的@vue/cli 
npm install -g @vue/cli## 执行创建命令
vue create vue_test## 随后选择3.x##  Choose a version of Vue.js that you want to start the project with (Use arrow keys)
##  > 3.x
##    2.x

## 启动
cd vue_test
npm run serve

2.2. 【基于 vite 创建】(推荐)

vite 是新一代前端构建工具,官网地址:https://vitejs.cnvite的优势如下:

  • 轻量快速的热重载(HMR),能实现极速的服务启动。
  • 对 TypeScriptJSXCSS 等支持开箱即用。
  • 真正的按需编译,不再等待整个应用编译完成。
  • webpack构建 与 vite构建对比图如下: <img src="images/1683167182037-71c78210-8217-4e7d-9a83-e463035efbbe.png" alt="webpack构建" title="webpack构建" style="zoom:20%;box-shadow:0 0 10px black" /> <img src="images/1683167204081-582dc237-72bc-499e-9589-2cdfd452e62f.png" alt="vite构建" title="vite构建" style="zoom: 20%;box-shadow:0 0 10px black" />
## 1.创建命令
npm create vue@latest## 2.具体配置
## 配置项目名称
√ Project name: vue3_test

## 是否添加TypeScript支持
√ Add TypeScript?  Yes## 是否添加JSX支持
√ Add JSX Support?  No## 是否添加路由环境
√ Add Vue Router for Single Page Application development?  No## 是否添加pinia环境
√ Add Pinia for state management?  No## 是否添加单元测试
√ Add Vitest for Unit Testing?  No## 是否添加端到端测试方案
√ Add an End-to-End Testing Solution? » No## 是否添加ESLint语法检查
√ Add ESLint for code quality?  Yes## 是否添加Prettiert代码格式化
√ Add Prettier for code formatting?  No

自己动手编写一个App组件

<template>
  <div class="app">
    <h1>你好啊!</h1>
  </div>
</template>

<script lang="ts">
  export default {
    name:'App' //组件名
  }
</script>

<style>
  .app {
    background-color: #ddd;
    box-shadow: 0 0 10px;
    border-radius: 10px;
    padding: 20px;
  }
</style>

安装官方推荐的vscode插件:

<img src="images/volar.png" alt="Snipaste_2023-10-08_20-46-34" style="zoom:50%;" /> <img src="images/image-20231218085906380.png" alt="image-20231218085906380" style="zoom:42%;" />

总结:

  • Vite 项目中,index.html 是项目的入口文件,在项目最外层。
  • 加载index.html后,Vite 解析 <script type="module" src="xxx"> 指向的JavaScript
  • Vue3**中是通过 **createApp 函数创建一个应用实例。

2.3. 【一个简单的效果】

Vue3向下兼容Vue2语法,且Vue3中的模板中可以没有根标签

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">年龄+1</button>
    <button @click="showTel">点我查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'App',
    data() {
      return {
        name:'张三',
        age:18,
        tel:'13888888888'
      }
    },
    methods:{
      changeName(){
        this.name = 'zhang-san'
      },
      changeAge(){
        this.age += 1
      },
      showTel(){
        alert(this.tel)
      }
    },
  }
</script>

3. Vue3核心语法

3.1. OptionsAPI CompositionAPI

  • Vue2API设计是Options(配置)风格的。
  • Vue3API设计是Composition(组合)风格的。

Options API 的弊端

Options类型的 API,数据、方法、计算属性等,是分散在:datamethodscomputed中的,若想新增或者修改一个需求,就需要分别修改:datamethodscomputed,不便于维护和复用。

<img src="images/1696662197101-55d2b251-f6e5-47f4-b3f1-d8531bbf9279.gif" alt="1.gif" style="zoom:70%;border-radius:20px" /><img src="images/1696662200734-1bad8249-d7a2-423e-a3c3-ab4c110628be.gif" alt="2.gif" style="zoom:70%;border-radius:20px" />

Composition API 的优势

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

<img src="images/1696662249851-db6403a1-acb5-481a-88e0-e1e34d2ef53a.gif" alt="3.gif" style="height:300px;border-radius:10px" /><img src="images/1696662256560-7239b9f9-a770-43c1-9386-6cc12ef1e9c0.gif" alt="4.gif" style="height:300px;border-radius:10px" />

说明:以上四张动图原创作者:大帅老猿

3.2. 【拉开序幕的 setup

setup 概述

setupVue3中一个新的配置项,值是一个函数,它是 Composition API 表演的舞台,组件中所用到的:数据、方法、计算属性、监视......等等,均配置在setup中。

特点如下:

  • setup函数返回的对象中的内容,可直接在模板中使用。
  • setup中访问thisundefined
  • setup函数会在beforeCreate之前调用,它是“领先”所有钩子执行的。
  • <template>
      <div class="person">
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">年龄+1</button>
        <button @click="showTel">点我查看联系方式</button>
      </div>
    </template>
    
    <script lang="ts">
      export default {
        name:'Person',
        setup(){
          // 数据,原来写在data中(注意:此时的name、age、tel数据都不是响应式数据)
          let name = '张三'
          let age = 18
          let tel = '13888888888'
    
          // 方法,原来写在methods中
          function changeName(){
            name = 'zhang-san' //注意:此时这么修改name页面是不变化的
            console.log(name)
          }
          function changeAge(){
            age += 1 //注意:此时这么修改age页面是不变化的
            console.log(age)
          }
          function showTel(){
            alert(tel)
          }
    
          // 返回一个对象,对象中的内容,模板中可以直接使用
          return {name,age,tel,changeName,changeAge,showTel}
        }
      }
    </script>
    
  • setup 的返回值
  • 若返回一个对象:则对象中的:属性、方法等,在模板中均可以直接使用**(重点关注)。**
  • 若返回一个函数:则可以自定义渲染内容,代码如下:
  • setup(){
      return ()=> '你好啊!'
    }
    

  • Vue2 的配置(datamethos......)中可以访问到 setup中的属性、方法。
  • 但在setup不能访问到Vue2的配置(datamethos......)。
  • 如果与Vue2冲突,则setup优先。

setup 语法糖

setup函数有一个语法糖,这个语法糖,可以让我们把setup独立出去,代码如下:

<template>
  <div class="person">
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="changName">修改名字</button>
    <button @click="changAge">年龄+1</button>
    <button @click="showTel">点我查看联系方式</button>
  </div>
</template>

<script lang="ts">
  export default {
    name:'Person',
  }
</script>

<!-- 下面的写法是setup语法糖 -->
<script setup lang="ts">
  console.log(this) //undefined
  
  // 数据(注意:此时的name、age、tel都不是响应式数据)
  let name = '张三'
  let age = 18
  let tel = '13888888888'

  // 方法
  function changName(){
    name = '李四'//注意:此时这么修改name页面是不变化的
  }
  function changAge(){
    console.log(age)
    age += 1 //注意:此时这么修改age页面是不变化的
  }
  function showTel(){
    alert(tel)
  }
</script>

 扩展:上述代码,还需要编写一个不写setupscript标签,去指定组件名字,比较麻烦,我们可以借助vite中的插件简化

import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

export default defineConfig({
  plugins: [ VueSetupExtend() ]
})
  1. 第一步:npm i vite-plugin-vue-setup-extend -D
  2. 第二步:vite.config.ts
  3. 第三步:<script setup lang="ts" name="Person">

3.3. ref 创建:基本类型的响应式数据】

  • **作用:**定义响应式变量。
  • 语法:let xxx = ref(初始值)
  • **返回值:**一个RefImpl的实例对象,简称ref对象refref对象的value属性是响应式的
  • 注意点:
    • JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用即可。
    • 对于let name = ref('张三')来说,name不是响应式的,name.value是响应式的。
      <template>
        <div class="person">
          <h2>姓名:{{name}}</h2>
          <h2>年龄:{{age}}</h2>
          <button @click="changeName">修改名字</button>
          <button @click="changeAge">年龄+1</button>
          <button @click="showTel">点我查看联系方式</button>
        </div>
      </template>
      
      <script setup lang="ts" name="Person">
        import {ref} from 'vue'
        // name和age是一个RefImpl的实例对象,简称ref对象,它们的value属性是响应式的。
        let name = ref('张三')
        let age = ref(18)
        // tel就是一个普通的字符串,不是响应式的
        let tel = '13888888888'
      
        function changeName(){
          // JS中操作ref对象时候需要.value
          name.value = '李四'
          console.log(name.value)
      
          // 注意:name不是响应式的,name.value是响应式的,所以如下代码并不会引起页面的更新。
          // name = ref('zhang-san')
        }
        function changeAge(){
          // JS中操作ref对象时候需要.value
          age.value += 1 
          console.log(age.value)
        }
        function showTel(){
          alert(tel)
        }
      </script>
      

 3.4. reactive 创建:对象类型的响应式数据】

  • 作用:定义一个响应式对象(基本类型不要用它,要用ref,否则报错)
  • 语法:let 响应式对象= reactive(源对象)
  • **返回值:**一个Proxy的实例对象,简称:响应式对象。
  • 注意点:reactive定义的响应式数据是“深层次”的。 
    <template>
      <div class="person">
        <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
        <h2>游戏列表:</h2>
        <ul>
          <li v-for="g in games" :key="g.id">{{ g.name }}</li>
        </ul>
        <h2>测试:{{obj.a.b.c.d}}</h2>
        <button @click="changeCarPrice">修改汽车价格</button>
        <button @click="changeFirstGame">修改第一游戏</button>
        <button @click="test">测试</button>
      </div>
    </template>
    
    <script lang="ts" setup name="Person">
    import { reactive } from 'vue'
    
    // 数据
    let car = reactive({ brand: '奔驰', price: 100 })
    let games = reactive([
      { id: 'ahsgdyfa01', name: '英雄联盟' },
      { id: 'ahsgdyfa02', name: '王者荣耀' },
      { id: 'ahsgdyfa03', name: '原神' }
    ])
    let obj = reactive({
      a:{
        b:{
          c:{
            d:666
          }
        }
      }
    })
    
    function changeCarPrice() {
      car.price += 10
    }
    function changeFirstGame() {
      games[0].name = '流星蝴蝶剑'
    }
    function test(){
      obj.a.b.c.d = 999
    }
    </script>
    

3.5. ref 创建:对象类型的响应式数据】

  • 其实ref接收的数据可以是:基本类型对象类型
  • ref接收的是对象类型,内部其实也是调用了reactive函数。 
    <template>
      <div class="person">
        <h2>汽车信息:一台{{ car.brand }}汽车,价值{{ car.price }}万</h2>
        <h2>游戏列表:</h2>
        <ul>
          <li v-for="g in games" :key="g.id">{{ g.name }}</li>
        </ul>
        <h2>测试:{{obj.a.b.c.d}}</h2>
        <button @click="changeCarPrice">修改汽车价格</button>
        <button @click="changeFirstGame">修改第一游戏</button>
        <button @click="test">测试</button>
      </div>
    </template>
    
    <script lang="ts" setup name="Person">
    import { ref } from 'vue'
    
    // 数据
    let car = ref({ brand: '奔驰', price: 100 })
    let games = ref([
      { id: 'ahsgdyfa01', name: '英雄联盟' },
      { id: 'ahsgdyfa02', name: '王者荣耀' },
      { id: 'ahsgdyfa03', name: '原神' }
    ])
    let obj = ref({
      a:{
        b:{
          c:{
            d:666
          }
        }
      }
    })
    
    console.log(car)
    
    function changeCarPrice() {
      car.value.price += 10
    }
    function changeFirstGame() {
      games.value[0].name = '流星蝴蝶剑'
    }
    function test(){
      obj.value.a.b.c.d = 999
    }
    </script>
    

3.6. ref 对比 reactive

宏观角度看:

  1. ref用来定义:基本类型数据对象类型数据
  2. reactive用来定义:对象类型数据
  • 区别:
  • 1.ref创建的变量必须使用.value(可以使用volar插件自动添加.value)。

<img src="images/自动补充value.png" alt="自动补充value" style="zoom:50%;border-radius:20px" />

 2. reactive重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)。

  • 使用原则:
  1. 若需要一个基本类型的响应式数据,必须使用ref
  2. 若需要一个响应式对象,层级不深,refreactive都可以。
  3. 若需要一个响应式对象,且层级较深,推荐使用reactive

3.7. toRefs toRef

  • 作用:将一个响应式对象中的每一个属性,转换为ref对象。
  • 备注:toRefstoRef功能一致,但toRefs可以批量转换。
  • 语法如下: 
    <template>
      <div class="person">
        <h2>姓名:{{person.name}}</h2>
        <h2>年龄:{{person.age}}</h2>
        <h2>性别:{{person.gender}}</h2>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">修改年龄</button>
        <button @click="changeGender">修改性别</button>
      </div>
    </template>
    
    <script lang="ts" setup name="Person">
      import {ref,reactive,toRefs,toRef} from 'vue'
    
      // 数据
      let person = reactive({name:'张三', age:18, gender:'男'})
    	
      // 通过toRefs将person对象中的n个属性批量取出,且依然保持响应式的能力
      let {name,gender} =  toRefs(person)
    	
      // 通过toRef将person对象中的gender属性取出,且依然保持响应式的能力
      let age = toRef(person,'age')
    
      // 方法
      function changeName(){
        name.value += '~'
      }
      function changeAge(){
        age.value += 1
      }
      function changeGender(){
        gender.value = '女'
      }
    </script>
    

3.8. computed

作用:根据已有数据计算出新数据(和Vue2中的computed作用一致)。

<img src="images/computed.gif" style="zoom:20%;" />

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
    <button @click="changeFullName">全名改为:li-si</button>
  </div>
</template>

<script setup lang="ts" name="App">
  import {ref,computed} from 'vue'

  let firstName = ref('zhang')
  let lastName = ref('san')

  // 计算属性——只读取,不修改
  /* let fullName = computed(()=>{
    return firstName.value + '-' + lastName.value
  }) */


  // 计算属性——既读取又修改
  let fullName = computed({
    // 读取
    get(){
      return firstName.value + '-' + lastName.value
    },
    // 修改
    set(val){
      console.log('有人修改了fullName',val)
      firstName.value = val.split('-')[0]
      lastName.value = val.split('-')[1]
    }
  })

  function changeFullName(){
    fullName.value = 'li-si'
  } 
</script>

评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风铃子加油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值