一、v-model组件化
1.1v-model的基本原理
双向绑定和响应式数据是两个不同的概念
双向绑定数据,通俗说,如上我一个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
如果只是单选框的话,双向绑定的是一个布尔值,选中的话就是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中的属性,如果点击了就是true,那么多checkbox类型的input,怎么区分是哪个多选框被点击了? 所以我们必须有一个东西来区分,所以要value。
注意:
这里的用户协议单选框也是checkbox生成的,但是没有和其他input绑定相同的v-model,所以和其他多选框没有联系,那么它也不需要value,如果被勾选就是true,不勾选就是false
为什么第一个也是多选框,为什么和下面的爱好多选框不一样?
在原生html中,我们需要把爱好多选框全部加一个name属性,表示它们是一起的,建立一个联系
但是在vue中,v-model自带了这个联系
我们可以给data中的属性一个默认值,那么页面的input中也会默认选中拥有和默认值一样的value的那个input
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的值绑定过程
什么是值绑定,意思就是说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
v-number
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中用户输入后还是nu mber类型,vue2中即使设置了type=number,还是会变成字符串类型)
trim修饰符
trim:修剪,割掉,剪下
去除用户输入的空格,用户在输入的时候,是能看到自己打了空格的,如在数据提交的时候,我们接收的是无空格的。
如用户注册账户名字为:jin nian,如果加了trim修饰符,那么服务器收到的就是jinnian
而且如果这个input有input或者文本改变事件,输入空格,因为有trim,这些事件根本不会触发。
修饰符可以多个一起使用,修饰符在实际开发中,也用的不太多 ,点击事件也可以多个
<input type="text" v-model.lazy.trim="content">
//v-on:click.stop.prevent
<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组件化
搞明白组件化,什么全局组件,局部组件,只要搞清除它们和根组件的关系就好了。
1-根组件就是传入const app =Vue.createApp()的那个对象
2-app就是根组件的组件名,经过ceateApp这个函数方法底层一系列运作,app就可以挂载到html里面了
3-全局组件就是在根组件下生成的,如app.componet(‘组件名字’,组件对象),这个名字和对象和根组件是一样的原理。
tips:模板是template,不是templete
注册全局组件
<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绑定的盒子中)
组件自己的逻辑和组件名称
逻辑:逻辑的意思就是注册的组件里面,也是可以写methods和data和watch等等optionApi的
组件名称:
注册组件名称一般有两种,斜杠分隔单词或者大驼峰书写
问题:我们发现在页面中用大驼峰,浏览器提示不认识这个标签
因为我们现在的代码写在html中,html中的标签是不区分大小写的,我们写大驼峰自然没有作用
但是在以后的.vue文件中,我们把标签写在template中,就可以用大驼峰了
在实际开发中我们多用斜杠书写组件名字。
注意:注册的全局组件是无法使用根组件app中的optionApi的,如app的data中的变量,在全局组件中的template中无法使用。
局部组件也不能使用,也就是说不管是什么父子组件关系,这些组件的data都是互相独立的,
注册局部组件
<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脚手架
vue脚手架的安装与使用
创建命令为
vue create xxx(文件名字)
第一次创建项目,它会问你下载包的地址,下图中为镜像源,下载较快,我们选no就是用默认源,下载较慢但是版本肯定更准确.
这里他们已经给我们准备好了两个预设,包含了babel和eslint,我们也可以选最后一个选择为手动选择特性
然后会自动出现如下一些命令行界面,我们进行相应选择即可,空格为选中,再按空格为取消选中,a为全部选中
如下就是选中此项目,你会用到什么技术,脚手架自动给你配置环境
然后选择vue的版本
然后会提示bable的配置写入package.json还是单独的文件,我们一般选单独文件,更容易维护
然后会提示,我们是否保存当前预设
什么叫预设呢,就是你刚刚设置的这些脚手架选项,就像你玩王者荣耀和吃鸡的时候,那套操作配置或者符文配置,我们再设置一个名称,下次类型项目就可以直接用这套预设.
最后会让我们选择包管理器,一般现在还是用npm,但是一些公司慢慢向pnpm转型,好处在以往博客也写了,但是我们这里还是用npm,因为我也是初学.
项目创建后的配置
其中vue.config.js和webpack.config.js是差不多作用的
browserslistrc
这个是配置打包后的代码是否需要兼容浏览器的,事实上它也是一个工具,它会自动去caniuse网站去查询各种浏览器版本的一些信息.
如上大于1%,意思就是兼容浏览器占市场份额1%以上的浏览器
last 2 version就是最后两个本吧
not dead的意思是当前浏览器还在维护,还在市场上存在
not ie 11 就是不需要去兼容ie11
事实上在开发中,很多人根本不认识这玩意,都是使用默认的.
js.config.json
这个文件是给开发工具vscode来用的
方便vscode给我们更友好的代码提示,比如你在此文件里面写自己用了那些包,vscode就会识别到,然后给予相应提示。
总结: