Vue3_03_v-model&&组件开发


一、v-model组件化

1.1v-model的基本原理

1147

双向绑定和响应式数据是两个不同的概念

1148

双向绑定数据,通俗说,如上我一个input输入框,我们可以通过message给它设置默认value,但是当用户在输入框改变value的时候,我们要取得这个新value,那么怎么取得呢?

方式一:手动实现,如上图中,每次用户输入东西改变value都会触发input事件,我们让这个事件触发一个methods方法,然后改变message拿到最新值即可 ; 但是这样太繁琐了

方式二:****通过v-model实现双向绑定

我们直接在input中写入指令,v-model="message"即可

那么message自动就有了双向绑定,vue底层会帮我们去进行input,单选框,多选框,等等各种标签互换数据。

1.2 v-model的初步使用

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

  <div id="app">
    <!-- 1.手动的实现了双向绑定 -->
    <!-- <input type="text" :value="message" @input="inputChange"> -->

    <!-- 2.v-model实现双向绑定 -->
    <!-- <input type="text" v-model="message"> -->

    <!-- 3.登录功能 -->
    <label for="account">
      账号:<input id="account" type="text" v-model="account">
    </label>
    <label for="password">
      密码:<input id="password" type="password" v-model="password">
    </label>

    <button @click="loginClick">登录</button>

    <h2>{{message}}</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          message: "Hello Model",
          account: "",
          password: ""
        }
      },
      methods: {
        inputChange(event) {
          this.message = event.target.value
        },
        loginClick() {
          const account = this.account
          const password = this.password

          // url发送axios网络请求
          console.log(account, password)
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>
</html>

如上代码,我们实际开发中的登入,就是通过双向绑定,拿到用户的账户密码,然后通过axios发送请求即可

注意:如果是单个i标签如input和这个data中的变量绑定,只需要和optionsApi中的data中返回的变量名一样就好了,此变量会自动记录input等可以输入内容的标签的内容,如果是多个标签绑定同一个data中的属性,就需要写value属性。

上面代码account变量,还有一个id为account,其实没什么联系,id删了不影响双向绑定(这里代码id是和lable标签配合使用,lable for必须和id一样)

tips:复习一下,单选框是需要name属性的,两个name属性相同的单选框,只能选取一个

1.3 textarea的双向绑定

<body>

  <div id="app">
    <textarea cols="30" rows="10" v-model="content" name=""></textarea>

    <p>输入的内容: {{content}}</p>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          content: ""
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

如上代码中textarea的name属性,input也有,这个name是用于表单提交数据的,我们这里是双向绑定获取变量,自动提交数据,所以name不写也可以。

1.4 v-model绑定checkbox

1150

如果是单选框的话,双向绑定的是一个布尔值,选中的话就是true,不选中就是false

如果是多选框,那么data中的属性应该是一个数组,多选框的input全部绑定同一个变量,而且必须有value值

<body>

  <div id="app">
    <!-- 1.checkbox单选框: 绑定到属性中的值是一个Boolean -->
    <label for="agree">
      <input id="agree" type="checkbox" v-model="isAgree"> 同意协议
    </label>
    <h2>单选框: {{isAgree}}</h2>
    <hr>

    <!-- 2.checkbox多选框: 绑定到属性中的值是一个Array -->
    <!-- 注意: 多选框当中, 必须明确的绑定一个value值 -->
    <div class="hobbies">
      <h2>请选择你的爱好:</h2>
      <label for="sing">
        <input id="sing" type="checkbox" v-model="hobbies" value="sing"></label>
      <label for="jump">
        <input id="jump" type="checkbox" v-model="hobbies" value="jump"></label>
      <label for="rap">
        <input id="rap" type="checkbox" v-model="hobbies" value="rap"> rap
      </label>
      <label for="basketball">
        <input id="basketball" type="checkbox" v-model="hobbies" value="basketball"> 篮球
      </label>
      <h2>爱好: {{hobbies}}</h2>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          isAgree: false,
          hobbies: []
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

为什么必须要value值?

当我们input的type为text,或者textarea这些单个框里面的内容,那么就不需要value值,双向绑定的就是data中的属性和单个框里面的内容。

但是多选框不一样,都是checkbox的input,都绑定同一个data中的属性,我们必须有一个东西来区分,所以要value。属性的改变也是改为value的值,这里就通过 v-model=”hobbies”来建立了多选框之间的联系

1151

注意:

这里的用户协议单选框也是checkbox生成的,只是没有和其他input有相同的v-model而已,所以和其他多选框没有联系,那么它也不需要value,如果被勾选就是true,不勾选就是false

为什么第一个也是多选框,为什么和下面的爱好多选框不一样?

在原生html中,我们需要把爱好多选框全部加一个name属性,表示它们是一起的,建立一个联系

但是在vue中,v-model自带了这个联系

我们可以给data中的属性一个默认值,那么页面的input中也会默认选中拥有和默认值一样的value的那个input

1152

1.5v-model绑定radio

<body>

  <div id="app">
    <div class="gender">
      <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}}</h2>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          gender: "female"
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

因为radio也是多个input绑定同一个data中的属性,如上图的的v-model=”gender”

所以它也必须写上 value

html中我们单选框必须通过name来识别哪几个单选框是一起的,这里v-model底层帮我们已经实现了这个逻辑

1.6v-model绑定select

select中的name属性也是原生中用于做提交数据的,我们也可以不写

复习:多选框和单选框默认选中都是写checked,select下拉框默认选中是写selected

不同点:那些input单选多选,v-model都是写在input里面,select标签v-model必须写在select标签里面,而不是选项option里面。

知识点:select标签是有一个属性multiple的,可以多选option,size属性是让多选的select在页面中显示出多少个option,这些在黑马的三剑客里面没学过。

<body>

  <div id="app">
    <!-- select的单选 -->
    <select v-model="fruit">
      <option value="apple">苹果</option>
      <option value="orange">橘子</option>
      <option value="banana">香蕉</option>
    </select>
    <h2>单选: {{fruit}}</h2>
    <hr>
    
    <!-- select的多选 -->
    <!-- 多选在操作的时候需要按住ctrl -->
    <select multiple size="3" v-model="fruits">
      <option value="apple">苹果</option>
      <option value="orange">橘子</option>
      <option value="banana">香蕉</option>
    </select>
    <h2>多选: {{fruits}}</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          fruit: "orange",
          fruits: []
        }
      },
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

1.7v-model的值绑定过程

1153

什么是值绑定,意思就是说1.6中的代码,option一般不是写死的,而是从服务器来的数据,我们通过v-for去遍历,叫做值绑定。

<body>

  <div id="app">
    <!-- 1.select的值绑定 -->
    <select multiple size="3" v-model="fruits">
      <option v-for="item in allFruits" 
              :key="item.value" 
              :value="item.value">
        {{item.text}}
      </option>
    </select>
    <h2>多选: {{fruits}}</h2>

    <hr>

    <!-- 2.checkbox的值绑定 -->
    <div class="hobbies">
      <h2>请选择你的爱好:</h2>
      <template v-for="item in allHobbies" :key="item.value">
        <label :for="item.value">
          <input :id="item.value" type="checkbox" v-model="hobbies" :value="item.value"> {{item.text}}
        </label>
      </template>
      <h2>爱好: {{hobbies}}</h2>
    </div>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          // 水果
          allFruits: [
            { value: "apple", text: "苹果" },
            { value: "orange", text: "橘子" },
            { value: "banana", text: "香蕉" },
          ],
          fruits: [],

          // 爱好
          allHobbies: [
            { value: "sing", text: "唱" },
            { value: "jump", text: "跳" },
            { value: "rap", text: "rap" },
            { value: "basketball", text: "篮球" }
          ],
          hobbies: []
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

1.8 v-model的修饰符

.lazy

1154

v-number

1155

1-如上图的代码,当我们的input是type=“text”那么,虽然我们默认的message给的是number数字,但是当用户在input中输入数字后,会变成string类型。如果我们需要它是number类型,就可以加上number修饰符

情况:

如果用户输入sss111,即使加了number修饰符,message还是会是字符串类型,message=”“sss111”

如果用户输入1111ss,那么message是数字型,message=1111

和parseint类型,它能去除后面的字符串,剩余的数字变成整形,但是无法去除前面的字符

2-input可以设置type=”number”那么用户只能输入数字(vue3中用户输入后还是number类型,vue2中即使设置了type=number,还是会变成字符串类型)

1156

trim修饰符

trim:修剪,割掉,剪下

去除用户输入的空格,用户在输入的时候,是能看到自己打了空格的,如在数据提交的时候,我们接收的是无空格的。

如用户注册账户名字为:jin nian,如果加了trim修饰符,那么服务器收到的就是jinnian

而且如果这个input有input或者文本改变事件,输入空格,因为有trim,这些事件根本不会触发。

修饰符可以多个一起使用,修饰符在实际开发中,也用的不太多

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

  <div id="app">
    <!-- 1.lazy: 绑定change事件  -->
    <input type="text" v-model.lazy="message">
    <h2>message: {{message}}</h2>

    <hr>

    <!-- 2.number: 自动将内容转换成数字 -->
    <input type="text" v-model.number="counter">
    <h2>counter:{{counter}}-{{typeof counter}}</h2>

    <input type="number" v-model="counter2">
    <h2>counter2:{{counter2}}-{{typeof counter2}}</h2>

    <hr>

    <!-- 3.trim: 去除收尾的空格 -->
    <input type="text" v-model.trim="content">
    <h2>content: {{content}}</h2>

    <hr>

    <!-- 4.使用多个修饰符 -->
    <input type="text" v-model.lazy.trim="content">
    <h2>content: {{content}}</h2>
  </div>
  
  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const app = Vue.createApp({
      // data: option api
      data() {
        return {
          message: "Hello Vue",
          counter: 0,
          counter2: 0,
          content: ""
        }
      },
      watch: {
        content(newValue) {
          console.log("content:", newValue)
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>
</html>

1.9vue组件化

1157

注册全局组件

<body>

  <div id="app">
    <!-- 1.内容一: -->
    <product-item></product-item>
    
    <!-- 2.内容二: -->
    <product-item></product-item>

    <!-- 3.内容三: -->
    <product-item></product-item>
  </div>


  <!-- 组件product-item的模板 -->
  <template id="item">
    <div class="product">
      <h2>我是商品</h2>
      <div>商品图片</div>
      <div>商品价格: <span>¥9.9</span></div>
      <p>商品描述信息, 9.9秒杀</p>
    </div>
  </template>
  
  <script src="../lib/vue.js"></script>
  <script>
    /*
      1.通过app.component(组件名称, 组件的对象)
      2.在App组件的模板中, 可以直接使用product-item的组件
    */

    // 1.组件: App组件(根组件)
    const App = {}

    // 2.创建app
    const app = Vue.createApp(App)

    // 3.注册一个全局组件
    // product-item全局组件
    app.component("product-item", {
      template: "#item"
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

其中有有个component方法,第一个参数是要注册的组件的名字,第二个参数是组件的对象代码,我们可以直接写代码,也可以抽取出去,如上的app.component,我们可以写为

const demo ={
    template: "#item"
  }
  app.component("product-item", demo)

其中template我们知道里面是写html标签代码的,我们也可以通过id选择器抽取出去,如上的#item就是从

<template id="item">
   <div class="product">
     <h2>我是商品</h2>
     <div>商品图片</div>
     <div>商品价格: <span>¥9.9</span></div>
     <p>商品描述信息, 9.9秒杀</p>
   </div>
 </template>

通过id选择器找到的数据。

注意:因为你注册的组件是从根组件app中分支出来的,所以你的组件标签必须写在被app绑定了的盒子内如下

<div id="app">
       <product-item></product-item>
</div>

你必须写在这里面,才能显示在浏览器中(全局组件可以写在其他组件的template中,但是如果要显示在浏览器中,组件标签必须写在根组件app绑定的盒子中)

1158

组件自己的逻辑和组件名称

逻辑:逻辑的意思就是注册的组件里面,也是可以写methods和data和watch等等optionApi的

组件名称:

1159

注册组件名称一般有两种,斜杠分隔单词或者大驼峰书写

问题:我们发现在页面中用大驼峰,浏览器提示不认识这个标签

因为我们现在的代码写在html中,html中的标签是不区分大小写的,我们写大驼峰自然没有作用

但是在以后的.vue文件中,我们把标签写在template中,就可以用大驼峰了

在实际开发中我们多用斜杠书写组件名字。

注意:注册的全局组件是无法使用根组件app中的optionApi的,如app的data中的变量,在注册组件中的template中无法使用。

注册局部组件

1160

<body>

  <div id="app">
    <home-nav></home-nav>

    <product-item></product-item>
    <product-item></product-item>
    <product-item></product-item>
  </div>
  
  <template id="product">
    <div class="product">
      <h2>{{title}}</h2>
      <p>商品描述, 限时折扣, 赶紧抢购</p>
      <p>价格: {{price}}</p>
      <button>收藏</button>
    </div>
  </template>

  <template id="nav">
    <div>-------------------- nav start ---------------</div>
    <h1>我是home-nav的组件</h1>
    <product-item></product-item>
    <div>-------------------- nav end ---------------</div>
  </template>

  <script src="../lib/vue.js"></script>
  <script>
    // 1.创建app
    const ProductItem = {
      template: "#product",
      data() {
        return {
          title: "我是product的title",
          price: 9.9
        }
      }
    }

    // 1.1.组件打算在哪里被使用
    const app = Vue.createApp({
      // components: option api
      components: {
        ProductItem,
        HomeNav: {
          template: "#nav",
          components: {
            ProductItem
          }
        }
      },
      // data: option api
      data() {
        return {
          message: "Hello Vue"
        }
      }
    })

    // 2.挂载app
    app.mount("#app")
  </script>
</body>

区别:

1-局部组件是在原根组件的optionApp中写一个components对象,键是组件名,值是组件的optionApi内容

2-全局组件是app.components(组件名,组件内容)

3-全局组件生成的标签可以写入其他组件的template内,局部组件只能写入生成它的组件内的template

二、Vue脚手架

1161

1162

1163

vue脚手架的安装与使用

1164

1166

创建命令为
vue create xxx(文件名字)

第一次创建项目,它会问你下载包的地址,下图中为镜像源,下载较快,我们选no就是用默认源,下载较慢但是版本肯定更准确.

1167

这里他们已经给我们准备好了两个预设,包含了babel和eslint,我们也可以选最后一个选择为手动选择特性

1168

然后会自动出现如下一些命令行界面,我们进行相应选择即可,空格为选中,再按空格为取消选中,a为全部选中

如下就是选中此项目,你会用到什么技术,脚手架自动给你配置环境

1165

然后选择vue的版本

1169

然后会提示bable的配置写入package.json还是单独的文件,我们一般选单独文件,更容易维护

1170

然后会提示,我们是否保存当前预设

什么叫预设呢,就是你刚刚设置的这些脚手架选项,就像你玩王者荣耀和吃鸡的时候,那套操作配置或者符文配置,我们再设置一个名称,下次类型项目就可以直接用这套预设.

1171

最后会让我们选择包管理器,一般现在还是用npm,但是一些公司慢慢向pnpm转型,好处在以往博客也写了,但是我们这里还是用npm,因为我也是初学.

1172

项目创建后的配置

1173

其中vue.config.js和webpack.config.js是差不多作用的

browserslistrc

1174

这个是配置打包后的代码是否需要兼容浏览器的,事实上它也是一个工具,它会自动去caniuse网站去查询各种浏览器版本的一些信息.

如上大于1%,意思就是兼容浏览器占市场份额1%以上的浏览器

last 2 version就是最后两个本吧

not dead的意思是当前浏览器还在维护,还在市场上存在

not ie 11 就是不需要去兼容ie11

事实上在开发中,很多人根本不认识这玩意,都是使用默认的.

js.config.json

这个文件是给开发工具vscode来用的

方便vscode给我们更友好的代码提示

总结:

1175

三、双向绑定


文章作者: 瑾年
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 瑾年 !
免责声明: 本站所发布的一切内容,包括但不限于IT技术资源,网络攻防教程及相应程序等文章仅限用于学习和研究目的:不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站部分信息与工具来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如有侵权请邮件(32671794@qq.com和jinnian770@gmail.com)与我们联系处理。
评论
  目录