Vue3和TypeScript学习笔记coderwhyDay05之v-model、组件化

v-model、组件化

  • 补充知识点
    • watch侦听器注意点
    • 深拷贝和浅拷贝
  • v-model基本使用和原理
    • v-model基本使用
    • v-model原理
    • v-model绑定其他表单类型
    • v-model的值绑定
    • v-model修饰符
  • Vue组件化
    • 组件的注册方式
      • 注册全局组件
      • 注册局部组件
      • 不推荐注册全局组件
      • 组件的名称
    • Vue的开发模式

补充知识点

watch侦听器注意点

 const App = {
      template: '#my-app',
      data() {
        return { //...   
      },
      watch: {
        info(newValue, oldValue) {
          console.log(newValue, oldValue);
        },
        "info.name": function(newName, oldName) {
          console.log(newName, oldName);
        }
      }
 }

1.不应该使用箭头函数来定义 watcher 函数 。因为箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例。

2.回调函数得到的参数为新值和旧值。
在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本。

深拷贝和浅拷贝

浅拷贝:比如assign()
先看下面这段代码。
定义info变量指向一个对象(info保存对象地址),该对象中有个属性friend也是对象(friend保存的也是对象的地址。)
const obj = Object.assign({}, info)将info拷贝一份给{},obj指向返回的对象。
修改info的name属性,不会导致obj.name改变。
修改info.firend.name,会导致obj.friend.name的改变。(info.friend和obj.friend保存同一个地址)

	const info = { name: "why", age: 18, friend: { name: "kobe" } };
    const obj = Object.assign({}, info);
    
    info.name = "kobe";
    console.log(obj.name);//why

    info.friend.name = "james";
    console.log(obj.friend.name);//james

Vue3和TypeScript学习笔记coderwhyDay05之v-model、组件化_第1张图片


深拷贝
const obj = JSON.parse(JSON.stringify(info));
info拷贝一份到obj,info无论怎么改变属性值,都不影响obj。即使改变info的对象属性的值也不影响obj

 	const info = { name: "why", age: 18, friend: { name: "kobe" } };
    const obj = JSON.parse(JSON.stringify(info));
    info.age = 20
    console.log(obj.age); //18
    info.friend.name = "james";
    console.log(obj.friend.name); //kobe

lodash库实现拷贝
1.引入lodash库

<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js">script>

2.浅拷贝

const info = { name: "why", age: 18, friend: { name: "kobe" } };
const obj = _.clone(info);//浅拷贝

深拷贝

const info = { name: "why", age: 18, friend: { name: "kobe" } };
const obj = _.cloneDeep(info)//深拷贝

info.friend.name = "james";
console.log(obj.friend.name); //kobe

备注:手写深拷贝参考这篇文章手写深拷贝

v-model基本使用和原理

v-model基本使用

1.v-model指令可在表单input、textarea以及select元素上创建双向数据绑定
2.根据控件类型自动选取正确的方法来更新元素
3.负责监听用户的输入事件来更新数据
实现功能:
Vue3和TypeScript学习笔记coderwhyDay05之v-model、组件化_第2张图片

<body>
  <div id="app">div>

  <template id="my-app">
    <input type="text" v-model="message">
    <h2>{{message}}h2>
  template>

  <script src="../js/vue.js">script>
  <script>
    const App = {
      template: '#my-app',
      data() {
        return {
          message: "Hello World"
        }
      },
    }

    Vue.createApp(App).mount('#app');
  script>
body>

v-model原理

v-bind绑定value属性的值
v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中

<input type="text" :value="message" @input="message=$event.target.value" />

<input type="text" v-model="message">

v-model绑定其他表单类型

绑定textarea文本框
绑定checkbox,单个勾选框和多个勾选框
绑定radio,选择其中一项
绑定select,选中一个值和选中多个值
实现效果:
Vue3和TypeScript学习笔记coderwhyDay05之v-model、组件化_第3张图片

<template id="my-app">
    
    <label for="intro">
      自我介绍
      <textarea name="intro" id="intro" cols="30" rows="10" v-model="intro">textarea>
    label>
    <h2>intro: {{intro}}h2>

    
    
    <label for="agree">
      <input id="agree" type="checkbox" v-model="isAgree"> 同意协议
    label>
    <h2>isAgree: {{isAgree}}h2>

    
    <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>

    
    <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>

    
    <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>
//......省略
data() {
        return {
          intro: "Hello World",
          isAgree: false,
          hobbies: ["basketball"],
          gender: "",
          fruit: "orange"
        }
 }
script>

v-model的值绑定

我们上面的案例中,大部分的值value都是固定好的。
在真实开发中,我们的数据来自服务器,那该怎么做呢?
先将值请求下来,绑定到data返回的对象中,再通过v-bind进行值	value的绑定。
这个过程就是值绑定。

v-model修饰符

v-model.lazy
默认情况下,v-model进行双向绑定,绑的是input事件,会在每次输入内容后就将最新值和绑定属性同步。
lazy修饰符:将绑定事件切换为change事件,只有在提交时(如回车)才会触发。

 <input type="text" v-model.lazy="message">

v-model.number
message总是string类型,设置type为number也是string类型。


<input type="number" v-model.number="message">

进行逻辑判断时,如果是string类型,在可以转化的情况下会进行隐式转换。

const score="100"
if(score>90){
	console.log("优秀")
}

如果希望转换为数字类型,使用.number修饰符


 <input type="text" v-model.number="message">

v-model.trim
自动过滤用户输入的首尾空白

 <input type="text" v-model.trim="message">

Vue组件化

无论三大框架,还是跨平台方案Flutter,甚至移动端,小程序的开发都使用组件化开发思想。
组件化:
1.一个完整的页面分成很多组件,每个组件用于实现页面一个功能模块,每个组件又可进行细分,组件本身可在多个地方复用。
2.createApp函数传入一个对象App,该对象本质就是一个组件,也是应用程序的根组件。
3.任何应用都会被抽象成一个组件树


组件的注册方式

全局组件:在任何其他的组件中都能够使用
局部组件:只能在注册的组件中才能使用
组件本身可以有自己的代码逻辑:自己的data、computed、methods等


注册全局组件

使用 全局创建的app来注册组件
component(组件名称,组件对象)来注册全局组件
在App组件的template中直接使用这个全局组件


<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>Documenttitle>
  head>
  <body>
    <div id="app">div>

    <template id="my-app">
      <component-a>component-a>
      <component-b>component-b>
      <component-name>component-name>
    template>

    <template id="component-a">
      <h2>{{title}}h2>
      <p>{{desc}}p>
      <button @click="btnClick">按钮点击button>
    template>

    <template id="component-b">
      <div>
        <input type="text" v-model="message"/>
        <h2>{{message}}h2>
      div>
    template>

    <template id="component-c">
      <h2>ComponentCh2>
    template>

    <script src="../js/vue.js">script>
    <script>
      const App = {
        template: "#my-app",
      };

      const app = Vue.createApp(App);

      // 使用app注册一个全局组件app.component()
      app.component("component-a", {
        template: "#component-a",
        data() {
          return {
            title: "我是标题",
            desc: "我是内容, 哈哈哈哈哈",
          };
        },
        methods: {
          btnClick() {
            console.log("按钮的点击");
          },
        },
      });

      app.component("component-b", {
        template: "#component-b",
        data() {
          return {
            message: "Hello World",
          };
        },
      });

      app.component('ComponentName', {
        template: "#component-c"
      })

      app.mount("#app");
    script>
  body>
html>


注册局部组件

在我们需要用到的组件中,通过 components属性选项来进行注册
该components选项对应的是一个对象,对象中的键值对是 组件的名称:组件对象


<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>Documenttitle>
head>
<body>
  
  <div id="app">div>

  <template id="my-app">
    <h2>{{message}}h2>
    <component-a>component-a>
  template>

  <template id="component-a">
    <h2>我是组件Ah2>
    <p>我是内容, 哈哈哈哈p>
  template>

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

    const ComponentA = {
      template: "#component-a"
    }
    const App = {
      template: '#my-app',
      components: {
        // key: 组件名称
        // value: 组件对象
        ComponentA: ComponentA
      },
      data() {
        return {
          message: "Hello World"
        }
      }
    }

    const app = Vue.createApp(App);
    app.mount('#app');
  script>
body>
html>

不推荐注册全局组件

全局组件在应用程序一开始就会全局注册完成,如果某些组件我们没有使用到,也会一起被注册。
比如注册3个全局组件:ComponentA、ComponentB、ComponentC。
在开发中只用到ComponentA和ComponentB,ComponentC没有被使用但依然全局注册,意味着我们用webpack等构建工具打包时,会对其也进行打包。
最终打包出的JavaScript包会有关于ComponentC内容,用户下载对应的JavaScript时也会增加包的大小


组件的名称

定义组件名有两种方式:短横线分割kebab-case,驼峰标识符PascalCase(注意是大驼峰)。
推荐使用:短横线分割命名方式。
驼峰标识直接在DOM中无法使用。
在vue文件中用驼峰标识OK。


Vue的开发模式

真实开发中,我们通过后缀.vue的single-file components(单文件组件SFC)来写代码。
但是浏览器是无法直接对.vue文件进行解析的。怎么办呢?使用webpack、vite、rollup等构建工具来对其进行打包。

在这种方式下,可以获得很多特性。比如代码高亮;ES6、CommonJS的模块化能力;组件作用域的CSS;可以使用预处理器,比如TypeScript、Babel、Less、Sass等。

那么,怎么样才可以使用SFC的.vue文件呢?我们有两种方式。
第一种,Vue CLI来创建项目。这种方式项目会默认帮我们配置好所有的配置选项,可在其中直接用vue文件。
第二种,使用webpack、vite、rollup等构建工具来对其进行打包。


以上笔记参考coderwhy老师的Vue3和TypeScript。
老师讲课链接:课程链接

你可能感兴趣的:(vue3和TypeScript)