路飞学城—Vue
路飞项目概括
1.vue框架
前台html+css+js框架,是不同于js与jq的数据驱动框架
指令 | 实例成员 | vue项目
2.drf框架
django的插件,完成前后台分离项目后台接口编写的框架
序列化组件 | 三大认证组件 | 分页,筛选,过滤,排序 | 请求,解析,响应
3.路飞项目
前台由vue完成,后台由drf完成的前后台分离项目
git | 短信认证 | celery异步任务 | 项目上线
Vue导读
vue框架
vue是前台框架:Augular、React、Vue
vue:结合其他框架优点、轻量级、中文API、数据驱动、双向绑定、MVVM设计模式、组件化开发、单页面应用
vue环境:本地导入与cdn导入
vue是js渐进式框架
根据开发需求,可以决定vue框架控制项目的具体方位:可以为一个标签,也可以为一个页面,甚至可以为整个项目
实例成员-挂载点
1.vue渐进式框架:控制页面及项目的范围
2.vue的环境导入:本地、cdn
3.vue框架的优点:轻量级、中文API、数据驱动、双向绑定、MVVM设计模式、组件化开发、单页面应用
4.vue如何与html页面的结构建立关联:挂载点
注意:
1.html与body不能作为挂载点
2.一个vue对象挂载点之后索引一个匹配结果,所以挂载点一般用id标识
<body> {{ }} <hr> <div class="main"> {{ }} </div> <hr> <div class="main"> {{ }} </div> <div id="wrap"> {{ }} <hr> <div class="main"> {{ }} </div> <hr> <div class="main"> {{ }} </div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '.main' // el表示挂载点 }) new Vue({ el: '#wrap' }) </script> <script> let b = 20; let dic = { a:10, b //b: b 的简写 }; console.log(dic) </script>
实例成员-数据
1.用实例成员data为vue环境提供数据,数据采用字典{}形式
2.在插值表达式{{ }}中,直接书写数据的key来访问数据
3.在外部通过接受实例的变量app,访问实例成员(实例成员都用$开头),间接访问到数据
app.$data.info
4.在外部也可以通过实例化变量app直接访问数据
app.info
5.在vue实例内部的方法methods中,使用变量,this.info(this其实就是等价于app)
<body> <div id = 'app'> <!-- {{}}是插值表达式,中间出现的info是vue变量 --> <p>{{ info }}</p> <p>{{ info }}</p> <p>{{ num }}</p> <p>{{ arr }}</p> <p>{{ dic }}</p> </div> </body> <script src="js/vue.js"></script> <script> let app = new Vue({ el:'#app', data: { info: 'message', num: 100, result: true, arr: [1,2,3,4,5], dic: { name:'ZZJ', hobby:'reading' } } }) </script> <script> console.log(app); console.log(app.$data.info); console.log(app.info); </script>
实例成员-过滤器
1.过滤器本身就是数据处理函数,可以将插值表达式中的数据作为参数进行处理,得到的函数返回值就是处理后的结果
2.过滤使用语法{{ ...变量 | 过滤器(...变量) }}
3.过滤器在实例中用filters成员提供
<body> <div id="app"> <!-- 插值表达式可以直接做简单运算 --> <p>{{ num + 3.5 }}</p> <p>{{ msg.split('')[4] }}</p> <p>{{ num | f1 }}</p> <p>{{ 10, 20, 30, 40 | f2 }}</p> <p>{{ 10,20 | f2(50, 80) }}</p> <p>{{ 120 | f2 }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data:{ num: 100, msg: 'message' }, filters: { f1:function (num) { return num*2 }, f2:function (a,b,c,d) { console.log(a,b,c,d); return a + b + c + d } } }) </script>
文本指令
1. 插值表达式 同 v-text指令,渲染普通文本
2. v-html指令可以渲染有html语法的文本,能够解析html语法
3.文本指令中可以渲染 变量 也可以渲染 常量
<body> <div id="app"> <p>{{ info }}</p> <!-- v-指令名='变量',变量是需要data提供数据值的 --> <p v-text="info"></p> <!-- v-指令名='常量',常量采用常量基本的语法,数字与布尔类型可以直接书写的直接书写,字符串等需要特使符号的需要添加符号--> <p v-text="123"></p> <p v-text="true"></p> <p v-text="'abc' + info"></p> <p v-text="[1,2,3]"></p> <!-- v-html可以解析html语法 --> <p v-html="`<b style='color:red'>嘿嘿嘿</b>`"></p> <p v-text="'<b>嘻嘻嘻</b>'"></p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data:{ info:'data提供的数据' } }) </script> <script> // js多行字符串 反引号 `` let s1 = `第一行 第二行 结束行`; console.log(s1); let name = 'ZZJ'; let hobby = 'Reading'; let s2 = ` name: ${name} age: ${hobby} `; console.log(s2); </script>
事件指令
1.语法:v-on:事件名=“函数名(参数)”
2.简写:@事件名=“函数名(参数)”
3.用methods实例成员提供 事件函数 的实现
4.事件参数:函数名 | 函数名() | 函数名(自定义参数) | 函数名($event,自定义参数)
<head> <meta charset="UTF-8"> <title>Title</title> <style> body { /*页面文本不允许选择*/ user-select : none; } .low-num { cursor: pointer; } .low-num:hover { color: red; } </style> </head> <body> <div id="app"> <p class="low-num" v-on:click="lowNum"> <span>点击减1</span> <span>{{ num }}</span> </p> <p v-on:dblclick="dblAction">双击</p> <!-- v:on:事件名="事件函数"可以简写为@事件名="事件函数" --> <p @mouseover="overAction()">悬浮</p> <p @mouseover="overAction(10)">悬浮1</p> <p @mouseover="overAction(10,20)">悬浮2</p> <p @mouseover="overAction(10,20,$event)">悬浮3</p> <!--事件传参: @事件='方法' 默认传入事件对象 $event @事件='方法()' 不传递任何参数 @事件='方法(参数...)' 只传递自定义参数 @事件='方法($event,参数...)' 自定义传参时传递事件对象 --> </div> </body> <script src="js/vue.js"></script> <script> let app = new Vue({ el:'#app', data:{ num:100, }, methods:{ lowNum:function () { this.num -= 1 }, dblAction(ev){ console.log(ev) }, overAction(a,b,c){ console.log(a,b,c) } } }) </script>
属性指令
1.语法:v-bind:属性名=“变量”
2.v-bind:属性名=“变量”简写:属性名="变量"
3.单值属性绑定::titile="变量" | :id="变量" | :自定义属性="变量"
4.style属性绑定::style="字典变量" | style="{css属性1:变量1,...,css属性n:变量n}"
5.class属性绑定::class="变量" | :class="[变量1,...,变量n]" | :class="{类名:布尔变量}"
<head> <meta charset="UTF-8"> <title>属性指令</title> <style> [index] { color: orange; } .ccc { background-color: yellowgreen; color: greenyellow; border-radius: 50%; } .ccc1 { background-color: yellowgreen; } .ccc2 { color: greenyellow; } .ccc3 { border-radius: 50%; } .ttt { background-color: gold; color: orange; } </style> </head> <body> <div id="app"> <!--1) 语法:v-bind:属性名="变量" --> <p id="p1" class="p1" style="" title="" index="">属性指令1</p> <p id="p2" v-bind:class="p1" style="" title="" index="">属性指令2</p> <p v-bind:index="p1">自定义属性也可以被vue绑定1</p> <!--2) v-bind:属性名="变量" 简写 :属性名="变量" --> <p :index="p1">自定义属性也可以被vue绑定2</p> <p :title="'文本提示'">悬浮文本提示</p> <!--3) style样式属性绑定 --> <p :style="myStyle">样式绑定1</p> <p :style="{backgroundColor: c1, color: c2, 'border-radius': '50%'}">样式绑定2</p> <!--4) class类属性绑定 --> <p :class="myc1">样式绑定3</p> <p :class="[myc2,myc3,myc4,'bbb']">样式绑定4</p> <!--xxx是类名,是否起作用有布尔类型变量yyy值决定 --> <p :class="{xxx:yyy}">样式绑定5</p> <!--案例:点击切换类名是否起作用--> <p @click="clickAction" :class="{ttt:yyy}">点击切换类</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { p1: 'q1', myStyle: { backgroundColor: 'pink', color: 'deeppink', 'border-radius': '50%' }, c1: 'cyan', c2: 'tan', myc1: 'ccc ddd eee', myc2: 'ccc1', myc3: 'ccc2', myc4: 'ccc3', yyy: true, // false }, methods: { clickAction() { this.yyy = !this.yyy; } } }) </script>
交互修改文本与样式
<head> <meta charset="UTF-8"> <title>Title</title> <style> .box { width: 200px; height: 200px; background-color: orange; } .center { text-align: center; line-height: 200px; } .rcenter { text-align: right; line-height: 200px; } .right { text-align: right; } .top { line-height: 21px; } .bottom { line-height: calc(400px - 21px); } </style> </head> <body> <div id="app"> <div class="box" :class="[c1,{right:r,top:t,bottom:b}]" @mouseover="a1" @mousedown="a2" @mouseup="a3" @mouseout="a4">{{ msg }}</div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: "#app", methods: { a1(){ this.msg = '被悬浮'; this.c1 = 'center'; this.r = 0; this.t = 0; this.b = 0; }, a2(){ this.msg = '被按下'; this.r = 0; this.t = 0; this.b = 0; }, a3(){ this.msg = '被抬起'; this.c1 = 'center'; this.r = 0; this.t = 0; this.b = 0; }, a4(){ this.msg = '被移开'; this.r = 0; this.t = 0; this.b = 0; } }, data: { msg: '', c1: '', r:0, t:0, b:0, } }) </script>
表单指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .p1 { width: 500px; height: 21px; background-color: deeppink; } </style> </head> <body> <div id="app"> <form action=""> <!-- 对表单标签value进行绑定操作变量,不能时时检测绑定的变量 --> <input type="text" class="inp1" :value="info"> <input type="text" class="inp2" :value="info"> <p class="p1">{{ info }}</p> <hr> <!-- 表单标签的值有v-model="变量"来绑定控制,操作的还是value,但是拥有时时变量值的检测 --> <input type="text" class="inp1" v-model="info"> <input type="text" class="inp2" v-model="info"> <p class="p1">{{ info }}</p> <!-- 单选框 --> 性别: 男 <input type="radio" name="sex" value="male" v-model="mysex"> 女 <input type="radio" name="sex" value="female" v-model="mysex"> 其他 <input type="radio" name="sex" value="others" v-model="mysex"> <p>{{ mysex }}</p> <!-- 复选框 --> 兴趣爱好: 男 <input type="checkbox" name="hobbies" value="male" v-model="myhobbies"> 女 <input type="checkbox" name="hobbies" value="female" v-model="myhobbies"> 其他 <input type="checkbox" name="hobbies" value="others" v-model="myhobbies"> <p>{{ myhobbies }}</p> <hr> <input type="submit"> </form> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data:{ info:'123', isAgree:0, mysex:'others', myhobbies:['male','female'] } }) </script> </html>
v-once指令
v-once:单独使用,限制的标签内容一旦赋值,便不可被动更改(如果是输入框,可以主动修改)
<body> <div id="app"> <!-- v-once单独使用,限制的标签内容一旦赋值,便不可更改 --> <input type="text" v-model="msg"> <input type="text" v-model="msg" v-once> <p>{{ msg }}</p> <p v-once>{{ msg }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { msg:'初始值' } }) </script>
v-cloak指令(了解即可)
v-cloak:防止页面闪烁
<style> [v-cloak] { display: none; } </style> <!-- 不处理的情况下,每次新价值该页面,都会先渲染{{}},当vue环境加载成功,{{}}有会被解析消失 --> <!-- 处理后,vue环境没加载好时,#app是被隐藏的,vue环境加载成功,会依次#app的v-cloak属性,就不会出现{{}}渲染闪烁问题 --> <div id="app" v-cloak> {{ }} {{ }} {{ }} </div> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', }) </script>
条件指令
1. 两种都可以控制的显隐,绑定的值是布尔类型值,当都隐藏标签时
v-if是不渲染标签
v-show以 display:none 方式渲染
<body> <div id="app"> <p v-if="isShow">if条件指令</p> <p v-show="isShow">show条件指令</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { isShow: false, } }) </script>
2.v-if = "变量"
v-else-if = "变量"
v-else
一组分支上,成立分支会屏蔽下方所有分支,else分支没有条件,在所有分支不成立后才显示
<head> <meta charset="UTF-8"> <title>Title</title> <style> .box { width: 400px; height: 400px; } .r { background-color: red; } .y { background-color: yellow; } .b { background-color: blue; } .active { background-color: deeppink; } </style> </head> <body> <div id="em"> <p> <button @click="changeBox('rBox')" :class="{active:showName=='rBox'}">红</button> <button @click="changeBox('yBox')" :class="{active:showName=='yBox'}">黄</button> <button @click="changeBox('bBox')" :class="{active:showName=='bBox'}">蓝</button> </p> <div class="box r" v-if="showName=='rBox'"></div> <div class="box y" v-else-if="showName=='yBox'"></div> <div class="box b" v-else></div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#em', data:{ showName:'yBox' }, methods:{ changeBox(name){ this.showName = name; } } }) </script>
原义指令
利用v-pre指令可以在vue控制范围内,形成局部vue不控制区域
{{ }} 和 v-if 都会原样输出,不会被解析
<div id="app"> <p>{{ msg }}</p> <p v-pre> {{ }} <span v-if="hehe"></span> </p> </div> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { msg: 'message' } }) </script>
循环指令
1. 遍历字符串:可以只逐一遍历字符,也可以连同遍历索引
2.遍历数组:可以只逐一遍历成员元素,也可以连同遍历索引
3.遍历对象:可以只逐一遍历成员元素,也可以连用遍历成员键(key),还可以遍历成员key索引
<div id="app"> <p>{{ str }}</p> <p>{{ str[2] }}</p> <div> <span v-for="ch in str">{{ ch }}</span> </div> <div> <!-- 针对循环遍历的标签,通过会提供key属性来优化渲染速度,但key的值必须唯一(key可以不用提供) --> <span v-for="(ch,i) in str" :key="ch + i">{{ i }}{{ ch }}</span> </div> <div> <p v-for="(ele,i) in arr">{{ i }}{{ ele }}</p> </div> <div> <p v-for="ele in dic">{{ ele }}</p> </div> <div> <p v-for="(ele,k) in dic">{{ k }}:{{ ele }}</p> </div> <div> <p v-for="(ele,k,i) in dic">{{ i }}{{ k }}:{{ ele }}</p> </div> </div> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data:{ str:'寄个烧鸡摸摸哒', arr:[1, 2, 3, 4, 5, 10], dic:{ name: 'Owen', age: 66, gender: '嘿嘿', } } }) </script>
1. 留言就是往留言数组中添加数据,删除留言就是从留言数组中移除数据
2. 前台数据库:localStorage 和 sessionStorage
localStorage永久保存数据
sessionStorage临时保存数据(当所属页面标签被关闭,数据被清空)
3. 前台localStorage 和 sessionStorage数据库存储的值是字符串类型,所以要存放arr、dic等复杂数据需要JSON参与
<head> <meta charset="UTF-8"> <title></title> <style> li:hover { color: red; cursor: pointer; } </style> </head> <body> <div id="app"> <p> <input type="text" v-model="userMsg"> <button type="button" @click="sendMsg">留言</button> </p> <ul> <li v-for="(msg,index) in msgs" @click="deleteMsg(index)"> {{ msg }} </li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { msgs:localStorage.msgs ? JSON.parse(localStorage.msgs): [] , // 所有留言 userMsg:'', // 用户留言 }, methods:{ sendMsg(){ let userMsg = this.userMsg; if (userMsg) { this.msgs.unshift(this.userMsg); // 渲染给页面 localStorage.msgs = JSON.stringify(this.msgs); // 渲染给数据库 this.userMsg = "" // 清空留言板 } }, deleteMsg(index){ this.msgs.splice(index,1) } } }) </script>
实例成员-插值表达式符号(了解)
<div id="app"> {{ msg }} {[ msg ]} </div> <script> new Vue({ el: '#app', data: { msg: '12345' }, // delimiters: ['{{', '}}'], delimiters: ['{[', ']}'], }) </script>
计算属性
1. computed是用来声明 方法属性 的
2.声明的方法属性不能在data中重复定义
3.方法属性必须在页面中渲染使用,才会对内部出现的所有变量进行监听
4.计算机属性的值来源于监听方法的返回值
<div id="app"> 姓:<input type="text" v-model="fName"> 名:<input type="text" v-model="lName"> 姓名:<b>{{ flName }}</b> </div> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data: { fName:'', lName:'', }, computed: { flName(){ // this.fName和this.lName有值发送改变,该方法都会被调用 // 变量flName的值是有函数的返回值决定 return this.fName + this.lName; } } }) </script>
属性监听
1. watch为data中已存在的属性设置监听事件
2.监听的属性值发生改变,就会触发监听事件
3.监听事件的方法返回值没有任何意义
<div id="app"> 姓名:<input type="text" v-model="fullName"> 姓:<b>{{ firstName }}</b> 名:<b>{{ lastName }}</b> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app', data: { fullName:'', firstName:'', lastName:'', }, watch: { // fullName值改变,就会调用绑定的事件方法 fullName(){ nameArr = this.fullName.split(''); this.firstName = nameArr[0]; this.lastName = nameArr[1]; } } }) </script>
组件
1.组件:一个包含html、css、js独立的集合体,这样的集合体可以完后才能页面结构的代码复用
2.分组分为根组件、全局组件与局部组件
根组件:所有被new Vue()产生的组件,在项目开发阶段,一个项目只会出现一个根组件
全局组件:不用注册,就可以成为任何一个组件的子组件
局部组件:必须注册,才可以成为注册该局部组件的子组件
3.每一个组件都有自身的html结构,css样式,js逻辑
每一个组件其实都有自己的template,就是用来标识自己html结构的
template模板中有且只有一个根标签
根组件一般不提供template,就由挂载点的真实DOM提供html结构
4.除跟组件的其他组件,数据要有局部作用域,保证组件复用时,各组件间数据的独立性
5.在多组件共处时,在哪个组件模板中出现的变量,有当前组件提供
局部组件
1.创建局部组件
2.在父组件中注册该局部组件
3.在父组件的template模板中渲染该局部组件
<head> <meta charset="UTF-8"> <title>Title</title> <style> .box { box-shadow: 0 3px 5px 0 deeppink; width: 240px; height: 300px; text-align: center; padding: 20px 0; float: left; margin: 8px; } .box img { width: 200px; } </style> </head> <body> <div id="app"> <local-tag></local-tag> <local-tag></local-tag> <local-tag></local-tag> </div> </body> <script src="js/vue.js"></script> <script> let localTag = { template:` <div class="box"> <img src="img/333.png" alt=""> <h3>杨铚狗</h3> <p>马叉虫♥马叉虫</p> </div> ` }; new Vue({ el:'#app', components:{ 'local-tag':localTag } }) </script>
全局组件
1.创建全局组件
2.在父组件的template模板中直接渲染该全局组件
<head> <meta charset="UTF-8"> <title>Title</title> <style> .box { box-shadow: 0 3px 5px 0 #666; width: 240px; height: 300px; text-align: center; padding: 20px 0; float: left; margin: 5px; user-select: none; } .box img { width: 200px; } </style> </head> <body> <div id="app"> <global-tag></global-tag> <global-tag></global-tag> <global-tag></global-tag> </div> </body> <script src="js/vue.js"></script> <script> Vue.component('global-tag',{ template:` <div class="box" @click="action"> <img src="img/333.png" alt=""> <h3>杨铚狗</h3> <p>马叉虫♥{{ num }}</p> </div> `, data(){ return { num:0 } }, methods:{ action(){ this.num ++; } } }); new Vue({ el:'#app', }) </script>
组件交互-父传子
数据交互 - 父传子 - 通过绑定属性的方式
1. 父组件提供数据
2. 在父组件模板中,为子组件标签设置自定义属性,绑定的值由父组件提供
3. 在子组件实例中,通过props实例成员获得自定义属性
<head> <meta charset="UTF-8"> <title>Title</title> <style> .info { text-align: center; width: 200px; padding: 3px; box-shadow: 0 3px 5px 0 pink; float: left; margin: 5px; } .info img { width: 200px; } </style> </head> <body> <div id="app"> <info v-for="info in infos" :key="info.image" :myinfo="info"></info> </div> <script src="js/vue.js"></script> <script> let infos = [ { image:'img/001.png', title:'小猫' }, { image:'img/002.png', title:'蛋糕' }, { image:'img/003.png', title:'蓝糕' }, { image:'img/004.png', title:'恶犬' }, ]; let info = { template : ` <div class="info"> <img :src="myinfo.image" alt=""> <p><b>{{ myinfo.title }}</b></p> </div> `, props: ['myinfo'] }; new Vue({ el:'#app', components: { info, }, data: { infos, } }) </script> </body>
组件交互-子传父
1.数据由子组件提供
2.子组件内部通过触发系统事件,发送一个自定义事件,将数据携带出来
3.父组件为子组件标签的自定义属性通过方法实现,就可以通过参数拿到子组件传递处理的参数
<head> <meta charset="UTF-8"> <title>Title</title> <style> .close:hover { cursor: pointer; color: red; } </style> </head> <body> <div id="app"> <p> <input type="text" v-model="userMsg"> <button @click="sendMsg">留言</button> </p> <ul> <msg-li @remove_msg="removeAction" v-for="(msg,i) in msgs" :msg="msg" :index="i" :key="msg"></msg-li> </ul> </div> </body> <script src="js/vue.js"></script> <script> let msgLi = { template:` <li> <span class="close" @click="deleteMsg(index)">x</span> <span>第{{ index + 1 }}条:</span> <span>{{ msg }}</span> </li> `, props:['msg','index'], methods: { deleteMsg(i){ this.$emit('remove_msg',i); } } }; new Vue({ el:'#app', data: { msgs:[], userMsg:'' }, methods: { sendMsg(){ if (this.userMsg){ this.msgs.push(this.userMsg); this.userMsg=""; } }, removeAction(i){ this.msgs.splice(i,1) } }, components: { msgLi } }) </script>