首页
关于
友情链接
留言
推荐
51学代码
资源导航
hexo 博客
Search
1
给网站添加51la统计实现ip访客数显示在网站底部
617 阅读
2
微信小程序开发
234 阅读
3
Ajax请求
177 阅读
4
给网站上方添加流动字幕
175 阅读
5
给网站设置联系客服QQ或者加入QQ群一键唤起
116 阅读
前端
JavaScript 基础
Vue
Vue3
Ajax
echars
canvas
uniapp
后端
Java
项目管理工具
git
微信小程序开发
登录
Search
标签搜索
Vue
Vue3
JavaScript
echars
uniapp
Ajax
svg
canvas
Jeff Dean
累计撰写
14
篇文章
累计收到
7
条评论
首页
栏目
前端
JavaScript 基础
Vue
Vue3
Ajax
echars
canvas
uniapp
后端
Java
项目管理工具
git
微信小程序开发
页面
关于
友情链接
留言
推荐
51学代码
资源导航
hexo 博客
: 欢迎来到51学代码,一个专注于编程技术分享、知识导航、IT技术学习的网站!本站旗下导航网
nav.51xcode.com
搜索到
3
篇与
的结果
2022-05-27
Vue基础
此笔记来源尚硅谷张天禹老师Vue课程资料,放在这里仅供方便学习使用。课程视频连接:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=1一、初识Vue<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>初识Vue</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 初识Vue: 1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象; 2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法; 3.root容器里的代码被称为【Vue模板】; 4.Vue实例和容器是一一对应的; 5.真实开发中只有一个Vue实例,并且会配合着组件一起使用; 6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性; 7.一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新; 注意区分:js表达式 和 js代码(语句) 1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方: (1). a (2). a+b (3). demo(1) (4). x === y ? 'a' : 'b' 2.js代码(语句) (1). if(){} (2). for(){} --> <!-- 准备好一个容器 --> <div id="demo"> <h1>Hello,{{name.toUpperCase()}},{{address}}</h1> </div> <script type="text/javascript" > Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //创建Vue实例 new Vue({ el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。 data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。 name:'atguigu', address:'北京' } }) </script> </body> </html>二、Vue模板语法<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>模板语法</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- Vue模板语法有2大类: 1.插值语法: 功能:用于解析标签体内容。 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。 2.指令语法: 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件.....)。 举例:v-bind:href="xxx" 或 简写为 :href="xxx",xxx同样要写js表达式, 且可以直接读取到data中的所有属性。 备注:Vue中有很多的指令,且形式都是:v-????,此处我们只是拿v-bind举个例子。 --> <!-- 准备好一个容器--> <div id="root"> <h1>插值语法</h1> <h3>你好,{{name}}</h3> <hr/> <h1>指令语法</h1> <a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a> <a :href="school.url" x="hello">点我去{{school.name}}学习2</a> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'jack', school:{ name:'尚硅谷', url:'http://www.atguigu.com', } } }) </script> </html>三、数据绑定<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>数据绑定</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- Vue中有2种数据绑定的方式: 1.单向绑定(v-bind):数据只能从data流向页面。 2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。 备注: 1.双向绑定一般都应用在表单类元素上(如:input、select等) 2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。 --> <!-- 准备好一个容器--> <div id="root"> <!-- 普通写法 --> <!-- 单向数据绑定:<input type="text" v-bind:value="name"><br/> 双向数据绑定:<input type="text" v-model:value="name"><br/> --> <!-- 简写 --> 单向数据绑定:<input type="text" :value="name"><br/> 双向数据绑定:<input type="text" v-model="name"><br/> <!-- 如下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上 --> <!-- <h2 v-model:x="name">你好啊</h2> --> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' } }) </script> </html>四、el与data的两种写法<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>el与data的两种写法</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- data与el的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 (2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。 2.data有2种写法 (1).对象式 (2).函数式 如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。 3.一个重要的原则: 由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。 --> <!-- 准备好一个容器--> <div id="root"> <h1>你好,{{name}}</h1> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //el的两种写法 /* const v = new Vue({ //el:'#root', //第一种写法 data:{ name:'尚硅谷' } }) console.log(v) v.$mount('#root') //第二种写法 */ //data的两种写法 new Vue({ el:'#root', //data的第一种写法:对象式 /* data:{ name:'尚硅谷' } */ //data的第二种写法:函数式 data(){ console.log('@@@',this) //此处的this是Vue实例对象 return{ name:'尚硅谷' } } }) </script> </html>五、MVVM模型<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>理解MVVM</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- MVVM模型 1. M:模型(Model) :data中的数据 2. V:视图(View) :模板代码 3. VM:视图模型(ViewModel):Vue实例 观察发现: 1.data中所有的属性,最后都出现在了vm身上。 2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。 --> <!-- 准备好一个容器--> <div id="root"> <h1>学校名称:{{name}}</h1> <h1>学校地址:{{address}}</h1> <!-- <h1>测试一下1:{{1+1}}</h1> <h1>测试一下2:{{$options}}</h1> <h1>测试一下3:{{$emit}}</h1> <h1>测试一下4:{{_c}}</h1> --> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', address:'北京', } }) console.log(vm) </script> </html>六、数据代理1.回顾Object.defineProperty方法<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>回顾Object.defineproperty方法</title> </head> <body> <script type="text/javascript" > let number = 18 let person = { name:'张三', sex:'男', } Object.defineProperty(person,'age',{ // value:18, // enumerable:true, //控制属性是否可以枚举,默认值是false // writable:true, //控制属性是否可以被修改,默认值是false // configurable:true //控制属性是否可以被删除,默认值是false //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值 get(){ console.log('有人读取age属性了') return number }, //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值 set(value){ console.log('有人修改了age属性,且值是',value) number = value } }) // console.log(Object.keys(person)) console.log(person) </script> </body> </html>2.何为数据代理<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>何为数据代理</title> </head> <body> <!-- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)--> <script type="text/javascript" > let obj = {x:100} let obj2 = {y:200} Object.defineProperty(obj2,'x',{ get(){ return obj.x }, set(value){ obj.x = value } }) </script> </body> </html>3.Vue中的数据代理<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vue中的数据代理</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 1.Vue中的数据代理: 通过vm对象来代理data对象中属性的操作(读/写) 2.Vue中数据代理的好处: 更加方便的操作data中的数据 3.基本原理: 通过Object.defineProperty()把data对象中所有属性添加到vm上。 为每一个添加到vm上的属性,都指定一个getter/setter。 在getter/setter内部去操作(读/写)data中对应的属性。 --> <!-- 准备好一个容器--> <div id="root"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', address:'宏福科技园' } }) </script> </html>七、事件处理1.事件的基本使用<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件的基本使用</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 事件的基本使用: 1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名; 2.事件的回调需要配置在methods对象中,最终会在vm上; 3.methods中配置的函数,不要用箭头函数!否则this就不是vm了; 4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象; 5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参; --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <!-- <button v-on:click="showInfo">点我提示信息</button> --> <button @click="showInfo1">点我提示信息1(不传参)</button> <button @click="showInfo2($event,66)">点我提示信息2(传参)</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', }, methods:{ showInfo1(event){ // console.log(event.target.innerText) // console.log(this) //此处的this是vm alert('同学你好!') }, showInfo2(event,number){ console.log(event,number) // console.log(event.target.innerText) // console.log(this) //此处的this是vm alert('同学你好!!') } } }) </script> </html> 2.事件修饰符<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>事件修饰符</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> <style> *{ margin-top: 20px; } .demo1{ height: 50px; background-color: skyblue; } .box1{ padding: 5px; background-color: skyblue; } .box2{ padding: 5px; background-color: orange; } .list{ width: 200px; height: 200px; background-color: peru; overflow: auto; } li{ height: 100px; } </style> </head> <body> <!-- Vue中的事件修饰符: 1.prevent:阻止默认事件(常用); 2.stop:阻止事件冒泡(常用); 3.once:事件只触发一次(常用); 4.capture:使用事件的捕获模式; 5.self:只有event.target是当前操作的元素时才触发事件; 6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕; --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <!-- 阻止默认事件(常用) --> <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a> <!-- 阻止事件冒泡(常用) --> <div class="demo1" @click="showInfo"> <button @click.stop="showInfo">点我提示信息</button> <!-- 修饰符可以连续写 --> <!-- <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> --> </div> <!-- 事件只触发一次(常用) --> <button @click.once="showInfo">点我提示信息</button> <!-- 使用事件的捕获模式 --> <div class="box1" @click.capture="showMsg(1)"> div1 <div class="box2" @click="showMsg(2)"> div2 </div> </div> <!-- 只有event.target是当前操作的元素时才触发事件; --> <div class="demo1" @click.self="showInfo"> <button @click="showInfo">点我提示信息</button> </div> <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; --> <ul @wheel.passive="demo" class="list"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods:{ showInfo(e){ alert('同学你好!') // console.log(e.target) }, showMsg(msg){ console.log(msg) }, demo(){ for (let i = 0; i < 100000; i++) { console.log('#') } console.log('累坏了') } } }) </script> </html> 3.键盘事件<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>键盘事件</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 1.Vue中常用的按键别名: 回车 => enter 删除 => delete (捕获“删除”和“退格”键) 退出 => esc 空格 => space 换行 => tab (特殊,必须配合keydown去使用) 上 => up 下 => down 左 => left 右 => right 2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名) 3.系统修饰键(用法特殊):ctrl、alt、shift、meta (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。 (2).配合keydown使用:正常触发事件。 4.也可以使用keyCode去指定具体的按键(不推荐) 5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名 --> <!-- 准备好一个容器--> <div id="root"> <h2>欢迎来到{{name}}学习</h2> <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 Vue.config.keyCodes.huiche = 13 //定义了一个别名按键 new Vue({ el:'#root', data:{ name:'尚硅谷' }, methods: { showInfo(e){ // console.log(e.key,e.keyCode) console.log(e.target.value) } }, }) </script> </html> 八、计算属性1.姓名案例_插值语法实现<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_插值语法实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{firstName}}-{{lastName}}</span> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' } }) </script> </html> 2.姓名案例_methods实现<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_methods实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName()}}</span> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ firstName:'张', lastName:'三' }, methods: { fullName(){ console.log('@---fullName') return this.firstName + '-' + this.lastName } }, }) </script> </html> 3.姓名案例_计算属性实现<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_计算属性实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 计算属性: 1.定义:要用的属性不存在,要通过已有属性计算得来。 2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。 3.get函数什么时候执行? (1).初次读取时会执行一次。 (2).当依赖的数据发生改变时会被再次调用。 4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。 5.备注: 1.计算属性最终会出现在vm上,直接读取使用即可。 2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。 --> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 测试:<input type="text" v-model="x"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> <!-- 全名:<span>{{fullName}}</span> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> 全名:<span>{{fullName}}</span> --> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', x:'你好' }, methods: { demo(){ } }, computed:{ fullName:{ //get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值 //get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。 get(){ console.log('get被调用了') // console.log(this) //此处的this是vm return this.firstName + '-' + this.lastName }, //set什么时候调用? 当fullName被修改时。 set(value){ console.log('set',value) const arr = value.split('-') this.firstName = arr[0] this.lastName = arr[1] } } } }) </script> </html> 4.姓名案例_计算属性简写<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_计算属性实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', }, computed:{ //完整写法 /* fullName:{ get(){ console.log('get被调用了') return this.firstName + '-' + this.lastName }, set(value){ console.log('set',value) const arr = value.split('-') this.firstName = arr[0] this.lastName = arr[1] } } */ //简写 fullName(){ console.log('get被调用了') return this.firstName + '-' + this.lastName } } }) </script> </html> 九、监视属性1.天气案例<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 --> <!-- <button @click="isHot = !isHot">切换天气</button> --> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, }) </script> </html> 2.天气案例_监视属性<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_监视属性</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 监视属性watch: 1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作 2.监视的属性必须存在,才能进行监视!! 3.监视的两种写法: (1).new Vue时传入watch配置 (2).通过vm.$watch监视 --> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, /* watch:{ isHot:{ immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } } } */ }) vm.$watch('isHot',{ immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }) </script> </html> 3.天气案例_深度监视<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_深度监视</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 深度监视: (1).Vue中的watch默认不监测对象内部值的改变(一层)。 (2).配置deep:true可以监测对象内部值改变(多层)。 备注: (1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以! (2).使用watch时根据数据的具体结构,决定是否采用深度监视。 --> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> <hr/> <h3>a的值是:{{numbers.a}}</h3> <button @click="numbers.a++">点我让a+1</button> <h3>b的值是:{{numbers.b}}</h3> <button @click="numbers.b++">点我让b+1</button> <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button> {{numbers.c.d.e}} </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, numbers:{ a:1, b:1, c:{ d:{ e:100 } } } }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, watch:{ isHot:{ // immediate:true, //初始化时让handler调用一下 //handler什么时候调用?当isHot发生改变时。 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }, //监视多级结构中某个属性的变化 /* 'numbers.a':{ handler(){ console.log('a被改变了') } } */ //监视多级结构中所有属性的变化 numbers:{ deep:true, handler(){ console.log('numbers改变了') } } } }) </script> </html> 4.天气案例监视属性简写<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>天气案例_监视属性_简写</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ isHot:true, }, computed:{ info(){ return this.isHot ? '炎热' : '凉爽' } }, methods: { changeWeather(){ this.isHot = !this.isHot } }, watch:{ //正常写法 /* isHot:{ // immediate:true, //初始化时让handler调用一下 // deep:true,//深度监视 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }, */ //简写 /* isHot(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue,this) } */ } }) //正常写法 /* vm.$watch('isHot',{ immediate:true, //初始化时让handler调用一下 deep:true,//深度监视 handler(newValue,oldValue){ console.log('isHot被修改了',newValue,oldValue) } }) */ //简写 /* vm.$watch('isHot',(newValue,oldValue)=>{ console.log('isHot被修改了',newValue,oldValue,this) }) */ </script> </html> 5.姓名案例_watch实现<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>姓名案例_watch实现</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- computed和watch之间的区别: 1.computed能完成的功能,watch都可以完成。 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。 两个重要的小原则: 1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。 2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数, 这样this的指向才是vm 或 组件实例对象。 --> <!-- 准备好一个容器--> <div id="root"> 姓:<input type="text" v-model="firstName"> <br/><br/> 名:<input type="text" v-model="lastName"> <br/><br/> 全名:<span>{{fullName}}</span> <br/><br/> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ firstName:'张', lastName:'三', fullName:'张-三' }, watch:{ firstName(val){ setTimeout(()=>{ console.log(this) this.fullName = val + '-' + this.lastName },1000); }, lastName(val){ this.fullName = this.firstName + '-' + val } } }) </script> </html> 十、绑定样式<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>绑定样式</title> <style> .basic{ width: 400px; height: 100px; border: 1px solid black; } .happy{ border: 4px solid red;; background-color: rgba(255, 255, 0, 0.644); background: linear-gradient(30deg,yellow,pink,orange,yellow); } .sad{ border: 4px dashed rgb(2, 197, 2); background-color: gray; } .normal{ background-color: skyblue; } .atguigu1{ background-color: yellowgreen; } .atguigu2{ font-size: 30px; text-shadow:2px 2px 10px red; } .atguigu3{ border-radius: 20px; } </style> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 绑定样式: 1. class样式 写法:class="xxx" xxx可以是字符串、对象、数组。 字符串写法适用于:类名不确定,要动态获取。 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。 2. style样式 :style="{fontSize: xxx}"其中xxx是动态值。 :style="[a,b]"其中a、b是样式对象。 --> <!-- 准备好一个容器--> <div id="root"> <!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 --> <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/> <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 --> <div class="basic" :class="classArr">{{name}}</div> <br/><br/> <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 --> <div class="basic" :class="classObj">{{name}}</div> <br/><br/> <!-- 绑定style样式--对象写法 --> <div class="basic" :style="styleObj">{{name}}</div> <br/><br/> <!-- 绑定style样式--数组写法 --> <div class="basic" :style="styleArr">{{name}}</div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', mood:'normal', classArr:['atguigu1','atguigu2','atguigu3'], classObj:{ atguigu1:false, atguigu2:false, }, styleObj:{ fontSize: '40px', color:'red', }, styleObj2:{ backgroundColor:'orange' }, styleArr:[ { fontSize: '40px', color:'blue', }, { backgroundColor:'gray' } ] }, methods: { changeMood(){ const arr = ['happy','sad','normal'] const index = Math.floor(Math.random()*3) this.mood = arr[index] } }, }) </script> </html> 十一、条件渲染<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>条件渲染</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 条件渲染: 1.v-if 写法: (1).v-if="表达式" (2).v-else-if="表达式" (3).v-else="表达式" 适用于:切换频率较低的场景。 特点:不展示的DOM元素直接被移除。 注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。 2.v-show 写法:v-show="表达式" 适用于:切换频率较高的场景。 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉 3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。 --> <!-- 准备好一个容器--> <div id="root"> <h2>当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> <!-- 使用v-show做条件渲染 --> <!-- <h2 v-show="false">欢迎来到{{name}}</h2> --> <!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> --> <!-- 使用v-if做条件渲染 --> <!-- <h2 v-if="false">欢迎来到{{name}}</h2> --> <!-- <h2 v-if="1 === 1">欢迎来到{{name}}</h2> --> <!-- v-else和v-else-if --> <!-- <div v-if="n === 1">Angular</div> <div v-else-if="n === 2">React</div> <div v-else-if="n === 3">Vue</div> <div v-else>哈哈</div> --> <!-- v-if与template的配合使用 --> <template v-if="n === 1"> <h2>你好</h2> <h2>尚硅谷</h2> <h2>北京</h2> </template> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', n:0 } }) </script> </html> 十二、列表渲染1.基本列表<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>基本列表</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-for指令: 1.用于展示列表数据 2.语法:v-for="(item, index) in xxx" :key="yyy" 3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少) --> <!-- 准备好一个容器--> <div id="root"> <!-- 遍历数组 --> <h2>人员列表(遍历数组)</h2> <ul> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} </li> </ul> <!-- 遍历对象 --> <h2>汽车信息(遍历对象)</h2> <ul> <li v-for="(value,k) of car" :key="k"> {{k}}-{{value}} </li> </ul> <!-- 遍历字符串 --> <h2>测试遍历字符串(用得少)</h2> <ul> <li v-for="(char,index) of str" :key="index"> {{char}}-{{index}} </li> </ul> <!-- 遍历指定次数 --> <h2>测试遍历指定次数(用得少)</h2> <ul> <li v-for="(number,index) of 5" :key="index"> {{index}}-{{number}} </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:19}, {id:'003',name:'王五',age:20} ], car:{ name:'奥迪A8', price:'70万', color:'黑色' }, str:'hello' } }) </script> </html> 2.key的原理<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>key的原理</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 面试题:react、vue中的key有什么作用?(key的内部原理) 1. 虚拟DOM中key的作用: key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下: 2.对比规则: (1).旧虚拟DOM中找到了与新虚拟DOM相同的key: ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM! ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。 (2).旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM,随后渲染到到页面。 3. 用index作为key可能会引发的问题: 1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作: 会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。 2. 如果结构中还包含输入类的DOM: 会产生错误DOM更新 ==> 界面有问题。 4. 开发中如何选择key?: 1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。 2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示, 使用index作为key是没有问题的。 --> <!-- 准备好一个容器--> <div id="root"> <!-- 遍历数组 --> <h2>人员列表(遍历数组)</h2> <button @click.once="add">添加一个老刘</button> <ul> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} <input type="text"> </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'张三',age:18}, {id:'002',name:'李四',age:19}, {id:'003',name:'王五',age:20} ] }, methods: { add(){ const p = {id:'004',name:'老刘',age:40} this.persons.unshift(p) } }, }) </script> </html> 3.列表过滤<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>列表过滤</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <ul> <li v-for="(p,index) of filPerons" :key="index"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false //用watch实现 //#region /* new Vue({ el:'#root', data:{ keyWord:'', persons:[ {id:'001',name:'马冬梅',age:19,sex:'女'}, {id:'002',name:'周冬雨',age:20,sex:'女'}, {id:'003',name:'周杰伦',age:21,sex:'男'}, {id:'004',name:'温兆伦',age:22,sex:'男'} ], filPerons:[] }, watch:{ keyWord:{ immediate:true, handler(val){ this.filPerons = this.persons.filter((p)=>{ return p.name.indexOf(val) !== -1 }) } } } }) */ //#endregion //用computed实现 new Vue({ el:'#root', data:{ keyWord:'', persons:[ {id:'001',name:'马冬梅',age:19,sex:'女'}, {id:'002',name:'周冬雨',age:20,sex:'女'}, {id:'003',name:'周杰伦',age:21,sex:'男'}, {id:'004',name:'温兆伦',age:22,sex:'男'} ] }, computed:{ filPerons(){ return this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !== -1 }) } } }) </script> </html> 4.列表排序<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>列表排序</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <button @click="sortType = 2">年龄升序</button> <button @click="sortType = 1">年龄降序</button> <button @click="sortType = 0">原顺序</button> <ul> <li v-for="(p,index) of filPerons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} <input type="text"> </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ keyWord:'', sortType:0, //0原顺序 1降序 2升序 persons:[ {id:'001',name:'马冬梅',age:30,sex:'女'}, {id:'002',name:'周冬雨',age:31,sex:'女'}, {id:'003',name:'周杰伦',age:18,sex:'男'}, {id:'004',name:'温兆伦',age:19,sex:'男'} ] }, computed:{ filPerons(){ const arr = this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !== -1 }) //判断一下是否需要排序 if(this.sortType){ arr.sort((p1,p2)=>{ return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age }) } return arr } } }) </script> </html> 5.更新时的一个问题<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>更新时的一个问题</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>人员列表</h2> <button @click="updateMei">更新马冬梅的信息</button> <ul> <li v-for="(p,index) of persons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el:'#root', data:{ persons:[ {id:'001',name:'马冬梅',age:30,sex:'女'}, {id:'002',name:'周冬雨',age:31,sex:'女'}, {id:'003',name:'周杰伦',age:18,sex:'男'}, {id:'004',name:'温兆伦',age:19,sex:'男'} ] }, methods: { updateMei(){ // this.persons[0].name = '马老师' //奏效 // this.persons[0].age = 50 //奏效 // this.persons[0].sex = '男' //奏效 // this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效 this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'}) } } }) </script> </html> 6.Vue监测数据改变的原理_对象<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vue监测数据改变的原理</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ name:'尚硅谷', address:'北京', student:{ name:'tom', age:{ rAge:40, sAge:29, }, friends:[ {name:'jerry',age:35} ] } } }) </script> </html> 7.模拟一个数据监测<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script type="text/javascript" > let data = { name:'尚硅谷', address:'北京', } //创建一个监视的实例对象,用于监视data中属性的变化 const obs = new Observer(data) console.log(obs) //准备一个vm实例对象 let vm = {} vm._data = data = obs function Observer(obj){ //汇总对象中所有的属性形成一个数组 const keys = Object.keys(obj) //遍历 keys.forEach((k)=>{ Object.defineProperty(this,k,{ get(){ return obj[k] }, set(val){ console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`) obj[k] = val } }) }) } </script> </body> </html> 8.Vue.set的使用<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vue监测数据改变的原理</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h1>学校信息</h1> <h2>学校名称:{{school.name}}</h2> <h2>学校地址:{{school.address}}</h2> <h2>校长是:{{school.leader}}</h2> <hr/> <h1>学生信息</h1> <button @click="addSex">添加一个性别属性,默认值是男</button> <h2>姓名:{{student.name}}</h2> <h2 v-if="student.sex">性别:{{student.sex}}</h2> <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2> <h2>朋友们</h2> <ul> <li v-for="(f,index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ school:{ name:'尚硅谷', address:'北京', }, student:{ name:'tom', age:{ rAge:40, sAge:29, }, friends:[ {name:'jerry',age:35}, {name:'tony',age:36} ] } }, methods: { addSex(){ // Vue.set(this.student,'sex','男') this.$set(this.student,'sex','男') } } }) </script> </html> 9.Vue监测数据改变的原理_数组<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vue监测数据改变的原理_数组</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> <h1>学校信息</h1> <h2>学校名称:{{school.name}}</h2> <h2>学校地址:{{school.address}}</h2> <h2>校长是:{{school.leader}}</h2> <hr/> <h1>学生信息</h1> <button @click="addSex">添加一个性别属性,默认值是男</button> <h2>姓名:{{student.name}}</h2> <h2 v-if="student.sex">性别:{{student.sex}}</h2> <h2>年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2> <h2>爱好</h2> <ul> <li v-for="(h,index) in student.hobby" :key="index"> {{h}} </li> </ul> <h2>朋友们</h2> <ul> <li v-for="(f,index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ school:{ name:'尚硅谷', address:'北京', }, student:{ name:'tom', age:{ rAge:40, sAge:29, }, hobby:['抽烟','喝酒','烫头'], friends:[ {name:'jerry',age:35}, {name:'tony',age:36} ] } }, methods: { addSex(){ // Vue.set(this.student,'sex','男') this.$set(this.student,'sex','男') } } }) </script> </html> 10.总结Vue数据监测<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>总结数据监视</title> <style> button{ margin-top: 10px; } </style> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- Vue监视数据的原理: 1. vue会监视data中所有层次的数据。 2. 如何监测对象中的数据? 通过setter实现监视,且要在new Vue时就传入要监测的数据。 (1).对象中后追加的属性,Vue默认不做响应式处理 (2).如需给后添加的属性做响应式,请使用如下API: Vue.set(target,propertyName/index,value) 或 vm.$set(target,propertyName/index,value) 3. 如何监测数组中的数据? 通过包裹数组更新元素的方法实现,本质就是做了两件事: (1).调用原生对应的方法对数组进行更新。 (2).重新解析模板,进而更新页面。 4.在Vue修改数组中的某个元素一定要用如下方法: 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse() 2.Vue.set() 或 vm.$set() 特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!! --> <!-- 准备好一个容器--> <div id="root"> <h1>学生信息</h1> <button @click="student.age++">年龄+1岁</button> <br/> <button @click="addSex">添加性别属性,默认值:男</button> <br/> <button @click="student.sex = '未知' ">修改性别</button> <br/> <button @click="addFriend">在列表首位添加一个朋友</button> <br/> <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br/> <button @click="addHobby">添加一个爱好</button> <br/> <button @click="updateHobby">修改第一个爱好为:开车</button> <br/> <button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/> <h3>姓名:{{student.name}}</h3> <h3>年龄:{{student.age}}</h3> <h3 v-if="student.sex">性别:{{student.sex}}</h3> <h3>爱好:</h3> <ul> <li v-for="(h,index) in student.hobby" :key="index"> {{h}} </li> </ul> <h3>朋友们:</h3> <ul> <li v-for="(f,index) in student.friends" :key="index"> {{f.name}}--{{f.age}} </li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 const vm = new Vue({ el:'#root', data:{ student:{ name:'tom', age:18, hobby:['抽烟','喝酒','烫头'], friends:[ {name:'jerry',age:35}, {name:'tony',age:36} ] } }, methods: { addSex(){ // Vue.set(this.student,'sex','男') this.$set(this.student,'sex','男') }, addFriend(){ this.student.friends.unshift({name:'jack',age:70}) }, updateFirstFriendName(){ this.student.friends[0].name = '张三' }, addHobby(){ this.student.hobby.push('学习') }, updateHobby(){ // this.student.hobby.splice(0,1,'开车') // Vue.set(this.student.hobby,0,'开车') this.$set(this.student.hobby,0,'开车') }, removeSmoke(){ this.student.hobby = this.student.hobby.filter((h)=>{ return h !== '抽烟' }) } } }) </script> </html> 十三、收集表单数据<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>收集表单数据</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 收集表单数据: 若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。 若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。 若:<input type="checkbox"/> 1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2.配置input的value属性: (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值) (2)v-model的初始值是数组,那么收集的的就是value组成的数组 备注:v-model的三个修饰符: lazy:失去焦点再收集数据 number:输入字符串转为有效的数字 trim:输入首尾空格过滤 --> <!-- 准备好一个容器--> <div id="root"> <form @submit.prevent="demo"> 账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/> 密码:<input type="password" v-model="userInfo.password"> <br/><br/> 年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/> 性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="male"> 女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/> 爱好: 学习<input type="checkbox" v-model="userInfo.hobby" value="study"> 打游戏<input type="checkbox" v-model="userInfo.hobby" value="game"> 吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat"> <br/><br/> 所属校区 <select v-model="userInfo.city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="wuhan">武汉</option> </select> <br/><br/> 其他信息: <textarea v-model.lazy="userInfo.other"></textarea> <br/><br/> <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a> <button>提交</button> </form> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ userInfo:{ account:'', password:'', age:18, sex:'female', hobby:[], city:'beijing', other:'', agree:'' } }, methods: { demo(){ console.log(JSON.stringify(this.userInfo)) } } }) </script> </html> 十四、过滤器<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>过滤器</title> <script type="text/javascript" src="../js/vue.js"></script> <script type="text/javascript" src="../js/dayjs.min.js"></script> </head> <body> <!-- 过滤器: 定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。 语法: 1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}} 2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名" 备注: 1.过滤器也可以接收额外参数、多个过滤器也可以串联 2.并没有改变原本的数据, 是产生新的对应的数据 --> <!-- 准备好一个容器--> <div id="root"> <h2>显示格式化后的时间</h2> <!-- 计算属性实现 --> <h3>现在是:{{fmtTime}}</h3> <!-- methods实现 --> <h3>现在是:{{getFmtTime()}}</h3> <!-- 过滤器实现 --> <h3>现在是:{{time | timeFormater}}</h3> <!-- 过滤器实现(传参) --> <h3>现在是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3> <h3 :x="msg | mySlice">尚硅谷</h3> </div> <div id="root2"> <h2>{{msg | mySlice}}</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //全局过滤器 Vue.filter('mySlice',function(value){ return value.slice(0,4) }) new Vue({ el:'#root', data:{ time:1621561377603, //时间戳 msg:'你好,尚硅谷' }, computed: { fmtTime(){ return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss') } }, methods: { getFmtTime(){ return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss') } }, //局部过滤器 filters:{ timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){ // console.log('@',value) return dayjs(value).format(str) } } }) new Vue({ el:'#root2', data:{ msg:'hello,atguigu!' } }) </script> </html> 十五、内置指令1.v-text_指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-text指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 我们学过的指令: v-bind : 单向绑定解析表达式, 可简写为 :xxx v-model : 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on : 绑定事件监听, 可简写为@ v-if : 条件渲染(动态控制节点是否存存在) v-else : 条件渲染(动态控制节点是否存存在) v-show : 条件渲染 (动态控制节点是否展示) v-text指令: 1.作用:向其所在的节点中渲染文本内容。 2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。 --> <!-- 准备好一个容器--> <div id="root"> <div>你好,{{name}}</div> <div v-text="name"></div> <div v-text="str"></div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷', str:'<h3>你好啊!</h3>' } }) </script> </html> 2.v-html_指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-html指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-html指令: 1.作用:向指定节点中渲染包含html结构的内容。 2.与插值语法的区别: (1).v-html会替换掉节点中所有的内容,{{xx}}则不会。 (2).v-html可以识别html结构。 3.严重注意:v-html有安全性问题!!!! (1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。 (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上! --> <!-- 准备好一个容器--> <div id="root"> <div>你好,{{name}}</div> <div v-html="str"></div> <div v-html="str2"></div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷', str:'<h3>你好啊!</h3>', str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>', } }) </script> </html> 3.v-cloak_指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-cloak指令</title> <style> [v-cloak]{ display:none; } </style> <!-- 引入Vue --> </head> <body> <!-- v-cloak指令(没有值): 1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。 2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-cloak>{{name}}</h2> </div> <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script> </body> <script type="text/javascript"> console.log(1) Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ name:'尚硅谷' } }) </script> </html> 4.v-once_指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-once指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-once指令: 1.v-once所在节点在初次动态渲染后,就视为静态内容了。 2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-once>初始化的n值是:{{n}}</h2> <h2>当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ n:1 } }) </script> </html> 5.v-pre_指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>v-pre指令</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- v-pre指令: 1.跳过其所在节点的编译过程。 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-pre>Vue其实很简单</h2> <h2 >当前的n值是:{{n}}</h2> <button @click="n++">点我n+1</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ n:1 } }) </script> </html> 十六、自定义指令1.自定义指令<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>自定义指令</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。 需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。 自定义指令总结: 一、定义语法: (1).局部指令: new Vue({ new Vue({ directives:{指令名:配置对象} 或 directives{指令名:回调函数} }) }) (2).全局指令: Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数) 二、配置对象中常用的3个回调: (1).bind:指令与元素成功绑定时调用。 (2).inserted:指令所在元素被插入页面时调用。 (3).update:指令所在模板结构被重新解析时调用。 三、备注: 1.指令定义时不加v-,但使用时要加v-; 2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。 --> <!-- 准备好一个容器--> <div id="root"> <h2>{{name}}</h2> <h2>当前的n值是:<span v-text="n"></span> </h2> <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> --> <h2>放大10倍后的n值是:<span v-big="n"></span> </h2> <button @click="n++">点我n+1</button> <hr/> <input type="text" v-fbind:value="n"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义全局指令 /* Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element,binding){ element.value = binding.value }, //指令所在元素被插入页面时 inserted(element,binding){ element.focus() }, //指令所在的模板被重新解析时 update(element,binding){ element.value = binding.value } }) */ new Vue({ el:'#root', data:{ name:'尚硅谷', n:1 }, directives:{ //big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。 /* 'big-number'(element,binding){ // console.log('big') element.innerText = binding.value * 10 }, */ big(element,binding){ console.log('big',this) //注意此处的this是window // console.log('big') element.innerText = binding.value * 10 }, fbind:{ //指令与元素成功绑定时(一上来) bind(element,binding){ element.value = binding.value }, //指令所在元素被插入页面时 inserted(element,binding){ element.focus() }, //指令所在的模板被重新解析时 update(element,binding){ element.value = binding.value } } } }) </script> </html> 2.回顾一个DOM操作<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> <style> .demo{ background-color: orange; } </style> </head> <body> <button id="btn">点我创建一个输入框</button> <script type="text/javascript" > const btn = document.getElementById('btn') btn.onclick = ()=>{ const input = document.createElement('input') input.className = 'demo' input.value = 99 input.onclick = ()=>{alert(1)} document.body.appendChild(input) input.focus() // input.parentElement.style.backgroundColor = 'skyblue' console.log(input.parentElement) } </script> </body> </html> 十七、生命周期1.引出生命周期<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>引出生命周期</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 生命周期: 1.又名:生命周期回调函数、生命周期函数、生命周期钩子。 2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。 3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。 4.生命周期函数中的this指向是vm 或 组件实例对象。 --> <!-- 准备好一个容器--> <div id="root"> <h2 v-if="a">你好啊</h2> <h2 :style="{opacity}">欢迎学习Vue</h2> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ a:false, opacity:1 }, methods: { }, //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted mounted(){ console.log('mounted',this) setInterval(() => { this.opacity -= 0.01 if(this.opacity <= 0) this.opacity = 1 },16) }, }) //通过外部的定时器实现(不推荐) /* setInterval(() => { vm.opacity -= 0.01 if(vm.opacity <= 0) vm.opacity = 1 },16) */ </script> </html> 2.分析生命周期<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>分析生命周期</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root" :x="n"> <h2 v-text="n"></h2> <h2>当前的n值是:{{n}}</h2> <button @click="add">点我n+1</button> <button @click="bye">点我销毁vm</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', // template:` // <div> // <h2>当前的n值是:{{n}}</h2> // <button @click="add">点我n+1</button> // </div> // `, data:{ n:1 }, methods: { add(){ console.log('add') this.n++ }, bye(){ console.log('bye') this.$destroy() } }, watch:{ n(){ console.log('n变了') } }, beforeCreate() { console.log('beforeCreate') }, created() { console.log('created') }, beforeMount() { console.log('beforeMount') }, mounted() { console.log('mounted') }, beforeUpdate() { console.log('beforeUpdate') }, updated() { console.log('updated') }, beforeDestroy() { console.log('beforeDestroy') }, destroyed() { console.log('destroyed') }, }) </script> </html> 3.总结生命周期<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>引出生命周期</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 常用的生命周期钩子: 1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。 2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。 关于销毁Vue实例 1.销毁后借助Vue开发者工具看不到任何信息。 2.销毁后自定义事件会失效,但原生DOM事件依然有效。 3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。 --> <!-- 准备好一个容器--> <div id="root"> <h2 :style="{opacity}">欢迎学习Vue</h2> <button @click="opacity = 1">透明度设置为1</button> <button @click="stop">点我停止变换</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 new Vue({ el:'#root', data:{ opacity:1 }, methods: { stop(){ this.$destroy() } }, //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted mounted(){ console.log('mounted',this) this.timer = setInterval(() => { console.log('setInterval') this.opacity -= 0.01 if(this.opacity <= 0) this.opacity = 1 },16) }, beforeDestroy() { clearInterval(this.timer) console.log('vm即将驾鹤西游了') }, }) </script> </html> 十八、非单文件组件1.基本使用<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>基本使用</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- Vue中使用组件的三大步骤: 一、定义组件(创建组件) 二、注册组件 三、使用组件(写组件标签) 一、如何定义一个组件? 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别; 区别如下: 1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。 备注:使用template可以配置组件结构。 二、如何注册组件? 1.局部注册:靠new Vue的时候传入components选项 2.全局注册:靠Vue.component('组件名',组件) 三、编写组件标签: <school></school> --> <!-- 准备好一个容器--> <div id="root"> <hello></hello> <hr> <h1>{{msg}}</h1> <hr> <!-- 第三步:编写组件标签 --> <school></school> <hr> <!-- 第三步:编写组件标签 --> <student></student> </div> <div id="root2"> <hello></hello> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //第一步:创建school组件 const school = Vue.extend({ template:` <div class="demo"> <h2>学校名称:{{schoolName}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showName">点我提示学校名</button> </div> `, // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。 data(){ return { schoolName:'尚硅谷', address:'北京昌平' } }, methods: { showName(){ alert(this.schoolName) } }, }) //第一步:创建student组件 const student = Vue.extend({ template:` <div> <h2>学生姓名:{{studentName}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { studentName:'张三', age:18 } } }) //第一步:创建hello组件 const hello = Vue.extend({ template:` <div> <h2>你好啊!{{name}}</h2> </div> `, data(){ return { name:'Tom' } } }) //第二步:全局注册组件 Vue.component('hello',hello) //创建vm new Vue({ el:'#root', data:{ msg:'你好啊!' }, //第二步:注册组件(局部注册) components:{ school, student } }) new Vue({ el:'#root2', }) </script> </html> 2.几个注意点<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>几个注意点</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 几个注意点: 1.关于组件名: 一个单词组成: 第一种写法(首字母小写):school 第二种写法(首字母大写):School 多个单词组成: 第一种写法(kebab-case命名):my-school 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持) 备注: (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。 (2).可以使用name配置项指定组件在开发者工具中呈现的名字。 2.关于组件标签: 第一种写法:<school></school> 第二种写法:<school/> 备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。 3.一个简写方式: const school = Vue.extend(options) 可简写为:const school = options --> <!-- 准备好一个容器--> <div id="root"> <h1>{{msg}}</h1> <school></school> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义组件 const s = Vue.extend({ name:'atguigu', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> `, data(){ return { name:'尚硅谷', address:'北京' } } }) new Vue({ el:'#root', data:{ msg:'欢迎学习Vue!' }, components:{ school:s } }) </script> </html> 3.组件的嵌套<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>组件的嵌套</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 准备好一个容器--> <div id="root"> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 //定义student组件 const student = Vue.extend({ name:'student', template:` <div> <h2>学生姓名:{{name}}</h2> <h2>学生年龄:{{age}}</h2> </div> `, data(){ return { name:'尚硅谷', age:18 } } }) //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <student></student> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, //注册组件(局部) components:{ student } }) //定义hello组件 const hello = Vue.extend({ template:`<h1>{{msg}}</h1>`, data(){ return { msg:'欢迎来到尚硅谷学习!' } } }) //定义app组件 const app = Vue.extend({ template:` <div> <hello></hello> <school></school> </div> `, components:{ school, hello } }) //创建vm new Vue({ template:'<app></app>', el:'#root', //注册组件(局部) components:{app} }) </script> </html> 4.VueComponent<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>VueComponent</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 关于VueComponent: 1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。 2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象, 即Vue帮我们执行的:new VueComponent(options)。 3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!! 4.关于this指向: (1).组件配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。 (2).new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。 5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。 Vue的实例对象,以后简称vm。 --> <!-- 准备好一个容器--> <div id="root"> <school></school> <hello></hello> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showName">点我提示学校名</button> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, methods: { showName(){ console.log('showName',this) } }, }) const test = Vue.extend({ template:`<span>atguigu</span>` }) //定义hello组件 const hello = Vue.extend({ template:` <div> <h2>{{msg}}</h2> <test></test> </div> `, data(){ return { msg:'你好啊!' } }, components:{test} }) // console.log('@',school) // console.log('#',hello) //创建vm const vm = new Vue({ el:'#root', components:{school,hello} }) </script> </html> 5.一个重要的内置关系<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>一个重要的内置关系</title> <!-- 引入Vue --> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <!-- 1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype 2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。 --> <!-- 准备好一个容器--> <div id="root"> <school></school> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 Vue.prototype.x = 99 //定义school组件 const school = Vue.extend({ name:'school', template:` <div> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showX">点我输出x</button> </div> `, data(){ return { name:'尚硅谷', address:'北京' } }, methods: { showX(){ console.log(this.x) } }, }) //创建一个vm const vm = new Vue({ el:'#root', data:{ msg:'你好' }, components:{school} }) //定义一个构造函数 /* function Demo(){ this.a = 1 this.b = 2 } //创建一个Demo的实例对象 const d = new Demo() console.log(Demo.prototype) //显示原型属性 console.log(d.__proto__) //隐式原型属性 console.log(Demo.prototype === d.__proto__) //程序员通过显示原型属性操作原型对象,追加一个x属性,值为99 Demo.prototype.x = 99 console.log('@',d) */ </script> </html> 十九、单文件组件单个点Vue文件,这里省略......后面知识点详见课程文件笔记尚硅谷张天禹老师vue课程资料。免责声明:此笔记来源尚硅谷张天禹老师vue课程资料,放在这里仅供方便学习使用。课程视频连接:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=1欢迎关注本站微信公众号“51学代码”
2022年05月27日
94 阅读
0 评论
0 点赞
2022-05-27
Vue3快速上手
Vue3快速上手1.Vue3简介2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.02.Vue3带来了什么1.性能的提升打包大小减少41%初次渲染快55%, 更新渲染快133%内存减少54%......2.源码的升级使用Proxy代替defineProperty实现响应式重写虚拟DOM的实现和Tree-Shaking......3.拥抱TypeScriptVue3可以更好的支持TypeScript4.新的特性Composition API(组合API)setup配置ref与reactivewatch与watchEffectprovide与inject......新的内置组件FragmentTeleportSuspense其他改变新的生命周期钩子data 选项应始终被声明为一个函数移除keyCode支持作为 v-on 的修饰符......一、创建Vue3.0工程1.使用 vue-cli 创建官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上 vue --version ## 安装或者升级你的@vue/cli npm install -g @vue/cli ## 创建 vue create vue_test ## 启动 cd vue_test npm run serve2.使用 vite 创建官方文档:https://v3.cn.vuejs.org/guide/installation.html#vitevite官网:https://vitejs.cn什么是vite?—— 新一代前端构建工具。优势如下:开发环境中,无需打包操作,可快速的冷启动。轻量快速的热重载(HMR)。真正的按需编译,不再等待整个应用编译完成。传统构建 与 vite构建对比图## 创建工程 npm init vite-app <project-name> ## 进入工程目录 cd <project-name> ## 安装依赖 npm install ## 运行 npm run dev二、常用 Composition API官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html1.拉开序幕的setup理解:Vue3.0中一个新的配置项,值为一个函数。setup是所有Composition API(组合API)“ 表演的舞台 ”。组件中所用到的:数据、方法等等,均要配置在setup中。setup函数的两种返回值:若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)若返回一个渲染函数:则可以自定义渲染内容。(了解)注意点:尽量不要与Vue2.x配置混用Vue2.x配置(data、methos、computed...)中可以访问到setup中的属性、方法。但在setup中不能访问到Vue2.x配置(data、methos、computed...)。如果有重名, setup优先。setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)2.ref函数作用: 定义一个响应式的数据语法: const xxx = ref(initValue)创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。JS中操作数据: xxx.value模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>备注:接收的数据可以是:基本类型、也可以是对象类型。基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的。对象类型的数据:内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数。3.reactive函数作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)reactive定义的响应式数据是“深层次的”。内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。4.Vue3.0中的响应式原理vue2.x的响应式实现原理:对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。Object.defineProperty(data, 'count', { get () {}, set () {} })存在问题:新增属性、删除属性, 界面不会更新。直接通过下标修改数组, 界面不会自动更新。Vue3.0的响应式实现原理:通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。通过Reflect(反射): 对源对象的属性进行操作。MDN文档中描述的Proxy与Reflect:Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ProxyReflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflectnew Proxy(data, { // 拦截读取属性值 get (target, prop) { return Reflect.get(target, prop) }, // 拦截设置属性值或添加新属性 set (target, prop, value) { return Reflect.set(target, prop, value) }, // 拦截删除属性 deleteProperty (target, prop) { return Reflect.deleteProperty(target, prop) } }) proxy.name = 'tom' 5.reactive对比ref从定义数据角度对比:ref用来定义:基本类型数据。reactive用来定义:对象(或数组)类型数据。备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。从原理角度对比:ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。从使用角度对比:ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。reactive定义的数据:操作数据与读取数据:均不需要.value。6.setup的两个注意点setup执行的时机在beforeCreate之前执行一次,this是undefined。setup的参数props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。context:上下文对象attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。slots: 收到的插槽内容, 相当于 this.$slots。emit: 分发自定义事件的函数, 相当于 this.$emit。7.计算属性与监视1.computed函数与Vue2.x中computed配置功能一致写法import {computed} from 'vue' setup(){ ... //计算属性——简写 let fullName = computed(()=>{ return person.firstName + '-' + person.lastName }) //计算属性——完整 let fullName = computed({ get(){ return person.firstName + '-' + person.lastName }, set(value){ const nameArr = value.split('-') person.firstName = nameArr[0] person.lastName = nameArr[1] } }) }2.watch函数与Vue2.x中watch配置功能一致两个小“坑”:监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。监视reactive定义的响应式数据中某个属性时:deep配置有效。//情况一:监视ref定义的响应式数据 watch(sum,(newValue,oldValue)=>{ console.log('sum变化了',newValue,oldValue) },{immediate:true}) //情况二:监视多个ref定义的响应式数据 watch([sum,msg],(newValue,oldValue)=>{ console.log('sum或msg变化了',newValue,oldValue) }) /* 情况三:监视reactive定义的响应式数据 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!! 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视 */ watch(person,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue) },{immediate:true,deep:false}) //此处的deep配置不再奏效 //情况四:监视reactive定义的响应式数据中的某个属性 watch(()=>person.job,(newValue,oldValue)=>{ console.log('person的job变化了',newValue,oldValue) },{immediate:true,deep:true}) //情况五:监视reactive定义的响应式数据中的某些属性 watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{ console.log('person的job变化了',newValue,oldValue) },{immediate:true,deep:true}) //特殊情况 watch(()=>person.job,(newValue,oldValue)=>{ console.log('person的job变化了',newValue,oldValue) },{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效3.watchEffect函数watch的套路是:既要指明监视的属性,也要指明监视的回调。watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。watchEffect有点像computed:但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。 watchEffect(()=>{ const x1 = sum.value const x2 = person.age console.log('watchEffect配置的回调执行了') })8.生命周期vue2.x的生命周期vue3.0的生命周期1Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:beforeDestroy改名为 beforeUnmountdestroyed改名为 unmountedVue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:beforeCreate===>setup()created=======>setup()beforeMount ===>onBeforeMountmounted=======>onMountedbeforeUpdate===>onBeforeUpdateupdated =======>onUpdatedbeforeUnmount ==>onBeforeUnmountunmounted =====>onUnmounted9.自定义hook函数什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。类似于vue2.x中的mixin。自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。10.toRef作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。语法:const name = toRef(person,'name')应用: 要将响应式对象中的某个属性单独提供给外部使用时。扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)三、其它 Composition API1.shallowReactive 与 shallowRefshallowReactive:只处理对象最外层属性的响应式(浅响应式)。shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。什么时候使用?如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。2.readonly 与 shallowReadonlyreadonly: 让一个响应式数据变为只读的(深只读)。shallowReadonly:让一个响应式数据变为只读的(浅只读)。应用场景: 不希望数据被修改时。3.toRaw 与 markRawtoRaw:作用:将一个由reactive生成的响应式对象转为普通对象。使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新。markRaw:作用:标记一个对象,使其永远不会再成为响应式对象。应用场景:有些值不应被设置为响应式的,例如复杂的第三方类库等。当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。4.customRef作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。实现防抖效果:<template> <input type="text" v-model="keyword"> <h3>{{keyword}}</h3> </template> <script> import {ref,customRef} from 'vue' export default { name:'Demo', setup(){ // let keyword = ref('hello') //使用Vue准备好的内置ref //自定义一个myRef function myRef(value,delay){ let timer //通过customRef去实现自定义 return customRef((track,trigger)=>{ return{ get(){ track() //告诉Vue这个value值是需要被“追踪”的 return value }, set(newValue){ clearTimeout(timer) timer = setTimeout(()=>{ value = newValue trigger() //告诉Vue去更新界面 },delay) } } }) } let keyword = myRef('hello',500) //使用程序员自定义的ref return { keyword } } } </script>5.provide 与 inject作用:实现祖与后代组件间通信套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据具体写法:祖组件中:setup(){ ...... let car = reactive({name:'奔驰',price:'40万'}) provide('car',car) ...... } 后代组件中:setup(props,context){ ...... const car = inject('car') return {car} ...... } 6.响应式数据的判断isRef: 检查一个值是否为一个 ref 对象isReactive: 检查一个对象是否是由 reactive 创建的响应式代理isReadonly: 检查一个对象是否是由 readonly 创建的只读代理isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理四、Composition API 的优势1.Options API 存在的问题使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。 2.Composition API 的优势我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。 五、新的组件1.Fragment在Vue2中: 组件必须有一个根标签在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中好处: 减少标签层级, 减小内存占用2.Teleport什么是Teleport?—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。<teleport to="移动位置"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <button @click="isShow = false">关闭弹窗</button> </div> </div> </teleport> 3.Suspense等待异步组件时渲染一些额外内容,让应用有更好的用户体验使用步骤:异步引入组件import {defineAsyncComponent} from 'vue' const Child = defineAsyncComponent(()=>import('./components/Child.vue')) 使用Suspense包裹组件,并配置好default 与 fallback<template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template v-slot:default> <Child/> </template> <template v-slot:fallback> <h3>加载中.....</h3> </template> </Suspense> </div> </template> 六、其他1.全局API的转移Vue 2.x 有许多全局 API 和配置。例如:注册全局组件、注册全局指令等。//注册全局组件 Vue.component('MyButton', { data: () => ({ count: 0 }), template: '<button @click="count++">Clicked {{ count }} times.</button>' }) //注册全局指令 Vue.directive('focus', { inserted: el => el.focus() } Vue3.0中对这些API做出了调整:将全局的API,即:Vue.xxx调整到应用实例(app)上2.x 全局 API(Vue)3.x 实例 API (app)Vue.config.xxxxapp.config.xxxxVue.config.productionTip移除Vue.componentapp.componentVue.directiveapp.directiveVue.mixinapp.mixinVue.useapp.useVue.prototypeapp.config.globalProperties2.其他改变data选项应始终被声明为一个函数。过度类名的更改:Vue2.x写法.v-enter, .v-leave-to { opacity: 0; } .v-leave, .v-enter-to { opacity: 1; } Vue3.x写法.v-enter-from, .v-leave-to { opacity: 0; } .v-leave-from, .v-enter-to { opacity: 1; } 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes移除v-on.native修饰符父组件中绑定事件<my-component v-on:close="handleComponentEvent" v-on:click="handleNativeClickEvent" /> 子组件中声明自定义事件<script> export default { emits: ['close'] } </script> 移除过滤器(filter)过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。......免责声明:此笔记来自尚硅谷张天禹老师讲课笔记,放在这里主要是方便学习使用。欢迎关注本站微信公众号“51学代码”
2022年05月27日
78 阅读
0 评论
0 点赞
2022-05-27
Vue项目环境搭建
项目环境安装一、学习Vue点击进入Vue官网:https://cn.vuejs.org/二、工具Node.js安装(1)打开官方网站:https://nodejs.org/en/(2)选择对应的node版本进行下载(3)安装node.js后,进行版本检查三、使用VsCode开发工具新建Vue项目(1)新建项目文件夹,名字为:MyShop(2)选中文件夹,反键使用VsCode打开项目(3)使用ctrl+~打开终端命令(4)使用淘宝镜像执行cnpm命令 npm install -g cnpm --registry=https://registry.npm.taobao.org 注:因为npm是国外的服务,用起来比较卡。需要换成淘宝的cnpm(5)全局安装vue脚手架 cnpm install -g vue-cli 会提示一下报错: 解决办法如下:管理员身份打开powerShell 输入set-ExecutionPolicy RemoteSigned ,回车输入Y,回车再次安装vue脚手架cnpm install -g vue-cli(6)全局安装webpack cnpm install -g webpack 注意:第一次安装时,步骤不能乱,一定不能乱!(7)新建项目 vue init webpack +项目名注意:项目名字一定要小写,大写会报错(8)安装图解注意:ESlint(严选模式)一定要选NO,否则心态爆炸!(9)执行cnpm命令 cnpm install注意:必须执行此命令,要不然一直会报错(10)运行项目 npm run serve参考文档:https://www.jianshu.com/p/02b12c600c7bhttps://www.cnblogs.com/zyskr/p/10609288.html四、使用vue create 创建项目vue create 是vue-cli3.x的初始化方式,模板是固定的,模板选项可自由配置使用方式:vue create 加项目名称默认选择default方式即可五、vue创建项目之vue init 和 vue create的区别vue init 是vue-cli2.x的初始化方式,可以使用github上面的一些模板来初始化项目webpack是官方推荐的标准模板名使用方式:vue init webpack 项目名称vue create 是vue-cli3.x的初始化方式,模板是固定的,模板选项可自由配置使用方式:vue create 项目名称webpack init 创建,其项目目录为:目录说明:build及config:webpack配置相关 node_modules:通过npm install安装的依赖代码库 src:项目源码 static:存放静态资源 .babelrc:babel相关配置(因为我们的代码大多都是 ES6,而大多浏览器是不支持ES6的,所以我们需要babel帮我们转换成ES5语法) .editorconfig:编辑器的配置,可以在这里修改编码、缩进等 .eslintignore:设置忽略语法检查的目录文件 .eslintrc.js:eslint的配置文件 .gitignore:git忽略里面设定的这些文件的提交 index.html:入口html文件 package.json:项目的配置文件,用于描述一个项目,包括我们init时的设置、开发环境、生成环境的依赖插件及版本等。 package-lock.json:普通package.json文件“^2.0”这样写的,意味着版本可以大于等于2.0,如此就会出现各种错误。使用vue create 创建,其项目目录为:目录说明:build及config:webpack配置相关 node_modules:通过npm install安装的依赖代码库 src:项目源码 static:存放静态资源 .babelrc:babel相关配置(因为我们的代码大多都是 ES6,而大多浏览器是不支持ES6的,所以我们需要babel帮我们转换成ES5语法) .editorconfig:编辑器的配置,可以在这里修改编码、缩进等 .eslintignore:设置忽略语法检查的目录文件 .eslintrc.js:eslint的配置文件 .gitignore:git忽略里面设定的这些文件的提交 index.html:入口html文件 package.json:项目的配置文件,用于描述一个项目,包括我们init时的设置、开发环境、生成环境的依赖插件及版本等。 package-lock.json:普通package.json文件“^2.0”这样写的,意味着版本可以大于等于2.0,如此就会出现各种错误。总结vue create和vue init 的区别vue create 是vue-cli3.x的初始化方式,目前模板是固定的,模板选项可自由配置百,创建出来的是vue-cli3的项度目,与cue-cli2项目结构不同,配置方法不同,具体配置方法参考官方文档网页链接。vue init 是vue-cli2.x的初始化方式,可以使用github上面的一些模板来初始化项目,webpack是官方推荐的标准模板名。vue-cli2.x项目向专3.x迁移只需要把static目录复制到public目录下,老项目的src目录覆盖3.x的src目录(如果修改了配置,可以查看文档,用cli3的方法进行属配置)。运行方式:2.0是通过npm run dev 3.0是npm run serve 至于为什么会变,来看一下package.json文件找到script可以自行修改。文件夹目录:3.0取消掉了config目录、build目录、static目录 ,还有最重要的一点,3.0的安装项目时自动下载node-modelvue.config.js也没了,需要手动添加。六、vue cli2升级到vue cli31.先升级npm的版本npm install -g npm2.再卸载之前的vue cli 2.9.6npm uninstall -g @vue/cli3.下载最新的vue cli版本npm install -g @vue/cli七、安装饿了么UI前端框架cnpm i element-ui -S八、安装less和sass预处理(1):cnpm install less@3.9.0 -s (2):cnpm install less-loader@5.0.0 -s注意:一定要写版本号,否则less自动安装最新版本,会和vue-cli不兼容一直报错。解决报错的话使用cnpm install重新安装一遍!九、安装axios(1):cnpm install axios(2):cnpm install --save axios vue-axios注意:不安装axios的话,不能使用post/get等提交方式,会报错!文字高亮及提示插件:在Vscode中安装Vetur,写组件时,只需
2022年05月27日
92 阅读
0 评论
0 点赞