之前写CRM都是Django前后端一起写的,在大部分项目中实际上前后端是分离的,因此我们需要学习一个前端框架来进行前端页面的编写,这里选择了Vue进行学习,好了开始学习吧.
特点: 1.局部作用域 2.不会存在变量提升 3.变量不能重复声明
特点: 1.局部作用域 2.不会存在变量提升 3.不能重复声明,只声明常量 不可变的量
// 通过反引号 ${变量名}来插值 let name = 'liu'; let res = `我是${name}`; console.log(res); ---> 我是liu
// 箭头函数等同于add1 = function(x, y){return x+y;} let add1 = (x, y) => { return x+y; }; // 更简单的使用 let add2 = (x, y) => x+y; console.log(add1(3,2)); ---> 5 console.log(add2(3,2)); ---> 5
// 这是对象中使用箭头函数,此时的this指向的是person的父级对象(上下文,window) var person1 = { name: 'liu', age: '20', fav: () => { console.log(this); } }; person1.fav(); ---> Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …} // 为了解决箭头函数this指向的问题 推出来一种写法 对象的单体模式, 此时的this指向的是person对象 var person2 = { name: 'liu', age: '20', fav(){ console.log(this); } }; person2.fav(); ---> {name: "liu", age: "20", fav: ƒ}
// 基于原型的模式创建对象(prototype,继承当前父类) function Person1(name,age){ this.name = name; this.age = age; } Person1.prototype.showName = function(){ console.log(this.name); }; var p1 = new Person1('liu', 18); p1.showName(); class Person2{ // 构造器 当你创建实例的时候 constructor()方法会立刻调用 通常这个方法初始化对象的属性,类似py的__init__方法 constructor(name,age){ this.name = name; this.age = age; } showName(){ console.log(this.name); } } var p2 = new Person2('liu', 18); p2.showName();
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> // 在html中引入: <script src='./vue.js'></script>
// 模板语法, 可以插入任何你想插入的内容,除了if-else if-else用三元运算符代替 <div id="box"> <!--模板语法(内部不能写if else if-else用三元运算符代替)--> <!--去data中找到msg的值展示在页面--> <h3>{{ msg }}</h3> <!--直接运算得到结果展示在页面上--> <h3>{{ 1+2+3 }}</h3> <!--字符,对象都能直接被渲染到页面--> <h3>{{ {name: 'xiaohua'} }}</h3> <!--取出person对象的属性name值--> <h3>{{ person.name }}</h3> <!--三元运算符计算--> <h3>{{ 1>2?'对':'错' }}</h3> <!--翻转字符串,得到nohtyp evol,证明{{}}中可以使用js语法--> <h3>{{ str1.split('').reverse().join('') }}</h3> </div>
// 实例化Vue new Vue({ el: '#box', // 绑定id为box的标签,固定写法el data:{ msg: '测试', str1: 'love python', person:{ name: 'liu', age: 18 } } })
v-text相当于innerText
v-html相当于innerHTML
<!--直接将msg当成字符串读取展示--> <div v-text="msg"></div> <!--读取后解析成标签展示,这个比较常用--> <div v-html="msg"></div>
new Vue({ el: '#box', data(){ // data中是一个函数,函数返回一个对象,可以为空,但必须返回,data中的数据发生改变页面引用相关的值也会发生改变,因为data是observer,持续监听 return { msg: "<h4>你好</h4>" } } })
<div id="box"> <!--执行add方法并将值展示在页面--> {{ add(1, 2) }} <!--给button按钮绑定click事件,方法是changeShow--> <button v-on:click = 'changeShow'>点击显示隐藏</button> <!--isShow为true就显示,为false就隐藏--> <div class="t1" v-show="isShow"></div> <!--官网例子,如果随机数大于0.5就显示Now you see me, 否则就显示Now you don't--> <div v-if="Math.random() > 0.5"> Now you see me </div> <div v-else> Now you don't </div> </div>
// 数据驱动视图 new Vue({ el: '#box', data(){ return{ isShow: true } }, // 方法都在这里面定义 methods: { add(x, y){ return x+y }, changeShow(){ // 点击按钮就取反然后赋值,所以点击就是一直显示隐藏 this.isShow = !this.isShow } } })
v-if和v-show 等于 true都是表示显示,false表示隐藏,那区别是啥呢?
v-if vs v-show v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,
则使用 v-show 较好(也可以通过增加class或删除class实现);如果在运行时条件很少改变,则使用 v-if 较好。
上面是官网说法,实际上简单来讲就是v-show就是改变display属性,而v-if则是对dom的创建和删除.
v-bind可以绑定标签中任何属性 比如:img标签的src,a标签的href,id,class,name等 v-on 可以监听 js中所有事件 简写: v-bind:src 等价于 :src v-on:click 等价于 @click
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .t1{ width: 200px; height: 200px; background-color: #ff0000; } .active{ background-color: #0f0; } </style> </head> <body> <div id="box"> <!--第一种写法--> <!--<button v-on:mouseenter="changeGreen" v-on:mouseLeave="changeRed">改变颜色</button>--> <!--绑定src和alt属性,使用从服务器返回的动态数据--> <!--<img v-bind:src="imgSrc" v-bind:alt="imgAlt">--> <!--如果isActive为true就把active加到class里面,为false就不加--> <!--<div class="t1" v-bind:class="{active:isActive}"></div>--> <!--第二种简写,以后都用简写--> <button @mouseenter="changeGreen" @mouseLeave="changeRed">改变颜色</button> <!--绑定src和alt属性,使用从服务器返回的动态数据--> <img :src="imgSrc" :alt="imgAlt"> <!--如果isActive为true就把active加到class里面,为false就不加--> <div class="t1" :class="{active:isActive}"></div> </div> </body> <script src="vue.js"></script> <script> //数据驱动视图 设计模式 MVVM Model(数据) View(前端展示) ViewModel(类似v-bind方法) new Vue({ el: '#box', data(){ // img相关的动态数据 return { imgSrc: "timg.jpg", imgAlt: '图片', isActive: true, } }, methods: { // 鼠标进入离开的执行方法 changeGreen(){ this.isActive = false; }, changeRed(){ this.isActive = true; } } }) </script> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="box"> <!--先判断返回的状态是否正确,如果正确才显示整个ul列表--> <ul v-if="data.status == 'ok'"> <!--循环用户列表,index表示索引,从0开始,一定要绑定key,有id就需要用id绑定,没有则用index, 绑定key是为了避免修改数据后vue自动内部遍历,绑定之后修改了哪个数据就只修改哪一个,避免性能损耗,v-for的优先级最高--> <li v-for="(item, index) in data.user_list" :key="item.id"> <h3>{{ index }} -- {{ item.id }} -- {{ item.name }} -- {{ item.age }}</h3> </li> </ul> <!--for循环遍及对象, 注意顺序,值在第一个--> <div v-for="(value, name, index) in object"> {{ index }} -- {{ name }}: {{ value }} </div> </div> </body> <script src="vue.js"></script> <script> new Vue({ el:'#box', data(){ return { data: { status: 'ok', user_list: [ {id: 1, name: 'liu', age: '18'}, {id: 2, name: 'xiao', age: '28'}, {id: 3, name: 'bai', age: '38'}, ] }, object:{ name: 'liu', age: '18', } } } }) </script> </html>
1.轮播图实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="box" style="text-align: center;"> <div> <img :src="imageSrc[currentNum].image_url" alt=""> </div> <button @click="prevImage">上一张</button> <button @click="nextImage">下一张</button> </div> </body> <script src="vue.js"></script> <script> let vm = new Vue({ el: '#box', data(){ return { imageSrc:[ {id:1, image_url: 'images/1.jpg'}, {id:2, image_url: 'images/2.jpg'}, {id:3, image_url: 'images/3.jpg'}, ], currentNum: 0, } }, methods: { prevImage(){ this.currentNum--; if (this.currentNum < 0){ this.currentNum = this.imageSrc.length-1; } }, nextImage(){ this.currentNum++; if (this.currentNum >= this.imageSrc.length){ this.currentNum = 0; } } }, // 生命周期钩子,vue实例创建后执行 created(){ // 通过箭头函数将this指向了Vue对象,实现了每两秒自动轮播 setInterval(() => { this.currentNum++; if (this.currentNum >= this.imageSrc.length){ this.currentNum = 0; } },2000) } }) </script> </html>
2.音乐播放器实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>音乐播放器</title> <style> li.active{ color: #0079f4; } </style> </head> <body> <div id="box"> <!--src绑定当前的索引music_url,@onended播放完成 会自动调用endMusicHandler方法--> <audio :src="musicData[currentIndex].music_url" controls autoplay @onended="endMusicHandler"></audio>
<ul> <!--循环musicData,当前currentIndex和index相等时就播放该歌曲并高亮显示--> <li v-for="(item, index) in musicData" :key="item.id" :class="{active:index==currentIndex}" @click="musicHandler(index)"> <p>{{ item.name }}</p> </li> </ul> </div> </body> <script src="./js/jquery-3.3.1.min.js"></script> <script src="vue.js"></script> <script> var music_list = [ { id: 1, name: '拿走了什么', music_url: './mp3/happy.mp3' }, { id: 2, name: '逍遥叹', music_url: './mp3/h1.mp3' }, { id: 3, name: '情歌', music_url: './mp3/h2.mp3' } ]; let vm = new Vue({ el: '#box', data(){ return { musicData:[], currentIndex: 0 } }, methods:{ // 接收当前用户选择的index,并赋值给currentIndex musicHandler(index){ this.currentIndex = index; }, endMusicHandler(){ this.currentIndex++; // 如果当前用户选择的index>=musicData的长度就证明到最后了,因此又去到第一首 if (this.currentIndex >= this.musicData.length){ this.currentIndex = 0 } } }, created(){ this.musicData = music_list } }) </script> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="box"> <p>{{ msg }}</p> <button @click="changeHandler">点击修改</button> </div> </body> <script src="vue.js"></script> <script> new Vue({ el:'#box', data(){ return { msg: 'liu', age: 18 } }, methods:{ changeHandler(){ this.msg = 'haha'; } }, watch: { // watch侦听单个属性,如果想监听多个属性 声明多个属性的监听(例如msg, age) 'msg': function (values) { if (values == 'haha') { this.msg = "hhh"; } }, 'age':function () { } } }) </script> </html>
2.计算属性 computed, 可以同时监听多个属性(计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="box"> <!--直接调用计算属性myMsg--> <p>{{ myMsg }}</p> <button @click="changeHandler">点击修改</button> </div> </body> <script src="vue.js"></script> <script> new Vue({ el:'#box', data(){ return { name: 'liu', age: 18 } }, methods:{ changeHandler(){ this.name = 'haha'; this.age = 20; } }, computed: { // 计算属性默认只有getter方法 myMsg: function () { // 这里可以写很多业务逻辑,比如额外增加年龄 this.age += 2; return `我的名字是${this.name},年龄是${this.age}` } } }) </script> </html>