网站建设的电话销售,聚企网,公司做网站用什么主机,网站诊断内容一.Vue是什么#xff1a;
概念#xff1a;Vue是一个用于构建用户界面的渐进式的框架
以下的内容是自里向外的
声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite
Vue的两种使用方式#xff1a;
Vue核心包开发-
概念Vue是一个用于构建用户界面的渐进式的框架
以下的内容是自里向外的
声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite
Vue的两种使用方式
Vue核心包开发-局部模块改造Vue核心包Vue插件 工程化开发
二.创建Vue实例与初始化渲染
构建用户界面创建Vue实例初始化渲染 准备容器引包-开发版本/生产版本创建Vue new Vue();指定配置项渲染数据 el指定挂载点 -#iddata提供数据
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title
/headbodydiv idappp{{ message }}/pbutton v-on:clickchangeMessage改变消息/button/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {message: 这是一个简单的 Vue 实例},methods: {changeMessage: function () {this.message 消息已改变;}}});/script
/body/html 三.Vue指令
Vue指令的定义有v-前缀的标签属性
Vue根据不同的【指令】针对【标签】实现不同的【功能】
!--Vue指令 v-前缀的标签属性 --
div v-htmlstr/div
!--普通标签属性--
div classbox/div
div title小张/div1.v-html
插值表达式{{msg}} 其中msg是在data中定义的变量 vue会将其渲染到html标签中 而{{msg}}插值表达式就在标签中
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title
/headbodydiv idapp v-htmlmsg/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{msg:a hrefhttp://www.baidu.com测试内容/a}})/script
/body/html
v-html“data中的属性”data中的属性要用作为模板语法表示v-html等价于js中的innerHTMLdata中的属性必须是一个完整的html标签
2.v-show与v-if
v-show(条件渲染)
作用控制元素显示隐藏语法v-show“表达式” 表达式的值true显示 false隐藏原理display:none(本质控制的css样式-适合频繁切换显示隐藏的场景)
v-if(判断条件)
作用控制元素显示隐藏语法v-if“表达式” 表达式值true显示 false隐藏原理基于条件判断是否创建或者移除元素节点适合不频繁的场景
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/titlestyle
.box {display: flex; /* 使用 flexbox 布局 */justify-content: center; /* 在主轴上居中 */align-items: center; /* 在交叉轴上居中 */height: 200px;width: 200px;text-align: center;border-radius: 5px;border: 2px solid black;background-color: white;padding: 10px;margin: 10px;box-shadow: none;
}/style
/headbodydiv id appdiv v-showflag classbox我是v-show控制的盒子/divdiv v-ifflag classbox我是v-if控制的盒子/div/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{flag:false}})/script
/body/html
3.v-else v-else-if
作用辅助v-if进行判断渲染v-else v-else-if“表达式”必须结合v-if使用
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id appp v-ifgender1性别男/pp v-ifgender2性别女/pp v-ifscore90成绩评定为A等因为其90/pp v-else-ifscore70成绩评定为B等因为其70/pp v-else-ifscore60成绩评定C等因为其60/pp v-else成绩评定D等你的问题很大/p/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{gender:2,score:89}})/script
/body/html
上述为完整例子p可以是任意标签接下来抽取抽象概念
p v-ifxxx/p
p v-else-ifxxxxxx/p
p v-elsexxx/p4.v-on基础 作用注册事件 添加监听提供处理逻辑 语法 v-on:事件名”内联语句“ v-on:事件名“methods中的函数名” v-on可以用替代 button v-on:clickcount点我自增
/buttonbutton click-count点我自增
/button实例一内联语句
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id appbutton v-on:clickcount--点我做减法/buttonbrbutton v-on:clickcount点我做加法/buttonbrspan{{count}}/span/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{count:0}})/script
/body/html
实例二methods函数
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id appbutton clickfn切换显示隐藏/buttonh1 v-showisShow测试内容/h1/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{isShow:true},methods:{fn(){this.isShow!this.isShow}}})/script
/body/html
5.v-on调用传参
场景需求点击按钮购买道具需要扣除一定的资金点击按钮发生响应可以通过v-on:事件”命令“来实现但是如何传递扣除资金的参数呢我们引入v-on调用传参来实现v-on:click“函数名(传入的参数)”你是否会想那我如果希望点击按钮传递input框的值呢这个答案会在v-model中揭晓
售货机扣钱案例来学习调用传参
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/titlestyle.box{border: 2px solid black;width: 200px;height: 200px;text-align: center;}/style
/headbodydiv id appdiv classboxh3自动售货机/h3button clickbuy(5)可乐5元/buttonbutton clickbuy(10)咖啡10元/button/divp银行卡余额{{deposit}}元/p/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{deposit:5000},methods:{buy(price){this.depositthis.deposit-pricewindow.alert(购买成功您的余额是deposit);}}})/script
/body/html
6.v-bind
作用动态的设置html的标签属性语法 v-bind:属性名“表达式”省略语法v-bind:src“xxx” :src“xxx”
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id appimg v-bind:srcimgUrlimg :srcimgUrl/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{imgUrl: D:/desklop/OIP-C.jpg},})/script
/body/html
7.数组概念-切换图片案例
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id appbutton v-on:clickindex下一张/buttonbutton v-on:clickindex--上一张/buttonbrimg v-bind:srclist[index]/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{index:0,list:[D:/desklop/OIP-C.jpg,D:/desklop/testpng.png,D:/desklop/OIP-C.jpg,D:/desklop/testpng.png,]},})/script
/body/html
8.v-for
作用基于数据循环多次渲染整个元素语法v-for“(item,index) in 数组” ps:item是每一项大多数时候和 与 一起使用
p v-for...我是一个内容/p!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id apph3水果店/h3ulli v-for(item,index) in list{{item}} --{{index}}/lili v-foritem in list{{item}}/li/ul/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{list:[西瓜,苹果,鸭梨,榴莲]},})/script
/body/html
9.v-forv-on实战-书架
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id apph3书架/h3ulli v-for(item,index) in booklist :keyitem.idspan{{item.name}}/spanspan{{item.author}}/spanbutton v-on:clickdel(item.id)删除/button/li/ul/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{booklist:[{id:1,name:《红楼梦》,author:曹雪芹},{id:2,name:《西游记》,author:吴承恩},{id:3,name:《水浒传》,author:施耐庵},{id:4,name:《三国演义》,author:罗贯中},]},methods:{del(id){this.booklist this.booklist.filter(item item.id!id)}}})/script
/body/html 这段代码是用来过滤掉 booklist 数组中 id 与给定 id 相同的元素。它使用了 JavaScript 中的数组 filter 方法该方法会创建一个新数组其中包含通过指定函数测试的所有元素。在这里指定的函数是一个箭头函数它会检查每个元素的 id 是否与给定的 id 不相同如果不相同则保留该元素。所以最终item.idid的部分都保留下来了 10.v-for:key ulli v-for(item,index) in booklist :keyitem.idspan{{item.name}}/spanspan{{item.author}}/spanbutton v-on:clickdel(item.id)删除/button/li/ul语法key属性”唯一标识给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用 如果不加key v-for默认行为是原地修改元素就地复用 给元素添加唯一标识便于Vue进行列表的正确排序复用 key只能是字符串或者数字类型key必须要有唯一性推荐使用id作为key,不推荐使用index作为key(会变化不对应)
11.v-model
作用给表单元素使用双向数据绑定 -可以快速获取或设置表单元素内容语法v-model‘变量’
数据变化——视图自动更新视图变化——数据自动更新
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/title/headbodydiv id app账户:input typetext v-modelusernamebrbr密码:input typepassword v-modelpasswordbrbrbutton clicklogin登陆/buttonbutton clickreset重置/button/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{username:,password:,},methods:{login(){console.log(this.username,this.password)},reset(){this.username,this.password}}})/script
/body/html
12.记事本项目
功能需求 列表渲染删除功能添加功能底部统计与清空
!DOCTYPE html
html langen
head
meta charsetUTF-8 /
meta http-equivX-UA-Compatible contentIEedge /
meta nameviewport contentwidthdevice-width, initial-scale1.0 /
link relstylesheet href./css/index.css /
title记事本/title
/head
body!-- 主体区域 --
section idapp!-- 输入框 --header classheaderh1小黑记事本/h1input v-modeltodoName placeholder请输入任务 classnew-todo /button clickadd classadd添加任务/button/header!-- 列表区域 --section classmainul classtodo-listli classtodo v-for(item, index) in list :keyitem.iddiv classviewspan classindex{{ index 1 }}./span label{{ item.name }}/labelbutton clickdel(item.id) classdestroy/button/div/li/ul/section!-- 统计和清空 → 如果没有任务了底部隐藏掉 → v-show --footer classfooter v-showlist.length 0!-- 统计 --span classtodo-count合 计:strong {{ list.length }} /strong/span!-- 清空 --button clickclear classclear-completed清空任务/button/footer
/section!-- 底部 --
script srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/script
script// 添加功能// 1. 通过 v-model 绑定 输入框 → 实时获取表单元素的内容// 2. 点击按钮进行新增往数组最前面加 unshiftconst app new Vue({el: #app,data: {todoName: ,list: [{ id: 1, name: 跑步一公里 },{ id: 2, name: 跳绳200个 },{ id: 3, name: 游泳100米 },]},methods: {del (id) {// console.log(id) filter 保留所有不等于该 id 的项this.list this.list.filter(item item.id ! id)},add () {if (this.todoName.trim() ) {alert(请输入任务名称)return}this.list.unshift({id: new Date(),name: this.todoName})this.todoName },clear () {this.list []}}})/script
/body
/html
四:指令补充/计算属性/监听器
1.指令的修饰符
指令修饰符通过.指明的指令后缀不同后缀封装了不同的处理操作-简化代码 按键修饰符 keyup.enter -键盘回车监听 header classheaderh1记事本/h1input keyup.enteradd v-modeltodoName placeholder请输入任务 classnew-todo /button clickadd classadd添加任务/button/header
!--输入框注册了事件 keyup按键弹起 enter为回车 实现在输入框内回车即可添加--我们思考v-on:keyup.enter的内在逻辑“”中的函数若空参可以用e承接事件名然后以事件来调用方法 scriptconst app new Vue({el:#app,data:{username: },methods:{fn(e){console.log(e);console.log(键盘回车时候触发,this.username)}}})/scriptv-model修饰符 v-model.trim -去除首尾空格v-model.number-转数字 事件修饰符 事件名.stop -阻止冒泡 存在两个div嵌套点击内部div命令会执行外部div方法与内部div方法使用stop可以避免这种现象 事件名.prevent -阻止默认行为 !DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/titlestyle.father{width: 200px;height: 200px;background-color: aqua;}.son{width: 50px;height: 50px;background-color: blanchedalmond;}/style
/headbodydiv idapph3v-model修饰符.trim .number/h3姓名input v-model.trimusername typetextbr年龄input v-model.numberage typetextbrh3事件名.stop -阻止冒泡/h3div click.stop fatherFn classfatherdiv click.stopsonFn classson儿子/div/divh3事件名.prevent -阻止默认行为/h3a click.prevent hrefhttps://www.baidu.com阻止默认行为/a!--在被.prevent修饰后 无法跳转链接 因为herf是a的一个默认行为--/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{username: ,age:,},methods:{fatherFn(){alert(父亲被点击了)},sonFn(){alert(儿子被点击了)}}})/script
/body/html
2.v-bind操作class(样式控制增强)
语法:v-bind“对象/数组” 对象-键就是类名值是布尔值。如果值是true有这个类否则无这个类。第一类特征在于v-bind修饰的就是class本身而非是class中的某个具体属性。在于决定某个class是否被启用 div classbox v-bind:class{类名1:布尔值,类名2:布尔值}/div a :class{active:indexactiveIndex} href#{{item.name}}数组-数组中的所有类都会添加到盒子上本质是一个class列表.第二类是有特征的第一个class样式是不绑定vue的只有这个class里面的某个具体属性会绑定到vue。在于决定已经存在的class中的具体属性修改 div classbox v-bind:class{类名1,类名2,类名3}div classinner v-bind:style{width:percent %}div class:box :style{width:400px,height:400px,background:green}A.导航栏案例-v-bind应用
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/titlestyle*{margin: 0;padding: 0;}ul{display: flex;border-bottom: 2px solid #e01222;padding: 0 10px;}li {width: 100px;height: 50px;line-height: 50px;list-style: none;text-align: center;}li a{display: block;text-decoration: none;font-weight: bold;color:#333333;}li a.active{background-color: #e01222;color: #fff;}/style
/headbodydiv idappulli v-for(item,index) in list v-bind:keyitem.id clickactiveIndex indexa :class{active:indexactiveIndex} href#{{item.name}}/li/ul/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{activeIndex:1,list:[{Id:1,name:秒杀窗口},{id:2,name:每日特价},{id:3,name:品类秒杀}]}})/script
/body/html
B.进度条案例-v-bind绑定样式
!DOCTYPE html
html langzhheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title简单的 Vue 实例/titlestyle.progress{height: 25px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner{width: 50%;height: 20px;border-radius: 10px;text-align: right;position: relative;background-color: #409eff;background-size: 20px,20px;box-sizing: border-box;transition: all 1s; }.inner span{position: absolute;right: -20px;bottom: -25px;}/style
/head
!--
.inner中的 transition:all 1s是丝滑变化的原理--
bodydiv idappdiv classprogressdiv classinner v-bind:style{width:percent %}!--这里必须把%引用 因为width后面要接一个数值--span{{percent}}/span/div/divbutton clickpercent 25设置25%/buttonbutton clickpercent50设置50%/buttonbutton clickpercent 75设置75%/buttonbutton clickpercent 100设置100%/button/divscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{percent: 30}})/script
/body/html
3.v-model应用其他表单元素
作用获取/设置表单元素的值
v-model会根据控件类型自动选择正确的方法来更新元素
input:text -value
textarea -value
intput:checkbox -checked
input:radio -checked
select -value前置理解
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性用于提交给后台的数据
结合 Vue 使用 → v-model
前置理解
1. option 需要设置 value 值提交给后台
2. select 的 value 值关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlestyletextare{display: block;width: 240px;height: 100px;margin: 10px 0;}/style
/head
bodydiv idapph1学习网站/h1姓名input typetext v-modelusernamebrbr是否单身:input typecheckbox v-modelisSinglebrbr
!-- 前置理解1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥2. value: 给单选框加上 value 属性用于提交给后台的数据结合 Vue 使用 → v-model--性别:input v-modelgender typeradio namegender value1男input v-modelgender typeradio namegender value2女brbr
!-- 前置理解1. option 需要设置 value 值提交给后台2. select 的 value 值关联了选中的 option 的 value 值结合 Vue 使用 → v-model--所在城市select v-modelcityIdoption value101北京/optionoption value102上海/optionoption value103成都/optionoption value104南京/option/selectbrbrbutton立刻注册/button/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {username:,isSingle:false,gender:2,cityId:102,desc:}})/script
/body
/html4.计算属性computed
概念基于现有的数据计算出来的新属性。依赖的数据变化自动重新计算。
语法
1.声明在computed配置项中一个计算属性对应一个函数
2.使用起来和普通属性一样 {{计算属性名}}
计算属性-可以将一段求值的代码进行封装
3.如果在computed写了 xxx()这个方法 你就可以在html中{{xxx}} 至于xxx到底是怎么来的 交给xxx() 这里通常是this来调用data中的值回调函数进行计算
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlestyletable {border: 1px solid #000;text-align: center;width: 240px;}th,td{border: 1px solid #000;}h3{position: relative;}/style
/head
bodydiv idapph1礼物清单/h1tabletrth名字/thth数量/th/trtr v-for(item,index) in list :keyitem.idtd{{item.name}}/tdtd{{item.num}}/td/tr/tablep礼物总数 {{totalCount}}/p/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el: #app,data: {list:[{id:1,name:篮球,num:1},{id:2,name:玩具,num:2},{id:3,name:铅笔,num:5},]},computed:{totalCount(){// 基于现有的数据编写求值逻辑// 计算属性函数内部可以直接通过 this 访问到 app 实例// console.log(this.list)// 需求对 this.list 数组里面的 num 进行求和 → reducelet totalthis.list.reduce((sum,item)sumitem.num,0)return total;/*this.list 是一个数组其中包含了一些对象或元素。
reduce 方法是数组对象的一个高阶函数用于将数组中的每个元素执行一个指定的回调函数并将结果汇总成单个值。在这个例子中reduce 会对 this.list 数组中的每个元素执行回调函数。
回调函数接受两个参数第一个参数是累积值通常命名为 accumulator在这里命名为 sum第二个参数是当前正在处理的元素在这里命名为 item。
回调函数执行的操作是将当前元素的 num 属性值加到累积值上。
初始值为 0作为累积值的起始值。*/}}})/script
/body
/html5.computed计算属性vs方法methods
computed计算属性
**作用**封装了一段对于数据的处理求得一个结果
语法
1.写在computed的配置项中
2.作为属性直接使用-this.计算属性{{计算属性}}
methods方法
作用给实例提供一个方法调用以处理业务逻辑
语法
1.写在methods配置项中
2.作为方法需要调用 — this.方法名() {{方法名()}} 事件名“方法名” 八股部分 计算属性会对计算出来的结果缓存再次使用直接读取缓存 依赖项变化了会自动重新计算 -并且再次缓存 缓存特性-提升性能 6.计算属性的完整写法
计算属性默认的简写只能访问读取不能修改
如果要修改需要写计算属性的完整写法
一种常用逻辑
1.Input中v-model绑定一个变量
2.展示部分以计算属性表示{{xxx}}
3.定义动态属性:xxx的get和set方法return xxx (这里的xxx是data中的属性xxx)
以上操作完成就可以实现输入框的内容实时反馈到标签表现中
computed:{计算属性名(){代码逻辑(计算逻辑)return 结果}
}computed:{计算属性名{get(){一段代码逻辑(计算逻辑)return 结果},set(修改的值)一段代码逻辑(修改逻辑)
}!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlestyleinput{width: 30px;}/style
/head
bodydiv idapp姓 input typetext v-modelfirstName名 input typetext v-modellastNamespan{{fullName}}/spanbrbrbutton clickchangeName改名卡/button/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{firstName:刘,lastName:备,},methods:{changeName(){this.fullName 黄忠}},computed:{fullName:{get(){return this.firstNamethis.lastName},set(value){this.firstName value.slice(0,1)this.lastNamevalue.slice(1)}}}})/script
/body
/html7.成绩案例
要点分析 计算属性中的方法 this.list.reduce((sum,item)sumlist.score,0)
//是指 用sum来储存累加变量 item表示当前处理的数组元素 类似于增强for中定义的第三方变量 0表示从0开始积累
//这里是在对list数组中每个元素的score进行累加函数中的方法 this.listthis.list.filter(itemitem.id!id)
//非常经典的删除行
//filter实质上会生成一个新的数组这个数组的元素是满足 第三方变量的id不等于id,也就是说 我传入的id不会被添加到新的数组中this.list.unshift({id:new Date(),subject : this.subject,score: this.score})
this.subject,this.score
//list.unshift作用是修改数组更新视图 说白了就是往[]中添加一个{}
//这里是用作tr的v-for中的元素
//id用时间戳来代替 并且在标签中设定为:key
//subject和score都取data中的 最后记得重置为空!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /link relstylesheet href./styles/index.css /titleDocument/title/headbodydiv idapp classscore-casediv classtabletabletheadtrth编号/thth科目/thth成绩/thth操作/th/tr/theadtbody v-iflist.length0tr v-for(item,index) in list v-bind:keyitem.idtd{{index1}}/tdtd{{item.subject}}/tdtd :class{red:item.score60}{{item.score}}/tdtda click.preventdel(item.id) hrefhttps://www.baidu.com删除/td/tr/tbodytbody v-elsetrtd colspan5span总分{{totalScore}}/spanspan stylemargin-left: 50px平均分:{{averageScore}}/span/td/tr/tbody/table/divdiv classformdiv classform-itemdiv classlabel科目:/divdiv classinputinput typetextplaceholder请输入科目v-model.trimsubject//div/divdiv classform-itemdiv classlabel分数/divdiv classinputinput typetext placeholder请输入分数v-model.numberscore/div/divdiv classform-itemdiv classlabel/divdiv classinputbutton clickadd classsubmit添加/button/div/div/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst app new Vue({el:#app,data:{list:[{id:1,subject:语文,score:62},{id:7,subject:数学,score:89},{id:12,subject:英语,score:70},],subject:,score:},computed:{totalScore(){return this.list.reduce((sum,item)sumlist.score,0)},averageScore(){if(this.list.length0){return 0}return (this.totalScore/this.list.length).toFixed(2)}},methods:{del(id){this.listthis.list.filter(itemitem.id!id)},add(){if(!this.subject){alert(请输入科目)return}if(typeof this.score!number){alert(请输入正确的成绩)return}this.list.unshift({id:new Date(),subject : this.subject,score: this.score})this.subject,this.score}}})/script/body
/html
8.watch-简写-语法
作用监视数据变化执行业务逻辑或者异步操作
语法 1.简单写法-简单类型数据直接监视 2.完整写法-添加额外配置项 deep:true 对复杂类型深度监视immediate:true 初始化立刻执行一次handler方法handler就是简单写法中的监视发生变化执行的代码
简单写法
data:{words:苹果,obj:{words:苹果}},watch{//该方法会在数据变化时触发执行数据属性名(newValue,oldValue){//业务逻辑},对象.属性名(newValue,OldValue){//业务逻辑}}完整写法
const app new Vue({el:#app,data:{obj:{words:苹果,lang:italy},},watch:{数据属性名:{deep:true//深度监视handler(newValue){console.log(newValue)}}}
})9.watch-简写-业务实现
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlestyle* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}/style/headbodydiv idapp!-- 条件选择框 --div classqueryspan翻译成的语言/spanselectoption valueitaly意大利/optionoption valueenglish英语/optionoption valuegerman德语/option/select/div!-- 翻译框 --div classboxdiv classinput-wraptextarea v-modelobj.words/textareaspani⌨️/i文档翻译/span/divdiv classoutput-wrapdiv classtransbox{{ result }}/div/div/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscript srchttps://cdn.jsdelivr.net/npm/axios/dist/axios.min.js/scriptscript// 接口地址https://applet-base-api-t.itheima.net/api/translate// 请求方式get// 请求参数// 1words需要被翻译的文本必传// 2lang 需要被翻译成的语言可选默认值-意大利// -----------------------------------------------const app new Vue({el: #app,data: {// words: obj: {words: },result: , // 翻译结果// timer: null // 延时器id},// 具体讲解(1) watch语法 (2) 具体业务实现watch: {// 该方法会在数据变化时调用执行// newValue新值, oldValue老值一般不用// words (newValue) {// console.log(变化了, newValue)// }obj.words (newValue) {// console.log(变化了, newValue)// 防抖: 延迟执行 → 干啥事先等一等延迟一会一段时间内没有再次触发才执行clearTimeout(this.timer)this.timer setTimeout(async () {const res await axios({url: https://applet-base-api-t.itheima.net/api/translate,params: {words: newValue}})this.result res.data.dataconsole.log(res.data.data)}, 300)}}})/script/body
/html
10.watch-完整写法
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlestyle* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}/style/headbodydiv idapp!-- 条件选择框 --div classqueryspan翻译成的语言/spanselect v-modelobj.langoption valueitaly意大利/optionoption valueenglish英语/optionoption valuegerman德语/option/select/div!-- 翻译框 --div classboxdiv classinput-wraptextarea v-modelobj.words/textareaspani⌨️/i文档翻译/span/divdiv classoutput-wrapdiv classtransbox{{ result }}/div/div/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscript srchttps://cdn.jsdelivr.net/npm/axios/dist/axios.min.js/scriptscript// 需求输入内容修改语言都实时翻译// 接口地址https://applet-base-api-t.itheima.net/api/translate// 请求方式get// 请求参数// 1words需要被翻译的文本必传// 2lang 需要被翻译成的语言可选默认值-意大利// -----------------------------------------------const app new Vue({el: #app,data: {obj: {words: 小黑,lang: italy},result: , // 翻译结果},watch: {obj: {deep: true, // 深度监视immediate: true, // 立刻执行一进入页面handler就立刻执行一次handler (newValue) {clearTimeout(this.timer)this.timer setTimeout(async () {const res await axios({url: https://applet-base-api-t.itheima.net/api/translate,params: newValue})this.result res.data.dataconsole.log(res.data.data)}, 300)}}// obj.words (newValue) {// clearTimeout(this.timer)// this.timer setTimeout(async () {// const res await axios({// url: https://applet-base-api-t.itheima.net/api/translate,// params: {// words: newValue// }// })// this.result res.data.data// console.log(res.data.data)// }, 300)// }}})/script/body
/html
11.项目实战 方法集锦 this.fruitList.every(itemitem.isChecked)
//every方法检查fruitList数组中每个元素是否都有isChecked为true,只有全部满足则返回false
//返回 true/falsethis.fruitList.array.forEach(itemitem.isCheckedvalue)
//将item.isChecked设置为你想设置的值 value是外部传入的参数
//返回true/false;this.fruitList.reduce((sum,item){if(item.isChecked){return sumitem.num*item.price;{return sum;}}
/*
reduce是JavaScript提供的高阶函数,对数组中的每一个元素,执行一个提供的回调函数
通常用于数组累加汇总转换reduce函数有两个parameters 回调函数初始值初始值是放在外面的,并且是累加器
回调函数有四个参数: 累加器(sum),当前元素(item),当前索引,原数组
返回值
*/const fruit this.fruitList.find(itemitem.idid)
//find是返回一个值监视器实现本地储存 watch:{fruitlist:{deep:true,handler(newValue){localStorage.setItem(list,JSON.stringify(newValue))}}}!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /link relstylesheet href./css/inputnumber.css /link relstylesheet href./css/index.css /title购物车/title/headbodydiv classapp-container idapp!-- 顶部banner --div classbanner-boximg srcD:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/fruit.jpg alt //div!-- 面包屑 --div classbreadcrumbspan/span/span购物车/span/div!-- 购物车主体 --div classmain v-iffruitList.length 0div classtable!-- 头部 --div classtheaddiv classtrdiv classth选中/divdiv classth th-pic图片/divdiv classth单价/divdiv classth num-th个数/divdiv classth小计/divdiv classth操作/div/div/div!-- 身体 --div classtbodydiv v-for(item, index) in fruitList :keyitem.id classtr :class{ active: item.isChecked }div classtdinput typecheckbox v-modelitem.isChecked //divdiv classtdimg :srcitem.icon alt //divdiv classtd{{ item.price }}/divdiv classtddiv classmy-input-numberbutton :disableditem.num 1 classdecrease clicksub(item.id) - /buttonspan classmy-input__inner{{ item.num }}/spanbutton classincrease clickadd(item.id) /button/div/divdiv classtd{{ item.num * item.price }}/divdiv classtdbutton clickdel(item.id)删除/button/div/div/div/div!-- 底部 --div classbottom!-- 全选 --label classcheck-allinput typecheckbox v-modelisAll/全选/labeldiv classright-box!-- 所有商品总价 --span classprice-box总价nbsp;nbsp;:nbsp;nbsp;¥nbsp;span classprice{{ totalPrice }}/span/span!-- 结算按钮 --button classpay结算( {{ totalCount }} )/button/div/div/div!-- 空车 --div classempty v-else空空如也/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst defaultArr [{id: 1,icon: D:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/火龙果.png,isChecked: true,num: 2,price: 6,},{id: 2,icon: D:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/荔枝.png,isChecked: false,num: 7,price: 20,},{id: 3,icon: D:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/榴莲.png,isChecked: false,num: 3,price: 40,},{id: 4,icon: D:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/鸭梨.png,isChecked: true,num: 10,price: 3,},{id: 5,icon: D:/desklop/湖科大计算机科学与技术系/Vue/Vue23入门到实战-配套资料/01-随堂代码素材/day02/day02/code/15-综合案例-购物车/img/樱桃.png,isChecked: false,num: 20,price: 34,},]const app new Vue({el: #app,data: {// 水果列表fruitList: JSON.parse(localStorage.getItem(list)) || defaultArr,},computed: {// 默认计算属性只能获取不能设置要设置需要写完整写法// isAll () {// // 必须所有的小选框都选中全选按钮才选中 → every// return this.fruitList.every(item item.isChecked)// }// 完整写法 get setisAll: {get () {return this.fruitList.every(item item.isChecked)},set (value) {// 基于拿到的布尔值要让所有的小选框 同步状态this.fruitList.forEach(item item.isChecked value)}},// 统计选中的总数 reducetotalCount () {return this.fruitList.reduce((sum, item) {if (item.isChecked) {// 选中 → 需要累加return sum item.num} else {// 没选中 → 不需要累加return sum}}, 0)},// 总计选中的总价 num * pricetotalPrice () {return this.fruitList.reduce((sum, item) {if (item.isChecked) {return sum item.num * item.price} else {return sum}}, 0)}},methods: {del (id) {this.fruitList this.fruitList.filter(item item.id ! id)},add (id) {// 1. 根据 id 找到数组中的对应项 → findconst fruit this.fruitList.find(item item.id id)// 2. 操作 num 数量fruit.num},sub (id) {// 1. 根据 id 找到数组中的对应项 → findconst fruit this.fruitList.find(item item.id id)// 2. 操作 num 数量fruit.num--}},watch: {fruitList: {deep: true,handler (newValue) {// 需要将变化后的 newValue 存入本地 转JSONlocalStorage.setItem(list, JSON.stringify(newValue))}}}})/script/body
/html
五:生命周期/综合案例/工程化开发入门/工程化案例
1.生命周期生命周期四个阶段
思考什么时候可以发送初始化渲染请求越早越好什么时候可以开始操作dom(至少dom得渲染出来)
Vue生命周期一个Vue实例从创建到销毁的整个过程
四个阶段 创建阶段new Vue() data:{title:;计数器,count:100
}//响应式数据
//发送初始化渲染请求挂载阶段 div id#apph3{{title}}/h3divbutton-/buttonspan{{count}}/spanbutton/button/div
/div
!--渲染模板同时操作Dom--更新阶段 点击网页的加减号修改数据的同时就会更新视图 销毁阶段 销毁实例
2.生命周期钩子
定义Vue生命周期过程中会自动运行一些函数被称为生命周期钩子-开发者在特定阶段运行自己的代码
地位在Vue实例内部是最高的一批和el与data是平级的
1.创建阶段
beforeCreate
created//主要作用
2.挂载阶段渲染模板
beforeMount
mounted//主要作用
3.更新阶段:修改数据更新视图
beforeUpdate
updated//主要作用
4.销毁阶段:销毁实例:释放Vue外的资源清除定时器延时器
beforeDestory
destoryed//主要作用具体的函数例子
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodydiv idapph3{{title}}/h3divbutton clickcount---/buttonspan{{count}}/spanbutton clickcount/button/div/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscriptconst appnew Vue({el:#app,data:{count:100,title:计数器},beforeCreate(){console.log(beforeCreate响应式数据准备好以前,this.count)},created(){console.log(created响应式数据准备好之后,this.count)},beforeMount(){console.log(beforeMount模板渲染之前,document.querySelectorAll(h3).innerHTML)},mounted(){console.log(mounted模板渲染之后)},beforeUpdate(){console.log(beforeUpdate)},updated(){console.log(updated)},beforeDestory(){console.log(beforeDestory定时器)},destoryed(){console.log(destoryed)}})/script
/body3.生命周期案例
A.created新闻案例 created()-获取data 本案例的data是额外储存的因此需要通过created获取然后将data储存到本地vue的data属性中 async created () {// 1. 发送请求获取数据const res await axios.get(http://hmajax.itheima.net/api/news)// 2. 更新到 list 中用于页面渲染 v-forthis.list res.data.data}})async标识意味着created是一个异步方法 使用了axios库来获取网址中的data包 并且通过.data方法进行解包,下面为网址中的包 {message: 获取新闻列表成功,data: [{id: 1,title: 5G渗透率持续提升创新业务快速成长,source: 新京报经济新闻,cmtcount: 58,img: http://ajax-api.itheima.net/images/0.webp,time: 2222-10-28 11:50:28},{id: 5,title: 为什么说中美阶段性协议再近一步读懂周末的这些关键信息,source: 澎湃新闻,cmtcount: 131,img: http://ajax-api.itheima.net/images/4.webp,time: 2222-10-24 09:08:34},{id: 6,title: 阿根廷大选结果揭晓反对派费尔南德斯有话要说,source: 海外网,cmtcount: 99,img: http://ajax-api.itheima.net/images/5.webp,time: 2222-10-23 17:41:15},{id: 8,title: LV母公司当年史上最大并购报价145亿美元购Tiffany,source: 澎湃新闻,cmtcount: 119,img: http://ajax-api.itheima.net/images/7.webp,time: 2222-10-22 03:59:44},{id: 9,title: 黄峥当年1350亿蝉联80后白手起家首富1年中财富每天涨1个亿,source: 胡润百富,cmtcount: 676,img: http://ajax-api.itheima.net/images/8.webp,time: 2222-10-21 06:19:37}]
}!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlestyle* {margin: 0;padding: 0;list-style: none;}.news {display: flex;height: 120px;width: 600px;margin: 0 auto;padding: 20px 0;cursor: pointer;}.news .left {flex: 1;display: flex;flex-direction: column;justify-content: space-between;padding-right: 10px;}.news .left .title {font-size: 20px;}.news .left .info {color: #999999;}.news .left .info span {margin-right: 20px;}.news .right {width: 160px;height: 120px;}.news .right img {width: 100%;height: 100%;object-fit: cover;}/style
/head
bodydiv idappulli v-for(item, index) in list :keyitem.id classnewsdiv classleftdiv classtitle{{ item.title }}/divdiv classinfospan{{ item.source }}/spanspan{{ item.time }}/span/div/divdiv classrightimg :srcitem.img alt/div/li/ul/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscript srchttps://cdn.jsdelivr.net/npm/axios/dist/axios.min.js/scriptscript// 接口地址http://hmajax.itheima.net/api/news// 请求方式getconst app new Vue({el: #app,data: {list: []},async created () {// 1. 发送请求获取数据const res await axios.get(http://hmajax.itheima.net/api/news)// 2. 更新到 list 中用于页面渲染 v-forthis.list res.data.data}})/script
/body
/htmlB.焦点的获取 焦点获取是对标签的操作因此是渲染过程因此通过mounted进行 // 核心思路// 1. 等input框渲染出来 mounted 钩子// 2. 让input框获取焦点 inp.focus()mounted () {document.querySelector(#inp).focus()}!DOCTYPE html
html langzh-CNheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title示例-获取焦点/title!-- 初始化样式 --link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/reset.css2.0.2/reset.min.css!-- 核心样式 --stylehtml,body {height: 100%;}.search-container {position: absolute;top: 30%;left: 50%;transform: translate(-50%, -50%);text-align: center;}.search-container .search-box {display: flex;}.search-container img {margin-bottom: 30px;}.search-container .search-box input {width: 512px;height: 16px;padding: 12px 16px;font-size: 16px;margin: 0;vertical-align: top;outline: 0;box-shadow: none;border-radius: 10px 0 0 10px;border: 2px solid #c4c7ce;background: #fff;color: #222;overflow: hidden;box-sizing: content-box;-webkit-tap-highlight-color: transparent;}.search-container .search-box button {cursor: pointer;width: 112px;height: 44px;line-height: 41px;line-height: 42px;background-color: #ad2a27;border-radius: 0 10px 10px 0;font-size: 17px;box-shadow: none;font-weight: 400;border: 0;outline: 0;letter-spacing: normal;color: white;}body {background: no-repeat center /cover;background-color: #edf0f5;}/style
/headbody
div classcontainer idappdiv classsearch-containerimg srchttps://www.itheima.com/images/logo.png altdiv classsearch-boxinput typetext v-modelwords idinpbutton搜索一下/button/div/div
/divscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script
scriptconst app new Vue({el: #app,data: {words: },// 核心思路// 1. 等input框渲染出来 mounted 钩子// 2. 让input框获取焦点 inp.focus()mounted () {document.querySelector(#inp).focus()}})
/script/body/html4.综合案例记账本
A.列表渲染
** (1) 立刻发送请求获取数据 created*
** (2) 拿到数据存到data的响应式数据中*
** (3) 结合数据进行渲染 v-for*
** (4) 消费统计 计算属性* toFixed() 是 JavaScript 中用于将数字转换为指定小数位数的字符串的方法。 具体来说toFixed(2) 方法会将数字四舍五入到指定的小数位数并返回一个字符串表示结果。 computed:{totalPrice(){return this.list.reduce((sum,item)sumitem.price,0)},
mounted(){
B.添加
** (1) 收集表单数据 v-model*
** (2) 给添加按钮注册点击事件发送添加请求*
** (3) 需要重新渲染* async add () {if (!this.name) {alert(请输入消费名称)return}if (typeof this.price ! number) {alert(请输入正确的消费价格)return}// 发送添加请求const res await axios.post(https://applet-base-api-t.itheima.net/bill, {creator: 小黑,name: this.name,price: this.price})// 重新渲染一次this.getList()this.name this.price },C.删除
** (1) 注册点击事件传参传 id*
** (2) 根据 id 发送删除请求*
** (3) 需要重新渲染*
async del (id) {// 根据 id 发送删除请求const res await axios.delete(https://applet-base-api-t.itheima.net/bill/${id})// 重新渲染this.getList()}D.饼图渲染
** (1) 初始化一个饼图 echarts.init(dom) mounted钩子实现*
** (2) 根据数据实时更新饼图 echarts.setOption({ … })* this.myChart echarts.init(document.querySelector(#main))this.myChart.setOption({// 大标题title: {text: 消费账单列表,left: center},// 提示框tooltip: {trigger: item},// 图例legend: {orient: vertical,left: left},// 数据项series: [{name: 消费账单,type: pie,radius: 50%, // 半径data: [// { value: 1048, name: 球鞋 },// { value: 735, name: 防晒霜 }],emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: rgba(0, 0, 0, 0.5)}}}]})},E.整体工程
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title!-- CSS only --linkrelstylesheethrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css/style.red {color: red!important;}.search {width: 300px;margin: 20px 0;}.my-form {display: flex;margin: 20px 0;}.my-form input {flex: 1;margin-right: 20px;}.table :not(:first-child) {border-top: none;}.contain {display: flex;padding: 10px;}.list-box {flex: 1;padding: 0 30px;}.list-box a {text-decoration: none;}.echarts-box {width: 600px;height: 400px;padding: 30px;margin: 0 auto;border: 1px solid #ccc;}tfoot {font-weight: bold;}media screen and (max-width: 1000px) {.contain {flex-wrap: wrap;}.list-box {width: 100%;}.echarts-box {margin-top: 30px;}}/style/headbodydiv idappdiv classcontain!-- 左侧列表 --div classlist-box!-- 添加资产 --form classmy-forminput v-model.trimname typetext classform-control placeholder消费名称 /input v-model.numberprice typetext classform-control placeholder消费价格 /button clickadd typebutton classbtn btn-primary添加账单/button/formtable classtable table-hovertheadtrth编号/thth消费名称/thth消费价格/thth操作/th/tr/theadtbodytr v-for(item, index) in list :keyitem.idtd{{ index 1 }}/tdtd{{ item.name }}/tdtd :class{ red: item.price 500 }{{ item.price.toFixed(2) }}/tdtda clickdel(item.id) hrefjavascript:;删除/a/td/tr/tbodytfoottrtd colspan4消费总计 {{ totalPrice.toFixed(2) }}/td/tr/tfoot/table/div!-- 右侧图表 --div classecharts-box idmain/div/div/divscript srchttps://cdn.jsdelivr.net/npm/echarts5.4.0/dist/echarts.min.js/scriptscript srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/scriptscript srchttps://cdn.jsdelivr.net/npm/axios/dist/axios.min.js/scriptscript/*** 接口文档地址* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058* * 功能需求* 1. 基本渲染* (1) 立刻发送请求获取数据 created* (2) 拿到数据存到data的响应式数据中* (3) 结合数据进行渲染 v-for* (4) 消费统计 计算属性* 2. 添加功能* (1) 收集表单数据 v-model* (2) 给添加按钮注册点击事件发送添加请求* (3) 需要重新渲染* 3. 删除功能* (1) 注册点击事件传参传 id* (2) 根据 id 发送删除请求* (3) 需要重新渲染* 4. 饼图渲染* (1) 初始化一个饼图 echarts.init(dom) mounted钩子实现* (2) 根据数据实时更新饼图 echarts.setOption({ ... })*/const app new Vue({el: #app,data: {list: [],name: ,price: },computed: {totalPrice () {return this.list.reduce((sum, item) sum item.price, 0)}},created () {// const res await axios.get(https://applet-base-api-t.itheima.net/bill, {// params: {// creator: 小黑// }// })// this.list res.data.datathis.getList()},mounted () {this.myChart echarts.init(document.querySelector(#main))this.myChart.setOption({// 大标题title: {text: 消费账单列表,left: center},// 提示框tooltip: {trigger: item},// 图例legend: {orient: vertical,left: left},// 数据项series: [{name: 消费账单,type: pie,radius: 50%, // 半径data: [// { value: 1048, name: 球鞋 },// { value: 735, name: 防晒霜 }],emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: rgba(0, 0, 0, 0.5)}}}]})},methods: {async getList () {const res await axios.get(https://applet-base-api-t.itheima.net/bill, {params: {creator: 小黑}})this.list res.data.data// 更新图表this.myChart.setOption({// 数据项series: [{// data: [// { value: 1048, name: 球鞋 },// { value: 735, name: 防晒霜 }// ]data: this.list.map(item ({ value: item.price, name: item.name}))}]})},async add () {if (!this.name) {alert(请输入消费名称)return}if (typeof this.price ! number) {alert(请输入正确的消费价格)return}// 发送添加请求const res await axios.post(https://applet-base-api-t.itheima.net/bill, {creator: 小黑,name: this.name,price: this.price})// 重新渲染一次this.getList()this.name this.price },async del (id) {// 根据 id 发送删除请求const res await axios.delete(https://applet-base-api-t.itheima.net/bill/${id})// 重新渲染this.getList()}}})/script/body
/html
5.工程化开发入门
A.工程化开发和脚手架
1.核心包传统开发模式:基于html/css/js文件直接引入核心包开发Vue
2.工程化开发模式基于构建工具(webpack)的环境中开发Vue es6语法/typescript/less/sass -(webpack自动化 编译压缩组合) js(es3/es5) css 问题 webpack配置复杂雷同的基础配置缺乏统一标准 我们需要工具生成标准化的配置 基本介绍
Vue CLI是Vue官方提供的命令行工具可以帮助我们快速创建一个开发Vue项目的标准化基础架子
好处
开箱即用内置babel等工具标准化
使用步骤
全局安装yarn global add vue/cli 或者 npm vue/cli -g查看vue版本 vue --version创建项目架子 vue create project-name(项目名不能用中文)启动项目yarn serve 或者npm run serve (找package.json)
B.目录介绍与项目运行流程
Vue-demo
|-node_modules 第三方包文件夹
|-public 放html的地方
| |-favicon.ico 网站图标
| |-index.html index.html模板文件
|-src 源代码目录-以后写代码的文件夹
| |-assets:静态资源目录-存放图片与字体等
| |-components 组件目录-存放通用组件
| |-App.vue App根组件-项目运行看到的内容就在这里编写
| |-main.js 入口文件-打包或者运行第一个执行的文件
|-.gitignore git忽视文件
|-babel.config.js babel配置文件
|-package.json 项目配置文件-项目名版本号script,依赖包
|-README.md 项目说明文档
|-vue.config.js vue-cli配置文件
|-yarn.lock yarn锁文件由yarn自动生成的用来锁定安装版本//Babel是JavaScript编译器作用是ECMAScript2015(ES6)转化为向后版本的JavaScript版本方便在旧版本的浏览器或者环境执行
//yarn.lock是yarn包管理器自动生成的锁定文件用于确保项目的依赖项在不同环境中有一致的版本。项目运行过程
yarn serve-main.js(App.vue注入到main.js 过程如下)-index.html
import Vue from vue
import App from ./App.vue
new Vue({render:hh(App)
}).$mount(#app)
//描述的是App注入到main.js的过程
/*
new Vue({}): 这部分是创建一个新的 Vue 实例。Vue 实例是 Vue.js 应用程序的核心。通过 new Vue({})我们实例化了一个 Vue 对象用于管理应用的数据、状态和行为。render: h h(App): 这里是 Vue 实例的配置选项之一它定义了 Vue 实例如何渲染内容。在这个例子中render 函数接受一个参数 h它是一个用来创建虚拟 DOM 元素的函数。h(App) 表示使用 h 函数创建一个 App 组件的虚拟 DOM 元素。.$mount(#app): 这是将 Vue 实例挂载到 HTML 页面上的一种方式。$mount 方法用于手动挂载 Vue 实例到一个特定的 DOM 元素上。#app 是一个 CSS 选择器它指定了要挂载到的 HTML 元素的 id这里表示挂载到 id 为 app 的元素上。*/C.组件化
1.组件化一个页面可以拆分成若干组件每个组件都有独立的结构样式行为
好处便于维护利于复用提升开发效率组件分类普通组件、根组件
**2.根组件**整个应用最上层的组件包裹所有普通小组件 App.vue文件单文本组件的三个组成成分
template:结构有且只有一个根元素所有的html元素包含在一个元素内部script:js逻辑style样式可支持less需要装包
让组件支持Less:
style标签langless开启less功能装包:yarn add less less-loader
less代是一种css预处理器扩展了css语言我们给出一个例子。
Less 是一种功能强大的 CSS 预处理器它提供了许多有用的功能来简化和优化 CSS 的编写。以下是一些 Less 中常用的代码示例
变量Variables使用变量来存储颜色、尺寸、字体等重复使用的值以便统一管理和调整。
lessCopy Codeprimary-color: #3498db;
font-stack: Arial, sans-serif;
base-padding: 10px;嵌套规则Nested Rules可以在选择器内部嵌套其他选择器提高样式的可读性和维护性。
lessCopy Code.nav {ul {list-style: none;}li {display: inline-block;margin-right: 10px;a {text-decoration: none;}}
}混合器Mixins类似于函数可以将一组 CSS 属性集合定义为一个混合器然后在需要的地方调用。
lessCopy Code.rounded-corners(radius: 5px) {border-radius: radius;
}运算Operations可以在 Less 中执行数学运算如加法、减法、乘法和除法。
lessCopy Codebase-padding: 10px;
extra-padding: 5px;
.padding {padding: base-padding extra-padding;
}导入其他 Less 文件Import可以将一个 Less 文件导入到另一个 Less 文件中以便将样式模块化管理。
lessCopy Codeimport variables.less;
import mixins.less;条件语句Conditionals可以使用条件语句根据条件设置样式。
lessCopy Codebackground-color: #fff;
body {background-color: background-color;media screen and (max-width: 600px) {background-color: #f5f5f5;}
}循环Loops可以使用循环生成重复的样式减少重复代码。
lessCopy Code.columns(n) when (n 0) {.column-{n} {width: 100% / n;}.columns(n - 1);
}
.columns(12);这些是 Less 中一些常用的代码示例它们使得样式表更加灵活、易维护并提高了开发效率。
D.组件注册
A.分类
1.局部注册
创建.vue文件三个组成部分在使用的组件内导入并且注册 templatediv classhm-footer我是hm-footer/div
/templatescript
export default {}
/scriptstyle
.hm-footer {height: 100px;line-height: 100px;text-align: center;font-size: 30px;background-color: #4f81bd;color: white;
}
/styletemplatediv classhm-header我是hm-header/div
/templatescript
export default {}
/scriptstyle
.hm-header {height: 100px;line-height: 100px;text-align: center;font-size: 30px;background-color: #8064a2;color: white;
}
/styletemplatediv classhm-main我是hm-main/div
/templatescript
export default {}
/scriptstyle
.hm-main {height: 400px;line-height: 400px;text-align: center;font-size: 30px;background-color: #f79646;color: white;margin: 20px 0;
}
/styletemplatediv classApp!-- 头部组件 --HmHeader/HmHeader!-- 主体组件 --HmMain/HmMain!-- 底部组件 --HmFooter/HmFooter!-- 如果 HmFooter tab 出不来 → 需要配置 vscode设置中搜索 trigger on tab → 勾上--/div
/templatescript
import HmHeader from ./components/HmHeader.vue
import HmMain from ./components/HmMain.vue
import HmFooter from ./components/HmFooter.vue
export default {components: {// 组件名: 组件对象HmHeader: HmHeader,HmMain,HmFooter}
}
/scriptstyle
.App {width: 600px;height: 700px;background-color: #87ceeb;margin: 0 auto;padding: 20px;
}
/style// 文件核心作用导入App.vue基于App.vue创建结构渲染index.html
// 1. 导入 Vue 核心包
import Vue from vue// 2. 导入 App.vue 根组件
import App from ./App.vue// 提示当前处于什么环境 (生产环境 / 开发环境)
Vue.config.productionTip false// 3. Vue实例化提供render方法 → 基于App.vue创建结构渲染index.html
new Vue({// el: #app, 作用和$mount(选择器)作用一致用于指定Vue所管理容器// render: h h(App),render: (createElement) {// 基于App创建元素结构return createElement(App)}
}).$mount(#app)
当三个Vue组件都定义好了接下来要到App.vue中进行注册注意Components和标签都要注册
我们注意三个点即可以HmHeader为例子 import HmHeader from ‘./components/HmHeader.vue’ components:{ HmHeader:HmHeader, }
template
div classAppHmHeader/HmHeaderHmMain/HmMainHmFooter/HmFooter/div
/template
script
import HmHeader from ./components/HmHeader.vue
import HmMain from ./components/HmMain.vue
import HmFooter from ./components/HmFooter.vue
export default{components:{HmHeader:HmHeader,HmMain,HmFooter}
}
/script
style
.App {width: 600px;height: 700px;background-color: #87ceeb;margin: 0 auto;padding: 20px;
}
/style2.全局注册所有组件内都能使用
B.使用
当成html标签使用组件名/组件名大驼峰命名法
现在于局部注册基础上添加一个按钮HmFooter.vue对于它我们采取全局注册的方式
templatebutton classhm-button通用按钮/button
/templatescript
export default {}
/scriptstyle
.hm-button {height: 50px;line-height: 50px;padding: 0 20px;background-color: #3bae56;border-radius: 5px;color: white;border: none;vertical-align: middle;cursor: pointer;
}
/style这一次我们不考虑App.vue而是把目光投向main.js
// 文件核心作用导入App.vue基于App.vue创建结构渲染index.html
import Vue from vue
import App from ./App.vue
// 编写导入的代码往代码的顶部编写(规范)
import HmButton from ./components/HmButton
Vue.config.productionTip false// 进行全局注册 → 在所有的组件范围内都能直接使用
// Vue.component(组件名组件对象)
Vue.component(HmButton, HmButton)// Vue实例化提供render方法 → 基于App.vue创建结构渲染index.html
new Vue({// render: h h(App),render: (createElement) {// 基于App创建元素结构return createElement(App)}
}).$mount(#app)
六组件三大组成部分结构/样式/逻辑/组件通信/综合案例分析/进阶语法
1.组件三大组成部分结构/样式/逻辑 只能有一个根元素也就是所有的标签都必须包含在一个 中
A.组件的样式冲突Scoped 此处展示一种项目开发的问题 //一定要确定你是Vue2还是Vue3其中的main.js的导入方式不一样
//下面以Vue3举例
import{createApp} from vue
import App from ./App.vue
const app createApp(App);
app.mount(#app)默认情况写在组件中的样式会全局生效 -因此多个子组件之间样式容易冲突
1.全局样式默认组件中的样式会作用到全局
2.局部样式可以给组件加上scoped属性,可以让样式只作用于当前组件 例如
script
export default {}
/scripttemplate
div classbase-onespanBaseOne/span
/div
/templatestyle scoped
div{border:3px solid blue;margin:30px
}
/stylescript
export default{}
/scripttemplatediv classbase-oneBaseTwo/div
/templatestyle scoped
div{border: 3px solid red;margin:30px;
}
/stylescoped原理 1.当前组件内标签都被添加data-v-hash值的属性 2.css选择器都被添加data-v-hash值的属性选择器 templatediv data-v-che7c9bcp data-v-che7c9bc我是hm-header/p/div
/template
stylediv[data-v-che7c9bc]{border:1px solid #000,margin:10px,0;}
/style
scriptexport default{data(){return{msg:1111;}}}
/script一个组件的data选项为什么必须是一个函数 答保证每个组件实例维护独立的一份数据对象 每次创建新的属性实例都会重新执行一次data函数得到一个新对象 data(){return {count: 100
}2.组件通信
A.什么是组件通信
组件通信就是指组件与组件之间的数据传递组件的数据是独立的无法直接访问其他组件的数据想用其他组件的数据-组件通信
B.不同的组件关系和组件通信方案分类
父子关系非父子关系
解决方案
父子关系props和$emit非父子关系用provideinjecteventbus通用解决方案Vuex(适合复杂业务场景)
B.1父子通信流程
父组件通过props将数据传递给子组件子组件通过**$emit**通知父组件修改更新
B.2父子通信方案的核心流程
2.1父传子props
父中给子添加属性传值子props接收子组件使用
script
import Son from /components/Son.vue;
export default {name:App,data(){return{myTitle:测试title,gg:公告}},components:{Son,}
}
/scripttemplate
div classapp styleborder: 3px solid #000;margin: 10px我是App组件Son v-bind:titlemyTitle v-bind:gggg/Son/div
/templatestyle/stylescript
export default{name:Son-Child,//组件的名称props:[title,gg]
}
/scripttemplate
div classson我是son组件 {{title}}公告{{gg}}
/div
/templatestyle scoped/style2.2子传父$emit:
子$emit发送信息父中给子添加消息监听父中实现处理函数
script
export default{name:Son-child,props:[title],methods:{changeFn(){this.$emit(changeTitle,修改后的title)}}
}
/scripttemplate
div classson我是son组件 {{title}}button clickchangeFn修改title/button
/div
/templatestyle scoped/stylescript
import Son from /components/Son.vue;
export default {name:App,data(){return{myTitle:测试title,gg:公告}},components:{Son,},methods:{handleChange(newTitle){this.myTitlenewTitle;}}
}
/scripttemplate
div classapp styleborder: 3px solid #000;margin: 10px我是App组件Son v-bind:titlemyTitle changeTitlehandleChange/Son/div
/templatestyle/styleC.什么是prop
定义 组件上注册的一些自定义属性
**作用**向子组件传递数据
特点
可以传递任意数量的prop可以传递任意类型的prop
props:{xxx:boolean
}//xxx是名称 boolean是类型 xxx在父组件中template调用子组件时在属性里v-bind:xxxxxxaexport default{data(){return{xxx:000
}
}
}script
export default {props:[username,age,isSingle,car,hobby]
}
/scripttemplate
div classuserInfoh3我是个人信息组件/h3div姓名:{{username}}/divdiv年龄{{age}}/divdiv是否单身:{{isSingle}}/divdiv座驾:{{car.brand}}/divdiv兴趣爱好{{hobby}}/div
/div
/templatestyle
.userInfo{width: 300px;border: 3px solid #000;padding: 20px;
}
.userInfo div{margin: 20px 10px;
}
/stylescript
import UserInfo from /components/UserInfo.vue;
export default{data(){return{username:小帅,age:28,isSingle:true,car:{brand:小米,},hobby:唱跳rap,篮球}},components:{UserInfo}
}
/scripttemplate
div classappUserInfo:usernameusername:ageage:is-singleisSingle:carcar:hobbyhobby/UserInfo
/div
/templatestyle/styleD.prop校验
**思考**组件的prop可以乱传么
**作用**为组件的prop指定验证要求不符合要求控制台就会有错误提示-类似于Java中的自定义异常帮助开发者快速找到问题
语法
类型校验非空校验默认值自定义校验
script
import UserInfo from /components/UserInfo.vue;
export default {data(){return{width:10,}},components:{UserInfo,}
}
/scripttemplatediv classappUserInfo :wwidth/UserInfo/div
/templatestyle/styletemplatediv classbase-progressdiv classinner :style{ width: w % }span{{ w }}%/span/div/div
/templatescript
export default {// 1.基础写法类型校验// props: {// w: Number,// },// 2.完整写法类型、默认值、非空、自定义校验props: {w: {type: Number,required: true,default: 0,validator(val) {// console.log(val)if (val 100 || val 0) {console.error(传入的范围必须是0-100之间)return false} else {return true}},},},
}
/scriptstyle scoped
.base-progress {height: 26px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;
}
.inner {position: relative;background: #379bff;border-radius: 15px;height: 25px;box-sizing: border-box;left: -3px;top: -2px;
}
.inner span {position: absolute;right: 0;top: 26px;
}
/styleE.propdata、单向数据流
**共性**都可以给组件提供数据
区别
data的数据是自己的-随便改prop的数据是外部的-不能直接改要遵循单向数据流
单向数据流是什么
父级prop的数据更新会向下流动影响子组件这个数据流动是单向的。
templatediv classbase-countbutton clickhandleSub-/buttonspan{{ count }}/spanbutton clickhandleAdd/button/div
/templatescript
export default {// 1.自己的数据随便修改 谁的数据 谁负责// data () {// return {// count: 100,// }// },// 2.外部传过来的数据 不能随便修改props: {count: {type: Number,},},methods: {handleSub() {this.$emit(changeCount, this.count - 1)},handleAdd() {this.$emit(changeCount, this.count 1)},},
}
/scriptstyle
.base-count {margin: 20px;
}
/styletemplatediv classappBaseCount :countcount changeCounthandleChange/BaseCount/div
/templatescript
import BaseCount from ./components/BaseCount.vue
export default {components:{BaseCount},data(){return {count:100}},methods: {handleChange(newVal) {// console.log(newVal);this.count newVal}}
}
/scriptstyle/styleF.非父子通信- event bus事件总线
templatediv classbase-a我是A组件接受方p{{msg}}/p /div
/templatescript
import Bus from ../utils/EventBus
export default {data() {return {msg: ,}},created() {Bus.$on(sendMsg, (msg) {// console.log(msg)this.msg msg})},
}
/scriptstyle scoped
.base-a {width: 200px;height: 200px;border: 3px solid #000;border-radius: 3px;margin: 10px;
}
/styletemplatediv classbase-bdiv我是B组件发布方/divbutton clicksendMsgFn发送消息/button/div
/templatescript
import Bus from ../utils/EventBus
export default {methods: {sendMsgFn() {Bus.$emit(sendMsg, 今天天气不错适合旅游)},},
}
/scriptstyle scoped
.base-b {width: 200px;height: 200px;border: 3px solid #000;border-radius: 3px;margin: 10px;
}
/styletemplatediv classbase-c我是C组件接受方p{{msg}}/p /div
/templatescript
import Bus from ../utils/EventBus
export default {data() {return {msg: ,}},created() {Bus.$on(sendMsg, (msg) {// console.log(msg)this.msg msg})},
}
/scriptstyle scoped
.base-c {width: 200px;height: 200px;border: 3px solid #000;border-radius: 3px;margin: 10px;
}
/styleimport Vue from vueconst Bus new Vue()export default BusG.provideinject作用跨层级共享数据
1.父组件provide提供数据
templatediv classapp我是APP组件button clickchange修改数据/buttonSonA/SonASonB/SonB/div
/templatescript
import SonA from ./components/SonA.vue
import SonB from ./components/SonB.vue
export default {provide() {return {// 简单类型 是非响应式的color: this.color,// 复杂类型 是响应式的userInfo: this.userInfo,}},data() {return {color: pink,userInfo: {name: zs,age: 18,},}},methods: {change() {this.color redthis.userInfo.name ls},},components: {SonA,SonB,},
}
/scriptstyle
.app {border: 3px solid #000;border-radius: 6px;margin: 10px;
}
/style2.子孙类型取用
templatediv classSonA我是SonA组件GrandSon/GrandSon/div
/templatescript
import GrandSon from ../components/GrandSon.vue
export default {components:{GrandSon}
}
/scriptstyle
.SonA {border: 3px solid #000;border-radius: 6px;margin: 10px;height: 200px;
}
/styletemplatediv classSonB我是SonB组件/div
/templatescript
export default {}
/scriptstyle
.SonB {border: 3px solid #000;border-radius: 6px;margin: 10px;height: 200px;
}
/styletemplatediv classgrandSon我是GrandSon{{ color }} -{{ userInfo.name }} -{{ userInfo.age }}/div
/templatescript
export default {inject: [color, userInfo],
}
/scriptstyle
.grandSon {border: 3px solid #000;border-radius: 6px;margin: 10px;height: 100px;
}
/style3.综合案例分析
4.进阶语法
A.v-model原理
原理v-model本质是一个语法糖。例如应用在输入框上就是value属性和input属性的合写
**作用**提供数据的双向绑定
数据变视图跟着变 v-bind:value视图变数据跟着变v-on:input注意$event用于在模板中 获取事件的形参
换句话说。你在子组件的方法里面this.$emit(‘input’,e.target.value)
这里的input就必须要在父组件中的template里面引用子组件时候用v-on绑定上
比如v-on:input“selectId$event” 然后v-bind一个value值为selected
但是这样写太麻烦了 我们简化上述的v-on和v-bind以及value与input为v-modelselectID属性
template
div idappinput v-model“msg typetextinput v-bind:valuemsg inputmsg $event.target.value typetext/div
/templateB.表单类组件封装v-model简化代码
1.表单类组件封装-实现子组件和父组件数据的 双向绑定 父传子 数据从父组件通过props传递过来 拆解v-model绑定数据 子传父 监听输入子组件传值给父组件修改 templatedivselect :valuevalue changeselectCityoption value101北京/optionoption value102上海/optionoption value103武汉/optionoption value104广州/optionoption value105深圳/option/select/div
/templatescript
export default {props: {value: String,},methods: {selectCity(e) {this.$emit(input, e.target.value)},},
}
/scriptstyle
/styletemplatediv classappBaseSelectv-modelselectId/BaseSelect/div
/templatescript
import BaseSelect from ./components/BaseSelect.vue
export default {data() {return {selectId: 102,}},components: {BaseSelect,},
}
/scriptstyle
/styleC.sync修饰符
**作用**可以实现 子组件 与 父组件数据 的 双向绑定简化代码
**特点**prop属性名可以自定义非固定为 value
场景 封装弹框类的基础组件 visible属性 true显示 false隐藏
**本质**就是 :属性名 和 update:属性名 合写
**痛点:**我们之前提到了 v-bind:value v-on:input这种例子。但是有时候我们希望v-bind的元素不被限定为value比如我做一个弹窗我希望可读性高一点。于是我希望用visible来替代value这个传值对弹窗类进行封装
BaseDialog:visible.syncisShow///等价于
BaseDialog :visibleisShow
update:visibleisShow$event/那如何接受呢
props:{visible:Boolean
},
this.$emit(update:visible,false);templatediv classbase-dialog-wrap v-showisShowdiv classbase-dialogdiv classtitleh3温馨提示/h3button classclose clickcloseDialogx/button/divdiv classcontentp你确认要退出本系统么/p/divdiv classfooterbutton确认/buttonbutton取消/button/div/div/div
/templatescript
export default {props: {isShow: Boolean,},methods:{closeDialog(){this.$emit(update:isShow,false)}}
}
/scriptstyle scoped
.base-dialog-wrap {width: 300px;height: 200px;box-shadow: 2px 2px 2px 2px #ccc;position: fixed;left: 50%;top: 50%;transform: translate(-50%, -50%);padding: 0 10px;
}
.base-dialog .title {display: flex;justify-content: space-between;align-items: center;border-bottom: 2px solid #000;
}
.base-dialog .content {margin-top: 38px;
}
.base-dialog .title .close {width: 20px;height: 20px;cursor: pointer;line-height: 10px;
}
.footer {display: flex;justify-content: flex-end;margin-top: 26px;
}
.footer button {width: 80px;height: 40px;
}
.footer button:nth-child(1) {margin-right: 10px;cursor: pointer;
}
/styletemplatediv classappbutton clickopenDialog退出按钮/button!-- isShow.sync :isShowisShow update:isShowisShow$event --BaseDialog :isShow.syncisShow/BaseDialog/div
/templatescript
import BaseDialog from ./components/BaseDialog.vue
export default {data() {return {isShow: false,}},methods: {openDialog() {this.isShow true// console.log(document.querySelectorAll(.box)); },},components: {BaseDialog,},
}
/scriptstyle
/styleD.ref和$refs
作用利用ref和$refs可以用于获取dom元素或者组件实例
原本echarts中获取图表容易误取同名表
const myChart echarts.init(document.querySelector(.box))
//现在进行了优化
var myChart echarts.init(this.$refs.baseChartBox)现在我们简化流程减少错误
1.获取Dom:找到目标标签-添加ref属性
div refchartRef我是渲染图表的容器/div2.恰当时机通过this.$refs.xxx获取目标标签
mounted(){console.log(this.$refs.chartRef)
}templatediv classbase-chart-box refbaseChartBox子组件/div
/templatescript
import * as echarts from echartsexport default {mounted() {// 基于准备好的dom初始化echarts实例// document.querySelector 会查找项目中所有的元素// $refs只会在当前组件查找盒子// var myChart echarts.init(document.querySelector(.base-chart-box))var myChart echarts.init(this.$refs.baseChartBox)// 绘制图表myChart.setOption({title: {text: ECharts 入门示例,},tooltip: {},xAxis: {data: [衬衫, 羊毛衫, 雪纺衫, 裤子, 高跟鞋, 袜子],},yAxis: {},series: [{name: 销量,type: bar,data: [5, 20, 36, 10, 10, 20],},],})},
}
/scriptstyle scoped
.base-chart-box {width: 400px;height: 300px;border: 3px solid #000;border-radius: 6px;
}
/styletemplatediv classappdiv classbase-chart-box这是一个捣乱的盒子/divBaseChart/BaseChart/div
/templatescript
import BaseChart from ./components/BaseChart.vue
export default {components:{BaseChart}
}
/scriptstyle
.base-chart-box {width: 300px;height: 200px;
}
/styleE.Vue异步更新、$nextTick 在Vue.js开发过程中我们经常需要关注数据的变化以便进行相应的视图更新。然而JavaScript的执行是单线程的如果在数据更新时直接操作DOM会导致页面渲染不及时出现闪烁等问题。为了解决这个问题Vue.js提供了一个名为nextTick的机制它能够确保在下一个“tick”中执行延迟回调从而实现异步更新DOM。 nextTick是Vue.js中的一个内部方法用于在下一个“tick”执行延迟回调。在Vue.js中一个“tick”指的是JavaScript事件循环的一个完整周期。当调用nextTick时Vue.js会将回调函数添加到队列中等到当前操作完成包括DOM更新后再执行回调函数。 为什么要有nexttick
举个例子
{{num}}
for(let i0; i100000; i){num i
}如果没有 nextTick 更新机制那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图)有了nextTick机制只需要更新一次所以nextTick本质是一种优化策略 需求编辑标题编辑框自动聚焦
希望Dom在更新完成后做某事可以用$nextTick
new Vue({el:#app,data:{message:HelloWorld},methods:{updateMessage(){this.messageHelloWorld;this.$nextTick(function(){console.log(Dom updated)})}}
})在这个示例中当我们调用updateMessage方法时会首先更新数据然后调用$nextTick方法。在下一个“tick”中会执行回调函数此时DOM已经更新完毕我们可以执行相应的操作。