重学vue(2, 3)及其生态+TypeScript 之 vue(上)

简介: 重学vue(2, 3)及其生态+TypeScript 之 vue

在此之前也做了好多个vue3项目,这次通过coderwhy老师的视频,系统的学习一下vue3。


项目一:仿知乎项目 github.com/zhang-glitc…


项目二: 数据大屏项目: github.com/zhang-glitc…


项目三: 自己构建的个人blog: github.com/zhang-glitc…


如何使用Vue呢?


Vue的本质,就是一个JavaScript的库。


  • 方式一:在页面中通过CDN的方式来引入;<script src="https://unpkg.com/vue@next"></script>


  • 方式二:下载Vue的JavaScript文件,并且自己手动引入;


  • 方式三:通过npm包管理工具安装使用它;


  • 方式四:直接通过Vue CLI创建项目,并且使用它; 简单使用 我们可以调用Vue.createApp()来创建一个应用实例,并通过mount将其挂载到指定的dom上。


<div id="app"></div>
  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const options = {
      template: '<h2>Hello Vue3</h2>'
    }
    const app = Vue.createApp(options);
    app.mount("#app")
  </script>


模板语法


React的开发模式:


  • React使用的jsx,所以对应的代码都是编写的类似于js的一种语法;


  • 之后通过Babel将jsx编译成 React.createElement 函数调用;


Vue也支持jsx的开发模式:


  • 但是大多数情况下,使用基于HTML的模板语法;


  • 在模板中,允许开发者以声明式的方式将DOM和底层组件实例的数据绑定在一起;


  • 在底层的实现中,Vue将模板编译成虚拟DOM渲染函数。


Mustache双大括号语法


如果我们希望把数据显示到模板(template)中,使用最多的语法是 “Mustache”语法 (双大括号) 的文本插值。


  • 并且我们前端提到过,data返回的对象是有添加到Vue的响应式系统中;


  • 当data中的数据发生改变时,对应的内容也会发生更新。


  • 当然,Mustache中不仅仅可以是data中的属性,也可以是一个JavaScript的表达式。


指令


渲染内容相关指令


  • v-once用于指定元素或者组件只渲染一次:


  • 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过


  • 该指令可以用于性能优化;


  • 如果是子节点,也是只会渲染一次。即使用v-once的标签中的内容都只会渲染一次。


  • v-text用于更新元素的 textContent


  • 等价于{{}}


  • 并且他会覆盖标签中的任何内容。


  • v-html用于将html字符串当做html渲染到页面,这个指令一般在个人blog渲染文章用的比较多。


  • 我们通过{{}}展示html字符串时,vue并不会对其进行特殊的解析。仍然渲染成html字符串。


  • 如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示;


  • v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签:


  • 跳过不需要编译的节点,加快编译的速度;


属性相关指令


  • v-bind 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。


  • 缩写:


  • 修饰符


  • .camel 将 kebab-case attribute 名转换为 camelCase。


  • .prop - 将一个绑定强制设置为一个 DOM property。


  • .attr - 将一个绑定强制设置为一个 DOM attribute。


  • 绑定class有两种方式:


  • 对象语法: 传入一个对象作为class的值。key为class属性值,value为一个boolean,看key是否绑定到该元素的class。如果想使用data中定义的变量作为class值,我们需要使用动态属性绑定[],下面的title将被看作是一个变量,而不是一个字符串。


<div :class="{active: isActive, [title]: true}">对象形式添加class</div>


  • 数组语法: 传入一个数组作为class的值。数组中的每个元素作为class属性值。如果遇到元素是表达式或者对象,那么就看其值是否是true。就被添加到class上。注意如果是元素值不加上引号,那么他将会去定义的data中查找是否有该变量值。例如下面的title


<div :class="['abc', title, isActive ? 'active': '', {active: isActive}]">
    数组形式添加class
</div>


  • 绑定style:某些样式我们需要根据数据动态来决定。


  • CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名


  • 对象语法:等同于写内联的css样式。只不过属性必须是字符串。如果不是字符串,那么他将被当做成变量,然后将去data中查找是否有该变量。


<div :style="{color: finalColor, 'font-size': '30px'}">对象形式</div>


  • 数组语法:基本不用。就是将键值对的样式对象当做元素放在数组中。


<div :style="[style1Obj, style2Obj]">数组形式</div>
    data() {
       return {
         message: "Hello World",
         style1Obj: {
           color: 'red',
           fontSize: '30px'
         },
         style2Obj: {
           textDecoration: "underline"
         }
       }
     }


  • 动态绑定自定义属性。通过:[自定义属性]的形式。


<div :[name]="value">动态绑定自定义属性</div>
    data() {
       return {
         name: "cba",
         value: "kobe"
       }
     }


  • 将对象数据映射到dom元素的属性。这个一般用于将inheritAttrs: false后,将父元素传入的非props属性挂载到指定的dom上。v-bind="$attrs"


// 这里的info将被写到到div上,成为div的一个个属性
   <div v-bind="info">将对象数据映射到dom元素的属性</div>
   <div :="info">将对象数据映射到dom元素的属性</div>
   data() {
       return {
         info: {
           name: "zh",
           age: 20
         }
       }
     }


事件指令


  • v-on: 用于绑定事件监听。


  • 简写: @


  • 修饰符


  • .stop - 调用 event.stopPropagation()。


  • .prevent - 调用 event.preventDefault()。


  • .capture - 添加事件侦听器时使用 capture 模式。


  • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。


  • .{keyAlias}- 仅当事件是从特定键触发时才触发回调。


  • .once - 只触发一次回调。


  • .lef - 只当点击鼠标左键时触发。


  • .right - 只当点击鼠标右键时触发。


  • .middle - 只当点击鼠标中键时触发。


  • .passive - { passive: true } 模式添加侦听器


  • 开发时基本上都是绑定一个function,但是如果需要绑定多个函数,我们就需要传入一个对象。


<div  v-on="{click: btn1Click, mousemove: mouseMove}"></div>
   <div  @="{click: btn1Click, mousemove: mouseMove}"></div>


  • 当通过methods中定义方法,以供@click调用时,需要注意参数问题:


  • 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。


  • 但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去


  • 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。


条件渲染相关指令


  • v-if


  • v-if是惰性的。


  • 当条件为false时,其判断的内容完全不会被渲染或者会被销毁掉。


  • 当条件为true时,才会真正渲染条件块中的内容。


  • 如果想要多个dom同时显示或者隐藏,我们可以将v-if写在template标签上,并且让其包裹该多个dom元素。


  • v-else(配合v-if使用)


  • v-else-if(配合v-if使用)


  • v-show


  • v-show是不能添加在template标签上


  • v-show不可以和v-else一起使用。


  • 本质是通过设置css的display的属性值来显示或者隐藏元素的。


列表渲染指令


  • v-for


  • 它既可以遍历对象也可以遍历数组


  • 格式:


  • "value in object / Array / Number";


  • "(value, key) in object / Array / Number";


  • "(value, key, index) in object";


  • v-for同时也支持数字的遍历。


  • 可以使用template来对多个元素进行包裹,而不是使用div来完成。


  • 需要结合key来使用。 v-for中的key是什么作用?


  • key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。


  • 如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。


  • 而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素。


VNode是什么?


VNode的全称是Virtual Node,也就是虚拟节点。事实上,无论是组件还是元素,它们最终在Vue中表示出来的都是一个个VNode,VNode的本质是一个JavaScript的对象。


网络异常,图片无法展示
|


虚拟DOM?


如果我们不只是一个简单的div,而是有一大堆的元素,那么它们应该会形成一个VNode Tree。然后就组成了虚拟DOM。


下面我们来看一个小案例


网络异常,图片无法展示
|


vue中的diff算法


网络异常,图片无法展示
|


没有添加key的处理过程


网络异常,图片无法展示
|


网络异常,图片无法展示
|


添加key的处理过程


网络异常,图片无法展示
|


网络异常,图片无法展示
|

网络异常,图片无法展示
|


网络异常,图片无法展示
|


表单指令


  • v-model: 用于表单数据和提供的数据双向绑定。


  • 在表单 <input><textarea><select> 元素上创建双向数据绑定。


  • 它会根据控件类型自动选取正确的方法来更新元素。


  • 它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。


  • 他的本质就是监听input事件,并且通过事件对象将值赋值给提供的数据。


  • 修饰符


  • .lazy: 将v-model的事件绑定从input转变为change事件。


  • .number: 将v-model绑定的值转化为数字


  • .trim: 将v-model绑定的值两边的空格去除。


  • 如果是复选框和多选框,v-model将给选中的值加入到绑定的数组中。并且每个选项都必须设置value属性。


<div id="app"></div>
      <template id="my-app">
        <!-- 1.绑定textarea -->
        <label for="intro">
          自我介绍
          <textarea name="intro" id="intro" cols="30" rows="10" v-model="intro"></textarea>
        </label>
        <h2>intro: {{intro}}</h2>
        <!-- 2.checkbox -->
        <!-- 2.1.单选框 -->
        <label for="agree">
          <input id="agree" type="checkbox" v-model="isAgree"> 同意协议
        </label>
        <h2>isAgree: {{isAgree}}</h2>
        <!-- 2.2.多选框 -->
        <span>你的爱好: </span>
        <label for="basketball">
          <input id="basketball" type="checkbox" v-model="hobbies" value="basketball"> 篮球
        </label>
        <label for="football">
          <input id="football" type="checkbox" v-model="hobbies" value="football"> 足球
        </label>
        <label for="tennis">
          <input id="tennis" type="checkbox" v-model="hobbies" value="tennis"> 网球
        </label>
        <h2>hobbies: {{hobbies}}</h2>
        <!-- 3.radio -->
        <span>你的爱好: </span>
        <label for="male">
          <input id="male" type="radio" v-model="gender" value="male">男
        </label>
        <label for="female">
          <input id="female" type="radio" v-model="gender" value="female">女
        </label>
        <h2>gender: {{gender}}</h2>
        <!-- 4.select -->
        <span>喜欢的水果: </span>
        <select v-model="fruit" multiple size="2">
          <option value="apple">苹果</option>
          <option value="orange">橘子</option>
          <option value="banana">香蕉</option>
        </select>
        <h2>fruit: {{fruit}}</h2>
      </template>
      <script src="../js/vue.js"></script>
      <script>
        const App = {
          template: '#my-app',
          data() {
            return {
              intro: "Hello World",
              isAgree: false,
              hobbies: ["basketball"],
              gender: "",
              fruit: "orange"
            }
          }
        }
        Vue.createApp(App).mount('#app');
      </script>


在组件中使用v-model指令


我们在表单元素中很容易的使用v-model来做双向绑定。他的原理是通过v-bind:value

的数据绑定和@input的事件监听


如果我们想要在自定义组件中使用v-model呢?该如何实现呢?


<!-- 组件上使用v-model -->
    <hy-input v-model="message"></hy-input>
    // 等加入上面
    <hy-input :modelValue="message" @update:model-value="message = $event"></hy-input>


其实在组件中使用v-model,默认情况下其实就是在组件中提供modelValueprops, 并且定义update:modelValue事件。


网络异常,图片无法展示
|


如果我们想要在表单元素上使用v-model来代替上面的input事件中的属性操作。我们可以借助computed来实现,并且提供getter, setter方法。


// 通过原生的双向绑定实现
    <input v-model="updateModelValue">
    props: {
      modelValue: String
    },
    emits: ["update:modelValue"],
    computed: {
      updateModelValue: {
        // 当改变modelValue时,就是调用setter方法
        set(value) {
          this.$emit("update:modelValue", value);
        },
        get() {
          return this.modelValue;
        }
      }
    },


如果我们想要自定义props来实现在组件上使用v-model,我们需要给v-model传递自定义属性名。


<hy-input v-model:title="title"></hy-input>
    data() {
      return {
        title: "title"
      }
    }


// 这里绑定的computed提供的属性
    <input v-model="updateTitle">
    props: {
      title: String 
    },
    emits: ["update:title"],
    computed: {
      updateTitle: {
        set(value) {
          this.$emit("update:title", value);
        },
        get() {
          return this.title;
        }
      }
    }


当我们想在自定义组件中绑定多个属性(即使用多个v-model)时,我们就需要通过上面自定义props绑定名来实现了。


<hy-input v-model="message" v-model:title="title"></hy-input>
    data() {
      return {
        message: "message",
        title: "title"
      }
    }


<input v-model="updateModelValue">
    <input v-model="updateTitle">
    props: {
      modelValue: String,
      title: String 
    },
    emits: ["update:modelValue", "update:title"],
    computed: {
      updateModelValue: {
        set(value) {
          this.$emit("update:modelValue", value);
        },
        get() {
          return this.modelValue;
        }
      },
      updateTitle: {
        set(value) {
          this.$emit("update:title", value);
        },
        get() {
          return this.title;
        }
      }
    }


网络异常,图片无法展示
|


optionsAPI


computed计算属性


我们知道,在模板中可以直接通过插值语法显示一些data中的数据。但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示。


  • 需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示


  • 在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算,在模板中放入太多的逻辑会让模板过重和难以维护。所以需要使用计算属性。


  • 如果多个地方都使用到,那么会有大量重复的代码,将它抽离到计算属性中,可以得到重用。 其实,我们也可以通过methods来实现这些逻辑,那为什么要用计算属性呢?他们有什么区别呢?


  • 调用逻辑函数的时候,计算属性不需要写(), 但是methods需要写()


  • 计算属性方法多次使用会有缓存,只会执行一次,再调用就会使用缓存的结果。当引用的数据发生变化他会重新结算结果,并缓存。但是methods方法不会存在缓存,每次调用对应的方法,都会重新执行一遍。 计算属性的gettersetter方法


计算属性在大多数情况下,只需要一个getter方法即可,所以我们会将计算属性直接写成一个函数。但是,如果我们确实想设置计算属性的值呢? 这个时候我们也可以给计算属性设置一个setter的方法,并且调用计算属性函数时,可以传入值。


methods: {
        handleName() {
        // 改变计算属性值,然后值传递到set方法中作为参数
          this.test = "llm zh"
        }
    },
    computed: {
        test: {
          get() {
            return this.name
          },
          set(value) {
            // console.log(value)
            this.name = value
          }
        }
      }


Vue内部是如何对我们传入的是一个getter,还是说是一个包含setter和getter的对象进行处理的呢?


事实上非常的简单,Vue源码内部只是做了一个逻辑判断而已


网络异常,图片无法展示
|


相关文章
|
2月前
|
JavaScript 前端开发
在Vue中使用TypeScript的常见问题有哪些?
在Vue中使用TypeScript的常见问题有哪些?
32 2
|
2月前
|
JavaScript 前端开发
在Vue中使用TypeScript的优缺点是什么?
在Vue中使用TypeScript的优缺点是什么?
16 0
|
2月前
|
JavaScript
在 Vue 中如何使用 TypeScript?
在 Vue 中如何使用 TypeScript?
16 0
|
3月前
|
JavaScript 安全 容器
Vue3 + setup + TypeScript: 构建现代、类型安全的Vue应用的关键技巧总结
当使用 setup 的时候,组件直接引入就可以了,不需要再自己手动注册
|
4月前
|
前端开发 JavaScript 测试技术
Vue3+Vite+TypeScript常用项目模块详解(下)
现在无论gitee还是github,越来越多的前端开源项目采用Vue3+Vite+TypeScript+Pinia+Elementplus+axios+Sass(css预编译语言等),其中还有各种项目配置比如eslint 校验代码工具配置等等,而我们想要进行前端项目的二次开发,就必须了解会使用这些东西,所以作者写了这篇文章进行简单的介绍。
|
4月前
|
JavaScript 前端开发 API
Vue3+Vite+TypeScript常用项目模块详解
现在无论gitee还是github,越来越多的前端开源项目采用Vue3+Vite+TypeScript+Pinia+Elementplus+axios+Sass(css预编译语言等),其中还有各种项目配置比如eslint 校验代码工具配置等等,而我们想要进行前端项目的二次开发,就必须了解会使用这些东西,所以作者写了这篇文章进行简单的介绍。
Vue3+Vite+TypeScript常用项目模块详解
|
17天前
|
JavaScript 编译器
TypeScript中类型守卫:缩小类型范围的艺术
【4月更文挑战第23天】TypeScript中的类型守卫是缩小类型范围的关键技术,它帮助我们在运行时确保值的精确类型,提升代码健壮性和可读性。类型守卫包括`typeof`(检查原始类型)、`instanceof`(检查类实例)和自定义类型守卫。通过这些方法,我们可以更好地处理联合类型、泛型和不同数据源,降低运行时错误,提高代码质量。
|
3月前
|
JavaScript 前端开发 安全
Apollo与TypeScript:强大类型检查在前端开发中的应用
Apollo与TypeScript:强大类型检查在前端开发中的应用
|
10天前
|
JavaScript 安全 前端开发
【TypeScript技术专栏】TypeScript中的类型推断与类型守卫
【4月更文挑战第30天】TypeScript的类型推断与类型守卫是提升代码安全的关键。类型推断自动识别变量类型,减少错误,包括基础、上下文、最佳通用和控制流类型推断。类型守卫则通过`typeof`、`instanceof`及自定义函数在运行时确认变量类型,确保类型安全。两者结合使用,优化开发体验,助力构建健壮应用。
|
10天前
|
JavaScript 前端开发 开发者
【TypeScript技术专栏】TypeScript类型系统与接口详解
【4月更文挑战第30天】TypeScript扩展JavaScript,引入静态类型检查以减少错误。其类型系统包括基本类型、数组等,而接口是定义对象结构的机制。接口描述对象外形,不涉及实现,可用于规定对象属性和方法。通过声明、实现接口,以及利用可选、只读属性,接口继承和合并,TypeScript增强了代码的健壮性和维护性。学习和掌握TypeScript的接口对于大型项目开发至关重要。