前端系列
一、HTML5
二、CSS3
三、JavaScript
四、jQuery
五、BootStrap
六、Element
七、Ajax
八、JSON
九、VUE3
第一章、基础
一、vue简介
1、学习阶段
-
vue2基础
-
vue-cli(vue的手脚架,专门做工程化开发)
-
vue-router(实现前端路由的)
-
vuex(vue存储数据的)
-
element-ui(ui组件库)
-
vue3
2、 vue的特点
采用组件化模式,提高代码复用率、切让代码更好维护。
声明编码,让编码人员无需直接操作DOM,提高开发效率。
3、安装
将vue添加到项目中主要有四种方式:
1.在页面上以CDN包的形式导入 <script src="https://cdn.staticfile.org/vue/3.0.5/vue.global.js"></script> 2.下载JavaScript文件并自行托管 https://unpkg.com/vue@3.2.36/dist/vue.global.js 3.使用npm安装它 4.使用官方的CLI来构建一个项目
4、vue的简单应用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>简单的vue应用</title>
<!-- 导入vue本地源码 -->
<script src="./vue3.js"></script>
</head>
<body>
<!-- html代码 -->
<div id="counter">
<!-- vue语法{{}}:告诉vue这里面放了一个变量 -->
<p>{{num}}</p>
<p>{{uname}}</p>
</div>
<!-- js代码 -->
<script>
//配置对象
const Counter={
//data里面定义对象,methods里面定义函数
data:function(){
return{
num:0,
uname:"张三"
}
}
}
//Vue.createApp()创建应用,将配置对象传入
//mount():挂载,通过id属性,将document元素挂载到应用上
Vue.createApp(Counter).mount('#counter')
</script>
</body>
</html>
总结:通过Vue.createApp()创建vue应用,再通过mount()将document元素挂载到应用上。
一、Vite
1、vite介绍
vite是一个web开发构建工具,由于其原生的ES模块导入方式,可以实现快速的冷服务器启动。
通过终端中运行以下命令,可以使用vite快速构建vue项目。
> npm init vite@latest <project-name> -- --template vue > cd project-name > npm install > npm run dev
2、Vite的项目结构
node_modules(项目的依赖) public(存放静态资源文件夹) src(源代码) components HelloWorld.vue App.vue(根组件,渲染的起点) main.js(项目入口) style.css(项目的CSS样式文件)
三、应用&组件实例
1、创建一个应用实例
每个vue都是通过createAPP函数创建应用实例开始的
const app = Vue.createAPP({})
该应用实例是用来在应用中注册全局组件的
const app = Vue.createAPP({})
app.component('SearchInput', SearchInputComponent)
app.directive('focus', FocusDirective)
app.use(LocalePlugin)
2、根组件与挂载应用
//1.配置对象 const RootComponent = {/*选项*/} //2.createAPP(): 将配置对象传入,创建应用 const app = Vue.createAPP(RootComponent) //3.moint(): 挂载,通过id属性,将document元素挂载到应用上 const vm = app.moint('#app')
3、组件实例 property
data属性:在data中定义的属性通过组件实例暴露出去,就可以在DOM元素中使用。
组件实例的所有property都可以在组件的模板中访问到。
还可以将用户自定义的property添加组件实例中,例如:methods,props,computed,inject和setup。
Vue还通过组件暴露了一些内置的property,例如:$attrs 和 $emit。
//配置对象
const Counter={
data:function(){
return{
num:0,
uname:"张三"
}
}
}
//createApp()创建应用,将配置对象传入
const app = Vue.createApp(Counter)
//mount():挂载,通过id属性,将document元素挂载到应用上
const vm = app.mount('#counter')
console.log(vm.count)
四、模板语法
1、插值 {{ }}
{{ }}:可以在花括号中引用变量
<body>
<!-- html代码 -->
<h1>插值:</h1>
<div>
{{info}}
</div>
<!-- script代码 -->
<script src="./static/js/vue.global.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
info:"小牛马"
}
})
</script>
</body>
2、指令
vue指令:
-
v-text:文本内容绑定,让元素的文本内容和变量进行绑定
-
v-once:一次性渲染,当变量数据改变时,元素文本内容不会在更新
-
v-html:标签内容绑定,让元素的html标签内容和变量进行绑定
-
v-model:双向绑定,让控件和变量进行双向绑定,获取控件的值都是用双向绑定
-
v-bind 和 : :属性绑定,让元素的某个属性的值和变量进行绑定
-
v-on 和 @:事件绑定,将事件与方法绑定,调用的方法必须写在methods中
实例:
v-text:文本内容绑定,让元素的文本内容和变量进行绑定
<body>
<div>
<p v-text="info"></p>
</div>
<script src="./static/js/vue.global.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
info:"小牛马"
}
})
</script>
</body>
v-once:一次性渲染,当变量数据改变时,元素文本内容不会在更新
<body>
<div>
<p v-once="info"></p>
</div>
<script src="./static/js/vue.global.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
info:"大沙币"
}
})
</script>
</body>
v-html:标签内容绑定,让元素的html标签内容和变量进行绑定
<body>
<div>
<p v-html="info"></p>
</div>
<script src="./static/js/vue.global.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
info:"<s>小可爱</s>"
}
})
</script>
</body>
v-model:双向绑定,让控件和变量进行双向绑定,获取控件的值。
<body>
<!-- html代码 -->
<div>
<input type="text" v-model="url" placeholder="请输入访问地址">
<a :href="url">超链接</a>
</div>
<!-- script代码 -->
<script src="static/js/vue.global.js"></script>
<script>
let v = new Vue({
el: "body>div",
data: {
url: "www.baidu.com",
}
})
</script>
</body>
v-bind 和 : :属性绑定,让元素的某个属性的值和变量进行绑定
<body>
<div>
<a :href="url">百度一下</a>
<a v-bind:href="url">百度一下</a>
</div>
<script src="./static/js/vue.global.js"></script>
<script>
let v = new Vue({
el: "body>div",
data: {
url:"http://www.baidu.com",
}
})
</script>
</body>
v-on 和 @:事件绑定,将事件与方法绑定,调用的方法必须写在methods中
<body>
<!-- html代码 -->
<div>
<!-- 将 click事件 与 f()方法 绑定 -->
<input type="button" value="按钮1" @click="f()">
<input type="button" value="按钮2" v-on:click="f()">
</div>
<!-- script代码 -->
<script src="static/js/vue.global.js"></script>
<script>
let v = new Vue({
el: "body>div",
data: {},
methods: {
f() {
alert("按钮被点击了");
},
})
</script>
</body>
插入html标签
双花括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令
v-html 属性是一个指令,指令以 v- 为前缀。span
的内容将会被替换为 rawHtml
属性的值,插值为纯 HTML——数据绑定将会被忽略。
属性绑定(Attributes )
变量的值影响标签属性的值
双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个属性,应该使用 v-bind 指令:
<!-- v-bind: 动态绑定属性的内容 --> <img v-bind:src="url" alt="">
v-bind
指令指示 Vue 将标签的属性与组件的属性保持一致。
简写
<img :src="url" alt="">
2、指令
指令是带有 v-
前缀的特殊属性。
v-on: 用于监听DOM事件,简写@
动态参数
指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内,attributeName
会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。
<a v-bind:[attributeName]="url"> ... </a> <!-- 简写 --> <a :[attributeName]="url"> ... </a>
函数绑定到动态的事件名称上:
<a v-on:[eventName]="doSomething"> ... </a> <!-- 简写 --> <a @[eventName]="doSomething">
在此示例中,当 eventName
的值是 "focus"
时,v-on:[eventName]
就等价于 v-on:focus
。
动态参数值的限制
动态参数中表达式的值应当是一个字符串,或者是 null
。特殊值 null
意为显式移除该绑定。其他非字符串的值会触发警告。
指令
v-once: 一次性渲染,当数据改变时,插值处的内容不会更新 <p v-once>{{uname}}</p> v-bind: 动态绑定属性的内容 <img v-bind:src="url" alt=""> v-on: 用于监听DOM事件,简写:@ <a @[eventName]="doSomething">
五、data 的属性和方法
组件的 data 选项是一个函数。Vue 会在创建新组件实例的过程中调用此函数。它应该返回一个对象,然后Vue 会通过响应性系统将其包裹起来,并以$data的形式存储在组件实例中。
export default { data() { name: "张三", age: 18, } }
methods方法
方法methods通过this获取data属性的数据。
export default {
data() {},
methods:{
changeColor:function(){
this.id='d2';
}
}
}
这些methods和组件实例的其它所有属性一样可以在组件的模板中被访问。在模板中,它们通常被当做事件监听使用:
<button @click="changeColor">改变颜色</button>
计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。
只有依赖值不变,那么就不会重新计算。
//计算属性的简写
computed:{
//字符串翻转属性
reverseMsg:function(){
return this.message.split("").reverse().join("")
}
},
//每一个计算属性都有一个getter和setter方法
//完整写法
computed:{
reverseMsg:{
//当调用reverseMsg的时候就会自动执行getter方法
get: function(){
return this.message.split("").reverse().join("")
}
//计算属性一般没有set方法,计算属性是只读属性
//在设置或者更改计算属性的时候调用
set: function(newValue){
console.log(newValue);
}
}
}
//计算属性的调用
<p>{{ reverseMsg }}</p>
六、侦听器
1、侦听器 'watch'的使用
就是侦听数据的变化,当需要在数据变化是执行异步或其他操作时,可以使用侦听器来响应数据的变化。使用 watch 选项在每次响应式属性发生变化时触发一个函数。
//侦听器:监听数据的变化,一个数据影响多个数据
watch:{
//监听message属性的变化,当message发生变化时,就会调用这个函数
message:function(newValue, oldValue){
console.log(newValue);
console.log(oldValue);
}
}
2、侦听器'watch'对对象进行深度监听
v-model:对数据进行双向绑定
<script> export default { //属性 data(){ return { message: "hello", age: 0, } }, //方法 methods:{}, //侦听器:监听数据的变化,一个数据影响多个数据 watch:{ //监听message属性的变化,当message发生变化时,就会调用这个函数 message:function(newValue, oldValue){ console.log(newValue); console.log(oldValue); //执行异步操作,或者复杂逻辑代码 if(newValue.length<5 || newValue.length>10){ console.log("输入框的内容不能小于5,大于10"); } } } } </script> <!-- html模板代码 --> <template> <div> <!-- v-model:对数据进行双向绑定 --> <input type="text" v-model="message"> </div> </template>
当页面初始化的时候监听页面数据
<script> export default { //属性 data(){ return { message: "hello", age: 0, } }, //方法 methods:{}, //侦听器:监听数据的变化,一个数据影响多个数据 watch:{ //当输入框内容小于5或者大于10输出提示 message:{ immediate: true, handler: function(newValue){ if(newValue.length<5 || newValue.length>10){ console.log("输入框的内容不能小于5或者大于10"); } } } } } </script> <!-- html模板代码 --> <template> <div> <!-- v-model:对数据进行双向绑定 --> <input type="text" v-model="message"> </div>
监听对象里的属性
监听器不能监听对象的属性和方法,需要使用深度监听deep。
<script> export default { //属性 data(){ return { user:{ name:"张三", age: 18, } } }, //方法 methods:{}, //侦听器:监听数据的变化,一个数据影响多个数据 watch:{ //深度监听 user:{ deep:true, //表示是否深度监听,侦听器会一层层的向下遍历,给对象每个属性都会加上侦听器 handler:function(newValue){ console.log(newValue); } }, //属性指定深度监听:使用字符串形式进行优化,只会单独监听对象中对应的属性 "user.name":{ deep: true, handler: function(newValue){ console.log(newValue); } } } } </script> <!-- html模板代码 --> <template> <div> <!-- 深度监听 --> <button @click="user.name='李四'">修改user</button> </div> </template>
七、Class和style的绑定
1、class类名对象的使用
class和style绑定:
操作元素的class列表和内联样式是数据绑定的一个常见需求。因为它们都是 属性,所以我们可以用v-bind处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将v-bind 用于class 和style时,Vue.js做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
普通绑定
<script> export default { data(){ return { isActive: true, classObj: { isActive: true, a1: true, }, error:null, activeClass: "active", a1Class: "a1", }; }, // 计算属性 computed:{ chassObjectCom:function(){ return { //当isActive等于true且没有报错,就添加active的样式 active: this.isActive && !this.error, a1: this.error, } } } } </script> <!-- html模板代码 --> <template> <div> <!-- 第一种:放置字符串 --> <p class="active">Hello World</p> <!-- 第二种:放置对象 --> <!-- <p v-bind:class="{类名: Boolean}">hello world</p> --> <p v-bind:class="{active:isActive}">helloworld</p> <button @click="isActive = ! isActive">取反</button> <!-- 可以在标签里添加多个class --> <p v-bind:class="{active:isActive, a1:isActive}" class="a2">helloworld</p> <!-- 可以使用对象添加class --> <p v-bind:class="classObj">helloworld</p> <!-- 第三种:使用computed--> <p v-bind:class="chassObjectCom">helloworld</p> <!-- 第四种:数组语法 --> <p v-bind:class="[activeClass,a1Class]">helloworld</p> <!-- 第五种:数组和对象的结合 --> <p v-bind:class="[activeClass, {a1:isActive}]">helloworld</p> </div> </template> <!-- CSS样式 --> <style> .active{ font-size: 50px; color: red; }; .a1{ background-color: pig; }; .a2{}; </style>
2、style样式的使用
对象语法:
v-bind:style 的对象语法十分直观―-看着非常像CSS,但其实是一个JavaScript对象。CSSproperty名可以用驼峰式(camelCase)或短横线分隔(kebab-case,记得用引号括起来)来命名:
<script> export default { data(){ return{ active: "orange", fontSize: "50px", bgColor: "pink", styleObj: { color: 'red', fontSize: '50px', "background-color": 'pink', } }; } } </script> <!-- html模板代码 --> <template> <div> <!-- 第一种:放置字符串 --> <p style="color:orange">青松落色</p> <!-- 第二种:放置对象 --> <!-- <p v-bind:style="{key(css属性名):value(属性值,来自于data中的属性)}"></p> --> <p v-bind:style="{color:active, fontSize:fontSize,'background-color':bgColor}">青松落色</p> <p v-bind:style="styleObj">青松落色</p> <!-- 第三种:数组语法 --> <p v-bind:style="[styleObj, {border:'5px solid blue'}]">青松落色</p> </div> </template>
八、渲染
条件渲染
1、v-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
<script> export default { data(){ return{ age: 21, }; } } </script> <!-- html模板代码 --> <template> <div> <p v-if="age>18">我成年了</p> </div> </template>
2、v-else
为 v-if
添加一个“else 区块”。必须跟在一个 v-if
或者 v-else-if
元素后面,否则它将不会被识别。
<script> export default { data(){ return{ age: 21, }; } } </script> <!-- html模板代码 --> <template> <div> <p v-if="age>=18">我成年了</p> <p v-else>我还是小盆友</p> </div> </template>
3、v-else-if
顾名思义,v-else-if
提供的是相应于 v-if
的“else if 区块”。它可以连续多次重复使用:
<script> export default { data(){ return{ age: 12, }; } } </script> <!-- html模板代码 --> <template> <div> <p v-if="age>18">我成年了</p> <p v-else-if="age==18">我今天正好18岁</p> <p v-else>我还是小盆友</p> </div> </template>
4、<template> 上的 v-if、v-else-if、v-else
分组渲染:想要切换多个元素,可以使用<template>包括多个元素,在<template>上使用条件渲染。
<script> export default { data(){ return{ age: 21, }; } } </script> <!-- html模板代码 --> <template> <template v-if="age>18"> <p>成年人才可以看见</p> </template> </template>
5、v-show
v-show
:按条件显示一个元素的指令。
不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。
v-if:有后面为false,对应的元素以及子元素都不会被渲染,控制dom元素的创建和销毁,运行时条件很少改变,一次性。
<script> export default { data(){ return{ sex: man, }; } } </script> <!-- html模板代码 --> <template> <!-- v-show --> <div> <p v-show="sex=='man'">男生</p> <p v-show="sex=='woman'">女生</p> </div> </template>
列表渲染
<script> export default { //name为demo在下文中会提到是在我们的APp.vue 中进行引用的标志 name: "demo06", data() { return { names: ['张三', '李四', '王五'], color:[{message:"red"},{message:"blue"},{message:"green"}], person:{name:"张三",age:18,sex:"男"}, }; } } </script> <!-- html模板代码 --> <template> <!-- 分组渲染 --> <div> <li> <!-- 列表遍历 --> <ul v-for="item in names">{{item}}</ul> <!-- 遍历列表的字典值 --> <ul v-for="item in color">{{ item.message }}</ul> <!-- 索引遍历 --> <ul v-for="(item,index) in color">第{{index}}种颜色是{{ item.message }}</ul> <!-- 遍历对象:item表示键值,key表示键名,index表示索引 --> <p v-for="(item, key,index) in person">{{index}}: {{key}} {{item}}</p> </li> </div> </template>
数组更新检测
变更方法 Vue将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:.
<script> export default { data() { return { list:[1,2,3,4,5], }; }, methods:{ changeList: function(){ //通过索引值去修改数组 this.list[5] = 7; //数组更新方法 // .push():给数组末尾添加元素 this.list.push(7,8,9); // .pop():删除数组最末尾元素 this.list.pop(); // .shift():删除数组第一位元素 this.list.shift(); // .unshift():在数组第一位添加元素 this.list.unshift(0,9,9); // .splice():删除元素,插入元素,替换元素 // 第一个参数:表示开始插入或者开始册除的元素的位置下标删除元素 // 第二个参数:表示传入要删除几个元素(如果没有传,就删除后面所有的元素)插入元素: // 第二个参数:传入0,并且后面接上要插入的元素替换元素: // 第二个参数:表示我们替换几个元素,后面的参数表示用于替换前面的元素的 this.list.splice(1,3,7,8,9); // .sort():排序 this.list.sort(); // .reverse();翻转数组 this.list.reverse(); } } } </script> <!-- html模板代码 --> <template> <!-- 数组更新 --> <div> <ul> <li v-for="tiem in list">{{ item }}</li> </ul> <button @click="changeList">改变数组</button> </div> </template>
九、事件处理
方法事件处理器
方法事件处理器会自动接收原生 DOM 事件并触发执行。在上面的例子中,我们能够通过被触发事件的 event.target.tagName
访问到该 DOM 元素。
<!-- 事件处理 --> <script> export default { //属性 data() { return { counter: 0, age: 0, }; }, //方法 methods: { //处理函数的完整写 addcounter:function(number, e) { this.counter += number; console.log(e); }, //处理函数的简写 addage() { this.age++; }, } } </script> <!-- html模板代码 --> <template> <div> <!-- 绑定事件,没有传递参数 --> <h3 v-on:click="addcounter">{{counter}}</h3> <!-- 绑定事件,传递参数 --> <h3 v-on:click="addcounter(5)">{{counter}}</h3> <!-- 绑定事件,传递参数,也传递事件对象 --> <h3 v-on:click="addcounter(5, $event)">{{counter}}</h3> <!-- 一个事件,绑定多个处理函数(以逗号分隔,可以绑定多个处理函数) --> <h3 v-on:click="addcounter(5), addage()">{{counter}} -- {{age}}</h3> </div> </template>
事件修饰符
案例:
<!-- 事件修饰符 --> .stop .prevent .self .capture .once .passive <!-- javascript代码 --> <script> export default { //属性 data() { return {}; }, //方法 methods: { divClick(){ console.log("父元素展示") }, btnClick(){ console.log("子元素的展示"); }, submitClick(){ console.log("提交数据成功") }, onceClick(){ console.log("只会触发一次") }, keyUp(){ console.log("键盘被按下了,数据提交成功") } } } </script> <!-- html模板代码 --> <template> <!-- 事件修饰符 --> <div> <!-- .stop 阻止事件冒泡 --> <div @click="divClick"> <button @click.stop="btnClick">按钮</button> </div> <!-- .prevent 阻止默认行为 --> <form action=""> <input type="submit" value="提交" @click.prevent="submitClick"> </form> <!-- .once 只触发回调一次 --> <button @click.once="onceClick">只触发一次once</button> </div> </template>
键盘修饰符
<!-- 事件处理&事件修饰符 --> <!-- javascript代码 --> <script> export default { //属性 data() { return {}; }, //方法 methods: { keyUp(){ console.log("键盘被按下了,数据提交成功") } } } </script> <!-- html模板代码 --> <template> <!-- 按键修饰符 --> <div> <!-- .{keyCode(键盘编码) | keyAlias(键盘的简写)} 监听键盘的键帽 --> <input type="text" @keyup.enter="keyUp"> </div> </template>
按键别名
Vue 为一些常用的按键提供了别名:
-
.enter
-
.tab
-
.delete
(捕获“Delete”和“Backspace”两个按键) -
.esc
-
.space
-
.up
-
.down
-
.left
-
.right
鼠标按键修饰符
这些修饰符将处理程序限定为由特定鼠标按键触发的事件。
-
.left
-
.right
-
.middle
表单输入绑定
<script> export default { //属性 data() { return { msg: "helloWorld", checked: "", fruits: [], sex: "男", city: "", citys:[], counter:0, }; }, //方法 methods: { changeValue(e) { console.log(e); this.msg = e.target.value; }, downmsg(){ console.log(this.msg) } } } </script> <!-- html模板代码 --> <template> <div> <!-- v-model基本使用 --> <input type="text" v-model="msg"> <h2>{{msg}}</h2> <!-- v-model的原理 本质是两个操作: 1.v-bind绑定一个value属性 2.v-on给当前元素添加一个input事件 --> <input type="text" :value="msg" @input="changeValue"> </div> <!-- v-model表单控件的基本使用 --> <div> <!-- 文本框 --> <input type="text" :value="msg" @input="changeValue"><br> <!-- 复选框 --> <!-- 单个勾选框,v-model为布尔值 --> <input type="checkbox" v-model="checked"> 真与假:{{checked}}<br /> <!-- 多个勾选框 --> <input type="checkbox" v-model="fruits" value="冰果">冰果 <input type="checkbox" v-model="fruits" value="香蕉">香蕉 <input type="checkbox" v-model="fruits" value="柚子">柚子 <input type="checkbox" v-model="fruits" value="橘子">橘子 <input type="checkbox" v-model="fruits" value="葡萄">葡萄 <h2>喜欢的水果:{{fruits}}</h2> <!-- 单选框 --> <input type="radio" v-model="sex" value="男">男 <input type="radio" v-model="sex" value="女">女 <h2>{{sex}}</h2> <!-- 选项框 --> <!-- 单选 --> <select name="" id="" v-model="city"> <option value="张家界">张家界</option> <option value="长沙">长沙</option> <option value="益阳">益阳</option> <option value="邵阳">邵阳</option> </select> <h2>城市:{{city}}</h2> <!-- 多选 --> <select name="" id="" v-model="citys" multiple> <option value="张家界">张家界</option> <option value="长沙">长沙</option> <option value="益阳">益阳</option> <option value="邵阳">邵阳</option> </select> <h2>{{citys}}</h2> </div> </template>
修饰符
<!-- javascript代码 --> <script> export default { //name为demo在下文中会提到是在我们的APp.vue 中进行引用的标志 name: "demo08", //属性 data() { return { msg: "helloWorld", counter:0, }; }, //方法 methods: { downmsg(){ console.log(this.msg) } } } </script> <!-- html模板代码 --> <template> <!-- 修饰符的使用 --> <!-- .lazy,当输入框失去焦点,再去同步输入框的内容 --> <input type="text" v-model.lazy="msg"> <h2>{{msg}}</h2> <!-- .number将输入框中的内容自动转换为数字类型 --> <input type="text" v-model.number="counter"> <h2>{{typeof counter}}</h2> <!-- .trim,自动过滤用户输入的首尾空白字符 --> <input type="text" v-model.trim="msg" @keydown="downmsg"> <h2>{{msg}}</h2> </template>