Vue框架
Vue3基础:
前面已经分享了webpack的相关操作,那么如此多的配置是不可能每次建项目都要手动配置的:插件–> server,html等; 实际上Vue项目就不需要手动配置webpack
这里就简单介绍一下Vue的基本使用和常用的命令
Vue简介
Vue是一套用于构建用户界面的前端框架;
-
构建用户界面 : 前端开发最主要的工作 : 为网站的使用者构建出美观、舒服的网页界面;
- 传统的是使用JQuery+ 模板引擎; ----------------- 缺点就是 需要定义大量的模板结构,缺少语法高亮和语法提示;数据变化需要重新编译函数,否则页面不更新; 并且一旦大量的DOM的时候,programmer需要花费大量的事件来操作DOM
- Vue解决了这些问题,基于vue的指令来渲染页面的结构,数据驱动视图,只要页面数据发生变化,对页面自动重新渲染【指令是vue提供的模板语法】 基于vue提供的事件绑定,可以轻松处理用户和页面的交互行为
-
框架 : vue提供了构建用户界面的一整套解决方案(Vue全家桶) : vue【核心库】、vue-router【路由方案】、vuex【状态管理方案】、vue组件库【快速搭建页面UI效果的方案】; 除了这些,还有辅助vue项目开发的一系列工具: vue-cli (npm全局包: 一键生成工程化的vue项目,基于webpack、大而全),vite(npm全局包:一键生成工程化的Vue项目,小而巧),vue-devtools【浏览器插件:辅助调试的工具】、vetur(vscode插件:提供语法高亮和智能提示) ---- 这个其实使用HBuilderX可以选择vue的语法库
vue特性— 数据驱动视图,双向数据绑定
数据驱动视图 数据----- 渲染页面需要使用到的数据 (写死的假数据或者api接口返回的数据);视图 ------ 最终渲染出的bom页面: 在使用了vue的页面中,vue会监听数据的变化,从而重新渲染页面的结构:— 这个机制就是数据驱视图
当页面的数据发生变化时,页面会自动重新渲染; 数据驱动视图是单向数据绑定
双向数据绑定
在填写表单时,双向数据绑定可以辅助开发者在不操作DOM的前提下,自动把用户填写的内容同步到数据源中
比如:vue可以将data的内容自动填充到下面的input中, 而修改了表单数据的时候,也会自动更新data —这就是双向数据绑定
var data ={
name:'Bod',
email:'18798798@qq.com'
}
<input name='name' type='text'/>
<input name='email' type='text'/>
所以programmer不需要再手动操作DOM元素,vue可以自动更新表单元素
MVVM
MVVM时vue实现数据驱动视图和双向数据绑定的核心原理,其将每一个HTML页面分成了三个部分:
View:当前页面所渲染的dom结构【视图】
Model : 标识当前页面渲染所依赖的数据源
ViewModel: vue的实例,是MVVM的核心;将M和V连接到一起,Model数据源发生变化,VM重新渲染View;表单数据项发生变化,VM也会将数据重新同步到Model中
Vue3和Vue2的对比
Vue3支持Vue2的绝大多数API,并且增加了新的功能,废弃了一些旧功能
新增的功能 : 组合式API,多根结点组件,更好的TypeScript支持
废弃的功能 : 过滤器,不再支持$on ,off,once等实例方法
Vue的基本使用
使用vue遵循几个基本的步骤
- 导入vue.js的脚本文件
- 在页面中声明一个将要被vue控制的DOM区域
- 创建vm实例对象【vue的实例对象】
在官网上,这就是without Build Tools的使用步骤,这里可以不用下载vue,try Vue with SFCs online on StackBiltz,网址为: https://unpkg.com/vue@3 ,建立一个html页面用来使用vue
这里创建vue的实例采用的是官网推荐的Vue.createApp 而不是原始的new Vue(),同时指定操控区域采用.mout(选择器)
<script src="https://unpkg.com/vue@3" charset="utf-8"></script>
<div id="myapp">{{message}}</div>
<script>
const vm = new Vue({
el: 'myapp',
data:{
message:'hello vue3'
}
});
</script>
--------------------------上面的这种写法不再适用Vue3在HbuilderX中运行不出结果-----------
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>体验vue3</title>
</head>
<body>
<script src="https://unpkg.com/vue@3" charset="utf-8"></script>
<div id="myapp">{{message}}</div>
<script>
Vue.createApp({
data() {
return {
message:'hello Vue3'
}
}
}).mount('#myapp')
</script>
</body>
</html>
在HBuilderX中,使用vue3的语法提示库就可以找到mout方法;注意数据驱动视图只是操作被vue实例操控的DOM区域
Vue的调试工具,vue-devtools
Vue官方提供的是vue-devtools调试,能偶方便开发的时候对Vue项目进行调试与开发,安装就和之前安装HttpWatch是类似的,就是在浏览器中安装扩展即可
当将Vue项目运行到浏览器之后,就可以使用Vuetools工具进行调试,
这里点击root根结点就可以找到Vue操作的DOM区域,并且可以修改data的值,与之前的数据驱动视图相同,下面只要修改,页面的数据就会更新
Vue内容渲染指令
指令(Directives)是Vue为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构;常用的指令有如下
v-text 覆盖
v-text : v-text可以将变量的值渲染给标签, v-text会覆盖元素【dom结点】内部默认的值,比如一个P标签中的内容都会被覆盖
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>体验vue3</title>
</head>
<body>
<script src="https://unpkg.com/vue@3" charset="utf-8"></script>
<div id="myapp">
<p v-text="message"></p>
<p v-text="gender">性别</p>
</div>
<script>
Vue.createApp({
data() {
return {
message:'hello Vue3',
gender:'woman'
}
}
}).mount('#myapp')
</script>
</body>
</html>
//其实上面的就是使用vue的步骤,就是在vue操控的的DOM区域,可以使用vue的指令
{{}}语法 插值表达式–Mustache 不覆盖
因为之前的v-text会完全覆盖原来的标签的内容,这有的时候有失偏颇,还有另外的指令就是插值表达式{{}},可以看作一种占位符,相对于v-text,插值表达式使用更多
<body>
<!-- 1. 导入vue的脚本文件,这里online,不下载了 -->
<script src="https://unpkg.com/vue@3" charset="utf-8"></script>
<!--2.声明要被vue控制的DOM区域 -->
<div id="myapp">
<p v-text="message"></p>
<p v-text="gender">性别</p>
<p> hello, : {{user}}</p>
</div>
<!--3.创建vue的实例对象 -->
<script>
Vue.createApp({
data() { //Vue3中,数据源为一个函数,返回的就是数据
return {
message:'hello Vue3',
gender:'woman',
user : 'Cfeng'
}
}
}).mount('#myapp') //mout方法可以指定控制的DOM区域
</script>
</body>
这里需要注意的是,数据源和引用的名称一定要一致,插值表达式使用相比v-text更方便
vue的模板渲染语法,除了支持绑定简单的数据之外,还支持JavaScript的表达式的运算
{{number + 1}}
{{ok ? 'Yes' : 'No'}}
{{message.split('').reverse().join('')}} //这里是使用的js的函数,split是分割为一个字符数组,然后使用数组的reverse方法反转,之后使用join方法拼接为一个字符串
<p v-text="message.split('').reverse().join('')"></p>
这里不管是插值表达式,还是其他的数据源填充指令,都是支持JavaScript表达式的
v-html 内部为html标签字符串
这个指令类似于之前的Jq中的html方法,就是替换其中的内容为html标签的表达式,v-text和插值表达式都只能渲染文本的内容,对于包含HTML标签的,需要使用v-html
比如这里在数据源中新增一条数据:
descript:'<h5 style="color: red;">和Cfeng一起学vue3</h5>'
那么想要在vue操控的DOM区域使用
<p v-html="descript"></p>
这样就会将P标签的内部填充为html语句执行之后的内容,相当于使用了eval函数
Vue属性绑定指令
如果需要为元素的属性动态绑定属性值,旧需要使用v-blind属性绑定指令
v-bind 绑定元素的属性 v-bind: attr = ‘xx’
动态地绑定一个或多个特性,或一个组件 prop 到表达式。 注意和上面的内容渲染指令的区别: 内容渲染指令比如{{}}都是填充dom元素的内容,而v-blind是将数据源填充给dom元素的属性,相当于之前Jq的attr方法
inputValue: '请输入姓名'
<input type="text" v-bind:placeholder="inputValue"/>
插值表达式只能渲染内容,不能赋值给属性,并且一定要使用vue指令,因为不使用找不到vue对象操作的数据源,这里绑定的目的就是数据驱动视图,方便随时修改palcehodler的内容,不用使用dom来获取修改
v-bind使用频繁,所以可以简写 为 :
<input type="text" :placeholder="inputValue"/>
所以以后只要看到 : 就应该直到使用的是vue的v-bind
事件绑定指令
vue提供了v-on来进行事件绑定,类似于JQ中的事件()方法,但是更方便,可以帮助进行DOM元素绑定事件监听
v-on绑定事件
绑定事件的命令为v-on,其格式和属性绑定指令bind类似
<button v-on:click= "whenClick">按钮xs</button>
按钮的内容直接放在button标签之间,这和intput类型的按钮不同
这里和之前的普通的行间事件绑定类似,这里使用vue指令因为数据要从model获取,要通过vue对象获取;原生DOM对象比如onclick,oninput等,替换为vue的事件绑定形式后,分别为:v-on:click, v-on:input, v-on:keyup【将on改为了v-on:】
v-on的事件处理函数需要在vue对象中的methods结点进行声明, methods结点和data平级,一个是数据,一个是方法
<script>
Vue.createApp({
data() {
return {
message:'hello Vue3',
user : 'Cfeng',
descript:'<h5 style="color: red;">和Cfeng一起学vue3</h5>',
inputValue: '请输入姓名'
}
},
methods:{
whenClick(){
console.log('hello')
this.inputValue = '请输入姓名 : Cfeng'
}
}
}).mount('#myapp')
</script>
这里就是在methods中放入上面v-on绑定的函数,运行之后浏览器就可以从vue对象中找到函数的声明进行调用
v-on和v-bind指令一样都是使用非常频繁,所以同样可以进行简化,可以简写为@
<button @click= "whenClick">按钮xs</button>
这里就可以绑定事件,同时,在原生的JavaScript中,事件回调函数可以接收事件对象event【比如当时敲击键盘的按键】,在v-on指令中,简写为@,绑定的事件处理函数,同样可以接收事件对象event
whenClick(e){
const nowColor = e.target.style.backgroundColor;
e.target.style.backgroundColor = nowColor === 'aqua' ? '' : 'aqua'
this.inputValue = '请输入姓名 : Cfeng'
}
这里可以解释一下 : === 为严格相等,就是说不会进行类型转换,必须是同类型的相等的值;而 == 是抽象的相等,会进行类型转换,比如false和0;
绑定事件并传参
事件绑定之后,可以使用()进行传参【参数可以交给vue对象来进行操作】
<button @click= "whenClick('Cfeng1')">按钮xs</button>
在下面的回调函数,就可以用参数来接收数据
whenClick(username){
// const nowColor = e.target.style.backgroundColor; //e.target可以定位到事件源
// e.target.style.backgroundColor = nowColor === 'aqua' ? '' : 'aqua'
this.inputValue = '请输入姓名 : ' + username
}
这样就可以接收参数了,但是出现了问题,以为username将event的位置给占用了【普通的event只能适用于无参的方法】,这个时候就要使用变量
$event – 表示事件对象
为了解决普通的含参数的方法无法调用event参数的问题,提供了特殊的变量$event表示原生的事件参数对象event,可以解决之前的覆盖问题
这里就是传递的时候,传入$event,在回调函数中,还是使用e接收即可
<button @click= "whenClick('Cfeng1',$event)">按钮xs</button>
-----在回调函数中就可以使用e来接收这个参数,解决了覆盖的问题---------
whenClick(username,e){
const nowColor = e.target.style.backgroundColor; //e.target可以定位到事件源
e.target.style.backgroundColor = nowColor === 'aqua' ? '' : 'aqua'
this.inputValue = '请输入姓名 : ' + username
}
event被覆盖之后就可以使用$event来手动调用event对象
事件修饰符 .prevent .stop .cpature .once .self
在事件处理函数中调用preventDefault()或者stopPropagation()是非常常见的需求,vue提供了事件修饰符,辅助对事件的触发进行控制
- .prevent : 阻止默认行为 【比如阻止a链接的跳转,阻止表单的提交
//原生的js阻止跳转,使用的javascript:void(0)
<a href="index.html" @click.prevent="aClick">Cfeng.com</a>
aClick(){
alert("你好,Cfeng")
}
- .stop 阻止事件冒泡【也就是内部的元素的事件触发同时冒泡触发外部元素结点的事件】
<div style="background-color: aqua;height: 100px;" @click="outClick">
外部的div
<div style="background-color: aquamarine;height: 20px;" @click="innerClick">内部的div</div>
</div>
事件的定义:
outClick(){
console.log("触发了外部的div的click事件")
},
innerClick(){
console.log("触发了内部div的click事件")
}
这里就出现了事件的冒泡,当点击内部的div的时候,因为内部的div包含于外部的div,所以就出现了事件的冒泡,外部的div的事件也会触发,为了解决这种情况,就需要使用.stop
<div style="background-color: aquamarine;height: 20px;" @click.stop="innerClick">内部的div</div>
- .capture 以捕获模式触发当前的事件处理函数 (capture 捕获)
这里的.capture的捕获模式就是意思当触发事件的时候,不是像冒泡哪种从内向外,而是从外向内依次执行事件,修饰符放在最外部的div中
<div style="background-color: aqua;height: 100px;" @click.capture="outClick">
外部的div
<div style="background-color: aquamarine;height: 20px;" @click="innerClick">内部的div</div>
</div>
//点击内部的div,先触发外部div的click事件,之后才会触发内部的div的click事件
有的时候事件只需要执行一次即可,不能执行多次,这个时候就可以使用.once来修饰
<div style="background-color: aqua;height: 100px;" @click="outClick">
外部的div
<div style="background-color: aquamarine;height: 20px;" @click.once="innerClick">内部的div</div>
</div>
- .self 只有在event.target是当前元素自身时触发事件处理函数
阻止冒泡的形式除了上面的stop,还可以使用.self,也就是将内部的元素结点单独剥离出去,不会冒泡
<div style="background-color: aqua;height: 100px;" @click.self="outClick">
外部的div
<div style="background-color: aquamarine;height: 20px;" @click.once="innerClick">内部的div</div>
</div>
冒泡传递过来的事件触发不会激活事件
按键修饰符
之前的原生的js使用的是event的参数来判断按键,在vue中,监听键盘事件时如keyup,经常需要判断详细的按键,可以为键盘相关的事件添加按键修饰符【相比之前的数字,这里的修饰符更直观,比如.esc, .enter】
通过event对象e.target就可以获取到事件触发源
<input type="text" @keyup.enter="akeyUp" />
------------这里就是enter键触发事件------------
akeyUp(e){
alert(e.target.value)
}
按键修饰符只能配合键盘相关事件比如keyup,keydown,keypress等,其他的事件不能使用按键修饰符,只能使用普通的事件修饰符
双向绑定指令
v-model数据双向绑定
vue提供了v-model双向数据绑定指令,辅助不操作DOM的前提下,快速获取表单的数据,这里的v-modle是直接作为属性出现的,注意和上面的v-bind属性绑定指令区别【 v-bind是数据驱动视图,只是将vue对象的数据填充到属性中,而v-model为数据双向绑定,符合MVVM,数据发生变化也会更新vue】所以这里是单独作为属性出现,不是修饰属性
<input type="text" v-model="user" />
<select v-model="province">
<option></option>
</select>
这里打开devtool,上面的数据修改,下面的vue实例的data也会同步发生变化,v-model只能配合表单元素一起使用
v-model指令修饰符.trim .number .lazy
为了方便用户输入的数据进行处理,vue为v-model指令提供了3个修饰符
- .number : 自动将用户的输入只转为数值类型 【不再是字符串】
<input type="text" v-model.number="age" />
- .trim : 自动过滤用户输入的首尾的空白字符 【字符串自动去空格】
<input type="text" v-model="user" />
- .lazy : 在change时而不是input的时候更新 【也就是文本框失去焦点的时候才会更新,而不是实时更新】
<input type="text" v-model.lazy="user" />
条件渲染指令
条件渲染指令用来辅助按需控制DOM的显示与隐藏
v-if和v-show DOM显示与隐藏
v-if和v-show和上面的v-model相同,都是作为标签的一个属性出现,其值为boolean值,当为true时,标签显示,当为false时,标签隐藏
<button @click ='flag = !flag'>条件渲染控制</button>
<div>
<p v-if = 'flag'>被v-if控制的标签</p>
<p v-show="flag">被v-show控制的标签</p>
</div>
flag : true //boolean类型
这里绑定事件不应该在div上:happy:,因为这里点击之后内容消失,div不可见,就点击不出来了
v-if和v-show的指令的效果是相同的,但是两者的实现yu原理不同
- v-if : 会动态的创建或移除DOM元素,从而控制元素在页面的显示与隐藏
- v-show : 会动态为元素添加或者移除style = "display:none"样式,从而控制元素的显示与隐藏
在F12上就会发现这个问题:
... == $0
<p style="display: none;">被v-show控制的标签</p>
- v-if 有更高的切换开销,v-show有更高的初始渲染开销【比如条件为false,就要渲染】,如果需要频繁切换,使用v-show更好,如果运行时条件很少改变,使用v-if更好
v-else【v-else-if】配合v-if
v-if是可以单独使用的,但是也可以配合v-else一起使用,就是条件成立的时候执行v-if显示,否则就是显示v-else的标签【需要注意的是,还有v-else-if】
<div style="background-color:aqua">
<p v-if = 'flag'>被v-if控制的标签</p>
<p v-else>被v-show控制的标签</p>
</div>
这里因为falg的值只有两种可能,不是true就是false,所以之类就是下面的else和上面的if配对,一次只能显示一个标签;当条件多个时,使用v-else-if实现条件显示
列表渲染指令
v-for列表数据的循环渲染
vue提供了v-for指令,帮助基于一个数组循环渲染相似的UI结构
v-for指令需要使用item in items语法, items代表的是待循环的数组,item是当前的循环项
在数据源中放入一个数据数组 :
stuList: [//列表数据
{id:1,name: 'cFENG'},
{id:2,name: 'cSheng'},
{id:3,name: 'cLei'}
]
在上面的ul标签中就可以循环调用数据,不再需要使用jsp的拼接
<ul>
<li v-for="item in stuList">姓名 : {{item.name}}</li>
</ul>
这里需要注意: v-for放在列表的项结点li中,作为属性出现,需要加上item in XX 在后面的域中就可以使用插值表达式调用item;【这里的item可以是任意合法的名称,但是item容易记忆】
v-for的索引
v-for指令还支持一个可选的第二参数,就是当前项的索引index; 语法格式
v-for = ‘( item, index) in XX’
这样就可以同时获取到item元素的索引(index)
<ul>
<li v-for="(item,index) in stuList">姓名 : {{item.name}} 索引为{{index}}</li>
</ul>
使用key维护列表的状态; key属性 ---- v-for = “…” : key="…"
当列表的数据发生变化时,默认情况下,vue会尽可能复用已经存在的DOM元素,从而提升渲染的性能,这样默认的性能优化策略,会导致有状态的列表无法被正确更新, 比如列表的每一项有一个复选框,当选中某一项,当增加了项时,之前的选中的一项的选中移动给占用该位置的元素,这是不正确的
为了给vue一个提示,以便识别每一个结点的身份,保证正确的更新,这个时候就要给每一项增加一个key属性;
这里的key属性和上面的事件修饰符的语法不同,事件修饰符实在v-on或者@后加上.stop等;而key则是在v-for之后加上:key
<ul>
<li v-for="(item,index) in stuList" :key="item.id">姓名 : {{item.name}} 索引为{{index}}</li>
</ul>
这样就可以正确的识别列表项,最好使用id【也就是PK】,这样状态就会正确更新
注意事项
- key的值只能为String或者Number类型,不能是其他的类型
- key为唯一识别的,key具有唯一性,所以建议使用id主键
- 索引【位置】是可变的,使用index当作key没有意义【不具有可识别的性质】
- 使用v-for指令的时候一定要绑定key值,可以提升性能,保持列表的状态
Vue2过滤器 管道符 |
上面的v-if是用来动态显示或者隐藏结点的,过滤器Filters常用于文本的格式化, 比如 hello ----> Hello
过滤器应该被台南佳在JavaScript的表达式的尾部,使用管道符进行调用
过滤器可以使用在两个地方 : 1. 插值表达式 2.v-bind属性绑定指令 [slice 切片,就是从index后面的部分]
<p>
{{message | capitalize}}
</p>
然后再下面的new Vue的对象中定义结点filters来定义过滤器
const vm = new Vue({
el: ,
data: {},
filters:{
capitalize(str){
return str.charAt(0).toUpperCase() + str.slice(1)
}
}
})
私有过滤器和全局过滤器
再filters节点下定义的过滤器,就是私有过滤器,因为只能被vue控制的el区域才能使用; 一个页面的区域是被多个vue实例共同控制;私有的过滤器只能再某个vue实例控制区域中使用
如果希望多个vue实例共享过滤器,就可以定义全局过滤器
Vue.filter('capitalize',(str) => {
return str.charAt(0).toUpperCase() + str.slice(1)
})
这个过滤器就是所有的vue的实例都可以共享的过滤器; 也是遵守就近原则,以私有过滤器为准
连续调用多个过滤器
过滤器支持串联调用,使用管道符连续链接多个
<p>
{{message | capitalize | capitalize1 | capitalize2}}
</p>
这里就会依次经过3个过滤器过滤
过滤器传参
过滤器的本质是JavaScript函数,因此可以接收参数
<p>
{{message | capitalize(arg1,arg2) | capitalize1}}
</p>
但是再filter或者Vue.filter定义过滤器的时候,第一个参数永远都是管道符前面待处理的数据,传递的参数都是从第二个位置开始
Vue.filter('capitalize',(msg,arg1,arg2) => {
})
过滤器的兼容性
过滤器仅在vue.2.x以下可以使用,在vue3.x的版本中删除了过滤器的相关功能, 所以在3.x的版本中,建议使用计算属性 或者方法 来代替过滤器
比如在methods或者computed中进行定义方法【调用computed也行,但是computed和data一样要使用闭包】
<p>
{{capitalize(message)}
</p>
<script>
Vue.creatApp({
data(){
return {
message: 'hello'
}
},
methods:{
cpatalize(str){
str.charAt(0).toUpperCase() + str.slice(1)
}
}
computed:{
captalize1():{
return (str) => {
str.charAt(0).toUpperCase() + str.slice(1)
}
}
}
}).mount('#myApp')
</script>
品牌列表案例
这里就是实现一个可以增加和删除的列表,对列表进行渲染
- 创建一个基本的Vue实例【就引入js文件,同时声明el区域,创建一个vue的实例】 vue实例不能控制body或者html结点,只能控制普通的结点
- 基于Vue渲染表格数据
<table>
<tr v-for="(item,index) in brandList":key="item.id">
<td>{{index + 1}}</td>
<td>{{item.brandname}}</td>
<td>{{item.state}}</td>
<td>{{item.addTime}}</td>
<td><a href="">删除</a></td>
</tr>
</table>
v-for专门用于做列表渲染,包括ul列表或者table表格;tr的td都可以使用
在表单中为submit事件加上.prevent修饰符,去掉自动提交;同时在其中的text文本框使用v-model进行双向数据绑定,使用.trim修饰符去空格
这里还可以为输入框绑定keyup事件,enter键相当于按钮,esc清空文本的内容;事件绑定后面不一定放的是函数的名称,还可以是JavaScript表达式
<input type="text" placeholder="请输入品牌名称" v-model.trim="brandname" @keyup.esc="brandname = ''" @keyup.enter="addBname"/>
删除品牌也就是先要使用.prevent事件修饰符来阻止超链接的自动跳转,之后绑定处理函数,这里可以使用JavaScript的数组的过滤方法实现数据的删除
this.brandList = this.brandList.filter(x => x.id !== id)
这里就直接看实现的功能代码,这里没有注重使用css美化界面,单纯的使用vue指令
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue3实例</title>
<style>
body{
padding: 8px;
}
</style>
</head>
<body>
<script src="./vue.3.2.31.js" type="text/javascript" charset="utf-8"></script>
<div id="app">
<div style="background-color: aqua;">
<form @submit.prevent>
<input type="text" placeholder="请输入品牌名称" v-model.trim="brandname" @keyup.esc="brandname = ''" @keyup.enter="addBname"/>
</form>
</div>
<button type="submit" @click="addBname">添加品牌</button><br/>
<table border="1px" style="border: orangered solid 1px;">
<tr v-for="(item,index) in brandList":key="item.id">
<td>{{index + 1}}</td>
<td>{{item.brandname}}</td>
<td>{{item.state}}</td>
<td>{{dataFormat(item.addTime)}}</td>
<td><a @click.prevent = 'removeItem(item.id)'>删除</a></td>
</tr>
</table>
</div>
<script>
Vue.createApp({
data(){
return {
nextId: 4,
brandname: '',
brandList: [
{id:1,brandname: 'XiaoMi',state:true,addTime: new Date()},
{id:2,brandname: 'HuaWei',state:true,addTime: new Date()},
{id:3,brandname: 'Honor',state:true,addTime: new Date()},
]
}
},
methods:{
dataFormat(datestr){
const dt = new Date(datestr)
const y = dt.getFullYear()
const m = dt.getMonth() + 1
const d = dt.getDate()
const hh = dt.getHours()
const mm = dt.getMinutes()
const ss = dt.getSeconds()
return y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss
},
addBname(){
if(!this.brandname) return alert("不能为空")
this.brandList.push({id:this.nextId,brandname:this.brandname,state:true,addTime:new Date()})
this.brandname = ''
this.nextId ++
},
removeItem(id) {
this.brandList = this.brandList.filter(x => x.id !== id)
}
}
}).mount('#app')
</script>
</body>
</html>
这里就没有使用bootstrap了,关于v-if和v-else就没有应用,v-if和v-show一样都是控制结点的显示的🎄
|