路费学城之 vue
路费学城之 vue
vue笔记
一、vue 框架内容大纲
"""
Vue框架:前台界面,页面逻辑
1)指令
2)实例成员
3)组件
4)项目开发
DRF框架:数据(接口)
1)基础的模块:请求、响应、解析、渲染
2)序列化、三大认证
3)过滤、搜索、排序、分页
4)异常、第三方jwt、restful接口规范
Luffy项目:前后台分离项目
1)项目的登录认证、课程商机销售、项目完成
2)短信、支付宝、服务器、上线、redis、celery、git
"""
vue 框架
"""
1)定义:javascript渐进式框架
渐进式:可以控制一个页面的一个标签,也可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前台项目
2)优势:
有指令(分支结构,循环结构...),复用页面结构等
有实例成员(过滤器,监听),可以对渲染的数据做二次格式化
有组件(模块的复用或组合),快速搭建页面
虚拟DOM
数据的双向绑定
单页面应用
数据驱动
3)为什么学习vue:
前台框架:Angular(庞大)、React(精通移动端)、Vue(吸取前两者优势,轻量级)
Vue一手文档是中文
实现前后台分离开发,节约开发成本
4)如何使用Vue
简单使用
"""
Vue环境简单搭建:通过script标签导入vue文件即可
"""
1)cdn
<script src="https://cn.vuejs.org/js/vue.js"></script>
2)本地导入
<script src="js/vue.js"></script>
"""
挂载点el
"""
/** el: 挂载点
* 1)一个挂载点只能控制一个页面结构(优先匹配到的结构)
* 2)挂载点挂载的页面标签严格建议用id属性进行匹配(一般习惯用app)
* 3)html标签与body标签不能作为挂载点(html和body标签不可以被替换,组件中详细介绍)
* 4)是否接受vue对象,是外界是否要只有vue对象的内容决定的
*/
"""
<div id="app">
<div class="d1">
{{ num }}
</div>
<div class="d1">
{{ num }}
</div>
</div>
<div id="main">
{{ n }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
num: 100
}
});
console.log(app.$data.num, app.num);
new Vue({
el: '#main',
data: {
n: app.num
}
});
</script>
插值表达式
"""
/** 插值表达式
* 1)空插值表达式:{{ }}
* 2)中渲染的变量在data中可以初始化
* 3)插值表达式可以进行简单运算与简单逻辑
* 4)插值表达式符合冲突解决,用delimiters自定义(了解)
*/
"""
<div id="app">
<p>{{ info }}</p>
<p>{{ msg }}</p>
<p>{{ }}</p>
<p>{{num}}</p>
<p>{{num + 10 * 2}}</p>
<p>{{ msg.length + num }}</p>
<p>{{ msg[4] }}</p>
<p>{{ msg.split('')[4] }}</p>
<p>[{ num }]</p>
</div>
<script>
new Vue({
el: '#app',
data: {
info: '信息',
msg: 'message',
num: 10,
},
// 控制vue插值表达式符合
delimiters: ['[{', '}]'],
})
</script>
过滤器
"""
/** 过滤器
* 1)用实例成员filters来定义过滤器
* 2)在页面结构中,用 | 来标识使用过滤器
* 3)过滤方法的返回值就是过滤器过滤后的结果
* 4)过滤器可以对1~n个变量进行过滤,同时还可以传入辅助的变量,
* 过滤器方法接受参数是安装传入的位置先后
*/
"""
<body>
<div id="app">
<!-- 简单使用:过滤的对象会作为参数传给过滤器 -->
<p>{{ num | add(20) }}</p>
<!-- 串联使用:将第一个过滤器结果作为参数给第二个过滤器 -->
<p>{{ num | add(100) | jump(2) }}</p>
<!-- 究极使用 -->
<p>{{ n1, n2 | fn(99, 77) }}</p>
<!-- 你品,你细品 -->
<p>{{ n1, n2 | fn(99, 77), n1, n2 | fn(100) }}</p>
</div>
</body>
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
n1: 66,
n2: 88
},
filters: {
add: function (a, b) {
console.log(a, b);
return a + b;
},
jump: function (a, b) {
return a * b
},
fn: function (a, b, c, d) {
console.log(a, b, c, d);
return a + b + c + d;
}
}
})
</script>
以上所学实例成员(实例属性,自我完成小结)
{
el:
data:
delimiters:
filters:
}
文本指令
"""
/**
* 1) v-* 是vue指令,会被vue解析,v-text="num"中的num是变量(指令是有限的,不可以自定义)
* 2)v-text是原样输出渲染内容,渲染控制的标签自身内容会被替换掉(<p v-text="num">123</p>会被num替换)
* 3)v-html可以解析渲染html语法的内容
*/
4)补充
<!-- js基本数据类型:字符串、数字、布尔、undefined -->
<p v-text="'abc' + num + 10"></p>
<p>{{ 'abc' + num + 10 }}</p>
"""
<body>
<div id="app">
<p>{{ num | add(300) }}</p>
<p v-text="num"></p>
<p v-text="num">123</p>
<p v-text="info"></p>
<p v-html="info"></p>
</div>
</body>
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 100,
info: '<i style="color: red">info内容</i>'
},
filters: {
add: function (a, b) {
return a + b;
}
}
})
</script>
事件指令
"""
/**
* 一、数据驱动
* 1)操作是一个功能,使用需要一个方法来控制 2)方法名是变量,所以控制变量就可以控制该方法
*
*
* 二、事件指令
* 1)在实例成员methods中声明事件方法
* 2)标签通过事件指令绑定声明的方法: v-on:事件名="事件方法名"
* eg: <button v-on:click="btnClick">按钮</button>
* 3)标签通过事件指令绑定声明的方法,且自定义传参: v-on:事件名="事件方法名()"
* eg: <button v-on:click="btnClick()">按钮</button> 不传任何参数
* eg: <button v-on:click="btnClick($event)">按钮</button> 传入事件对象,同不写()
* eg: <button v-on:click="btnClick(10)">按钮</button> 只传入自定义参数,当然也可以传入事件对象
*/
"""
<body>
<div id="app">
<button v-on:click="btnClick">{{ btn1 }}</button>
<button v-on:click="btnClick">{{ btn2 }}</button>
<hr>
<!-- 直接绑定事件名:系统会在触发事件时(点击时)调用事件方法(fn1),传给事件方法一个参数(事件对象) -->
<button v-on:click="fn1">按钮3</button>
<!-- 绑定的事件名后跟着(),不是主动调用事件方法,而是表示在触发事件调用时,传入的参数全由用户自己决定 -->
<button v-on:click="fn2($event, 10, 20)">按钮4</button>
<hr>
<button v-on:click="fn(btn1)">{{ btn1 }}</button>
<button v-on:click="fn(btn2)">{{ btn2 }}</button>
</div>
</body>
<script src="js/vue.js"></script>
<script>
// 对比DOM驱动:1)js选择器获取目标标签 2)为目标标签绑定事件 3)在事件中完成相应逻辑
// var btn = document.getElementsByTagName('button')[0];
// btn.onclick = function () {
// console.log(111111111111);
// };
new Vue({
el: '#app',
data: {
btn1: '按钮1',
btn2: '按钮2',
},
methods: {
btnClick () {
console.log(666)
},
fn1 (ev) {
console.log(ev.clientX, ev.clientY);
},
fn2(ev, n1, n2) {
console.log(ev, n1, n2);
console.log(ev.clientX, ev.clientY);
},
fn (msg) {
console.log(msg);
}
}
})
</script>
总结
"""
1、路飞项目所有知识点概况(了解)
2、Vue框架的介绍
what:渐进式 javascript 框架
where:前后台分离项目的前台开发(pc、移动端)
why:有其他框架的优点、轻量、中文API(低学习成本)
how:在页面中导入vue环境,用变量控制挂载点,各种指令与实例成员配合
3、基础实例成员
1)挂载点el:id选择器唯一绑定
2)插值表达式:{{ 内部可以写基本类型与变量,还可以完成简单运算与逻辑 }}
3、标识符:delimiters修改插值表达式符号(了解)
4、过滤器:filters自定义过滤器,可以串联使用,可以一次性过滤多个变量
5、方法:methods自定义vue控制的方法,给事件指令绑定的
4、基础指令
1)v-text:基本同{{}}
2)v-html:可以解析html语法的内容
3)v-on:
v-on:事件="方法" => 系统传参,只默认传$event
v-on:事件="方法($event, ...)" => 完全自定义传参,可以手动传入$event
5、js对象补充:
1)对象就可以作为字典,属性名都是字符串,可以省略引号
2)属性值时变量同属性名,可以简写
3){}中的属性值为函数,称之为方法,也可以简写
4)定义的函数,函数名大写,且函数内部有this,代表类
5)可以通过 类.prototype.类属性 实现所以对象共享
"""
二、内容大纲
"""
1)指令
属性指令:v-bind
表达指令:v-model
条件指令:v-show v-if
循环指令:v-for
斗篷指令:v-cloak
2)实例成员
计算:computed
监听:watch
3)vue项目环境
"""
斗篷指令(了解)
"""
v-cloak:避免屏幕闪烁
1)属性选择器,会将v-cloak属性所在的标签隐藏
2)当vue环境加载后,会将v-cloak属性解析移除,所以内容{{ num }}就会显示出来
3)而现在vue已经准备完毕,所以用户会直接看到数值10,而不会看到 页面从{{ num }}闪烁成数值10 """
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app" v-cloak>
<p>{{ num }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
num: 10
},
})
</script>
属性指令
"""
/** 属性指令
* 1)语法:v-bind:属性名="变量"
* 2)针对不同属性,使用方式稍微有一丢丢区别
* i)自定义属性以及title这些,直接赋值的,使用方式如下(t是变量,'o'是常量)
* <p v-bind:title="t" v-bind:owen="'o'">段落</p>
* ii)class属性(重点):
* 绑定的变量:值可以为一个类名 "p1",也可以为多个类名 "p1 p2"
* 绑定的数组:数组的每一个成员都是一个变量
* 绑定的字典:key就是类名,value是绝对该类名是否起作用
* iii)style属性(了解):
* 绑定的变量:值是一个字典
*/
"""
<p v-bind:title="t" v-bind:owen="'o'">段落</p>
<script>
new Vue({
el: '#app',
data: {
t: '悬浮提示',
},
})
</script>
<!--
a是变量,值就是类名
b就是类名,不是变量
c是变量,值为布尔,决定b类是否起作用
d是变量,值可以为一个类名 'p1' 也可以为多个类名 "p1 p2 ..."
calss="p1 b p2 p3"
-->
<p v-bind:class="[a, {b: c}]" v-bind:class="d"></p>
<script>
let app = new Vue({
el: '#app',
data: {
a: 'p1',
c: true,
d: 'p2 p3',
},
})
</script>
<p v-bind:style="myStyle"></p>
<script>
let app = new Vue({
el: '#app',
data: {
myStyle: {
width: '50px',
height: '50px',
backgroundColor: 'pink',
borderRadius: '50%'
}
},
})
</script>
案例
<button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1</button>
<button v-bind:class="{live: isLive == 2}" v-on:click="changeLive(2)">2</button>
<button v-bind:class="{live: isLive == 3}" v-on:click="changeLive(3)">3</button>
<script>
let app = new Vue({
el: '#app',
data: {
isLive: 1,
},
methods: {
changeLive (index) {
// this就代表当前vue对象,和app变量等价
// app.isLive = index;
this.isLive = index;
}
}
})
</script>
重点:事件指令与属性指令都可以简写
<!--
1)v-bind: 可以简写为 :
2)v-on: 可以简写为 @
-->
<button v-bind:class="{live: isLive == 1}" v-on:click="changeLive(1)">1</button>
<button :class="{live: isLive == 2}" @click="changeLive(2)">2</button>
<button :class="{live: isLive == 3}" @click="changeLive(3)">3</button>
事件补充
<style>
body {
/* 不允许文本选中 */
user-select: none;
}
.d1:hover {
color: orange;
/* 鼠标样式 */
cursor: pointer;
}
/* 只有按下采用样式,抬起就没了 */
.d1:active {
color: red;
}
/* div标签压根不支持 :visited 伪类 */
.d1:visited {
color: pink;
}
.d2.c1 {
color: orange;
}
.d2.c2 {
color: red;
}
.d2.c3 {
color: pink;
}
</style>
<div id="app">
<div class="d1">伪类操作</div>
<br><br><br>
<!--
click: 单击
dblclick:双击
mouseover:悬浮
mouseout:离开
mousedown:按下
mouseup:抬起
-->
<div :class="['d2', c]" @click="hFn('c1')" @mouseover="hFn('c2')" @mousedown="hFn('c3')">事件处理</div>
</div>
<script>
new Vue({
el: '#app',
data: {
c: '',
},
methods: {
hFn (c) {
this.c = c
}
}
})
</script>
表单指令
"""
1)语法:v-model="变量"
2)v-model绑定的变量控制的其实就是value属性值
3)v-model要比v-bind:value要对一个监听机制
4)数据的双向绑定:
v-model可以将绑定的变量值映射给表单元素的value
v-model还可以将表单元素的新value映射给报道的变量
"""
<!-- 两个输入框内容会同时变化 -->
<input name="n1" type="text" v-model="v1">
<input name="n2" type="text" v-model="v1">
<script>
new Vue({
el: '#app',
data: {
v1: ''
}
})
</script>
条件指令
"""
/**
* 1)语法:v-show="变量" | v-if="变量"
* 2)两者的区别:
* v-show在隐藏标签时,采用display:none渲染标签,标签通过css隐藏
* v-if在隐藏标签时,不会渲染在页面上
*
* 3)v-if有家族:v-if | v-else-if | v-else
* v-if是必须的,必须设置条件
* v-else-if可以为0~n个,必须设置条件
* v-else可以为0~1个
* 上方分支成立会屏蔽下方所有分支,从上至下依次类推
*/
"""
<div id="app">
<div>
<p v-show="isShow">show控制显隐</p>
<p v-if="isShow">if控制显隐</p>
</div>
<div>
<p v-if="0">你是第1个p</p>
<p v-else-if="0">你是第2个p</p>
<p v-else>你是第3个p</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
isShow: false,
}
})
</script>
案例
<style>
body {
margin: 0
}
button {
width: 60px;
line-height: 40px;
float: right;
}
.bGroup:after {
display: block;
content: '';
clear: both;
}
.box {
/* vw: view width vh: view height*/
width: 100vw;
height: 200px;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
button.active {
background-color: cyan;
}
</style>
<div id="app">
<div class="bGroup">
<button :class="{active: isShow === 'red'}" @click="isShow = 'red'">红</button>
<button :class="{active: isShow === 'green'}" @click="isShow = 'green'">绿</button>
<button :class="{active: isShow === 'blue'}" @click="isShow = 'blue'">蓝</button>
</div>
<div>
<div v-if="isShow === 'red'" class="box red"></div>
<div v-else-if="isShow === 'green'" class="box green"></div>
<div v-else class="box blue"></div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
isShow: 'red'
}
})
</script>
循环指令
"""
/**
* 1)语法:v-for="ele in obj" obj是被遍历的对象,ele是遍历得到的每一次结果
* 2)遍历可迭代对象的首要结果,都是可迭代对象容器中的值,其次还可以遍历得到索引及键等数据
* 字符串:v-for="v in str" | v-for="(v, i) in str"
* 数组:v-for="v in arr" | v-for="(v, i) in arr"
* 对象:v-for="v in obj" | v-for="(v, k) in obj" | v-for="(v, k, i) in obj"
* 注:v-for遍历要依赖于一个所属标签,该标签及内部所有内容会被遍历复用
*/
"""
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>循环指令</title>
</head>
<body>
<div id="app">
<!-- 遍历数字
5
【1】【2】【3】【4】【5】
-->
<p>{{ d1 }}</p>
<i v-for="e in d1">【{{ e }}】</i>
<hr>
<!-- 遍历字符串
abc
【a】【b】【c】
【0a】【1b】【2c】
-->
<p>{{ d2 }}</p>
<i v-for="e in d2">【{{ e }}】</i>
<i v-for="(e, i) in d2">【{{ i }}{{ e }}】</i>
<hr>
<!-- 遍历数组
[ 1, 3, 5 ]
【1】【3】【5】
【01】【13】【25】
-->
<p>{{ d3 }}</p>
<i v-for="e in d3">【{{ e }}】</i>
<i v-for="(e, i) in d3">【{{ i }}{{ e }}】</i>
<hr>
<!-- 遍历对象
{ "name": "Bob", "age": 17.5, "gender": "男" }
【Bob】【17.5】【男】
【name-Bob】【age-17.5】【gender-男】
【name-Bob-0】【age-17.5-1】【gender-男-2】
-->
<p>{{ d4 }}</p>
<i v-for="e in d4">【{{ e }}】</i>
<i v-for="(e, k) in d4">【{{ k }}-{{ e }}】</i>
<i v-for="(e, k, i) in d4">【{{ k }}-{{ e }}-{{ i }}】</i>
<hr>
</div>
</body>
<script>
new Vue({
el: '#app',
data: {
d1: 5,
d2: 'abc',
d3: [1, 3, 5],
d4: {
name: "Bob",
age: 17.5,
gender: "男"
}
}
})
</script>
商品循环案例
<style>
.box {
width: 280px;
border: 1px solid #eee;
border-radius: 5px;
overflow: hidden; /* 隐藏超出父级显示范围外的内容 */
text-align: center; /* 文本相关的属性大多默认值是inherit */
float: left;
margin: 10px;
}
.box img {
width: 100%;
}
</style>
<div id="app">
<div class="box" v-for="obj in goods">
<img :src="obj.img" alt="">
<p>{{ obj.title }}</p>
</div>
</div>
<script>
let goods = [
{
"img": "https://***1.jpg",
"title": "纯种拆家专家1"
},
{
"img": "https://***2.jpg",
"title": "纯种拆家专家2"
},
];
new Vue({
el: '#app',
data: {
goods,
}
})
</script>
面试题:todolist
js的Array操作
"""
尾增:arr.push(ele)
首增:arr.unshift(ele)
尾删:arr.pop()
首删:arr.shift()
增删改插:arr.splice(begin_index, count, args)
"""
前台数据库
"""
// 存
// 持久化化存储,永远保存
localStorage.name = "Bob";
// 持久化化存储,生命周期同所属标签(页面),页面关闭,重新打开就会丢失
sessionStorage.name = "Tom";
// 取
console.log(localStorage.name);
console.log(sessionStorage.name);
// 清空
localStorage.clear();
sessionStorage.clear();
// 短板:只能存储字符串,所有对象和数组需要转换为json类型字符串,再进行存储
let a = [1, 2, 3];
localStorage.arr = JSON.stringify(a);
let b = JSON.parse(localStorage.arr);
console.log(b);
"""
案例:留言板
<style>
li:hover {
color: red;
cursor: pointer;
}
</style>
<div id="app">
<form>
<input type="text" v-model="info">
<button type="button" @click="sendInfo">留言</button>
</form>
<ul>
<li v-for="(info, index) in info_arr" @click="deleteInfo(index)">{{ info }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
info: '',
// 三目运算符: 条件 ? 结果1 : 结果2
info_arr: localStorage.info_arr ? JSON.parse(localStorage.info_arr) : [],
},
methods: {
sendInfo () {
// 完成留言:将info添加到info_arr
// 增 push unshift | 删 pop shift
if (this.info) {
// 留言
this.info_arr.push(this.info);
// 清空输入框
this.info = '';
// 前台数据持久化(缓存)
localStorage.info_arr = JSON.stringify(this.info_arr);
}
},
deleteInfo(index) {
// 删
this.info_arr.splice(index, 1);
// 同步给数据库
localStorage.info_arr = JSON.stringify(this.info_arr);
}
}
})
</script>
小结
"""
1、v-cloak斗篷指令
2、属性指令
v-bind:title="变量"
:class="变量" | :class="[变量1, ..., 变量n]" | :class="{类名: 布尔变量}"
:style="字典变量"
3、事件:@click @dblclick @mouseover|out|down|up
鼠标单击、双击、悬浮、移开、按下、抬起
4、表单指令:
v-model绑定变量控制value属性,可以实现双向绑定
5、条件指令:
v-show | v-if
v-if | v-else-if | v-else
6、循环指令:
字符串:v-for="v in str" | v-for="(v, i) in str"
数组:v-for="v in arr" | v-for="(v, i) in arr"
对象:v-for="v in obj" | v-for="(v, k) in obj" | v-for="(v, k, i) in obj"
7、Array操作
arr.push(ele) arr.unshift(ele)
arr.pop() arr.shift()
arr.splice(begin_index, count, args)
8、前台数据库
localStorage | sessionStorage
1)操作就类似于obj,直接 .key 语法访问 value
2)localStorage永久存储
3)sessionStorage生命周期同所属页面标签
"""
三、内容大纲
"""
1)computed
2)watch
3)项目环境
4)项目开发:请求生命周期、组件、组件的生命周期、路由...
"""
字符串补充
"""
1)双引号:
"前缀" + 变量 + "后缀"
2)单引号:
'前缀' + 变量 + '后缀'
3)反引号:
`前缀${变量}后缀`
注:在反引号中可以用 ${} 来包裹变量,实现字符串拼接
"""
实例成员:计算属性
"""
/** 计算属性:
* 1)其实就是vue中的方法属性,方法名可以作为属性来使用,属性值为方法的返回值
* 2)在computed中声明的方法属性,不能在data中重复声明,比data中声明的属性要多出写逻辑的地方
* 3)方法属性,自带监听机制,在方法属性中出现的变量,都会被监听,一旦有任何被监听的变量值发生更新,
* 方法属性都会被调用更新方法属性的值
* 4)方法属性一定要在页面中渲染一次,方法属性采用意义,多次渲染,方法属性只会被调用一次
* 案例:计算器
* 方法属性的应用场景:一个变量依赖于多个变量,且需要进行一定的逻辑运算
*/
"""
<div id="app">
<!-- type="number"表示只能写数字 -->
<input type="number" v-model="num1" max="100" min="0">
+
<input type="number" v-model="num2" max="100" min="0">
=
<button>{{ sum }}</button>
</div>
<script>
new Vue({
el: '#app',
data: {
// sum: '', // 重复声明
num1: '',
num2: '',
},
computed: {
sum () {
// num1和num2都在该方法属性中,所以有一个更新值,该方法都会被调用
if (this.num1 && this.num2) {
return +this.num1 + +this.num2; // +this.num1是将字符串快速转换澄数字
}
return '结果';
}
}
})
</script>
监听属性
"""
/**
* 1)watch中不定义属性,只是监听属性,所以方法的返回值没有任何意义,只是监听变量值是否发生更新
* 2)watch中的方法名,就是被监听的属性(方法名同被监听属性名)
* 3)被监听的变量值一旦发生更新,监听方法就会被调用
* 应用场景:
* i)k线图:股票数据变化,页面的k线图重新渲染(需要逻辑将数据转换为图形)
* ii)拆分姓名:录入姓名,拆分为姓和名(需要逻辑将一个数据拆分为多个数据)
*/
"""
<div id="app">
姓名:<input type="text" v-model="full_name">
<hr>
姓:<button>{{ first_name }}</button>
名:<button>{{ last_name }}</button>
</div>
<script>
new Vue({
el: '#app',
data: {
full_name: '',
first_name: '未知',
last_name: '未知'
},
watch: {
full_name () {
if (this.full_name) {
// 只是实现简易的拆分逻辑
this.first_name = this.full_name.split('')[0];
this.last_name = this.full_name.split('')[1];
} else {
this.first_name = '未知';
this.last_name = '未知';
}
}
}
})
</script>
vue的项目开发
环境:安装vue的脚手架cli环境
"""
node ~~ python
npm ~~ pip
python:c语言编写,解释执行python语言的
node:c++语言编写,解释执行JavaScript语言的
npm类似于pip,是为node环境安装额外功能的
"""
"""
1)官网下载并安装node,附带npm
https://nodejs.org/zh-cn/
2)换源:将npm欢迎为cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
3)安装vue脚手架
cnpm install -g @vue/cli
注:如果第二三步异常,基本都是由网络导致的,可以重新执行第二三步,如果一直有问题,可以清理缓存后重复
npm cache clean --force
"""
项目创建:在终端中创建
各插件作用
Babel:将ES6语法解析为ES5语法给浏览器
Router:前台路由
Vuex:前台仓库,相当于单例,完成个组件间传参的
项目移植:将公司代码在自己电脑上跑起来
"""
1)拷贝出环境 node_modules 意外的文件与文件夹到目标文件夹
2)终端进入目标文件夹所在位置
3)执行:npm install 重新构建依赖(npm可以用cnpm替换)
"""
pycharm配置并启动vue项目
1) 用pycharm打开vue项目
2) 添加配置npm启动
vue项目目录结构分析
├── v-proj
| ├── node_modules // 当前项目所有依赖,一般不可以移植给其他电脑环境
| ├── public
| | ├── favicon.ico // 标签图标
| | └── index.html // 当前项目唯一的页面
| ├── src
| | ├── assets // 静态资源img、css、js
| | ├── components // 小组件
| | ├── views // 页面组件
| | ├── App.vue // 根组件
| | ├── main.js // 全局脚本文件(项目的入口)
| | ├── router
| | | └── index.js// 路由脚本文件(配置路由 url链接 与 页面组件的映射关系)
| | └── store
| | | └── index.js// 仓库脚本文件(vuex插件的配置文件,数据仓库)
| ├── README.md
└ └── package.json等配置文件
vue组件(.vue文件)
"""
注:pycharm安装vue.js插件,就可以高亮显示vue文件了
1)一个.vue文件就是一个组件
2)组件都是由三部分组成:html结构、js逻辑、css样式
html结构都是在template标签中,页面结构有且只有一个根标签(template一级结构下)
js逻辑都是在script标签中,必须设置导出,export default {...}
css样式都是在style标签中,必须设置scoped属性,是样式组件化
"""
<template>
<div class="first-cp">
<h1>第一个组件</h1>
</div>
</template>
<script>
// .vue文件类似于模块,可以直接相互导入,所以在组件内部要设置导出
export default {
}
</script>
<style scoped>
/* scoped可以使样式组件化,只在自己内部起作用 */
</style>
全局脚本文件main.js(项目入口)
"""
1)main.js是项目的入口文件
2)new Vue()就是创建根组件,用render读取一个.vue文件,$mount渲染替换index.html中的占位
3)项目所依赖的环境,比如:vue环境、路由环境、仓库环境、第三方环境、自定义环境都是在main.js中完成
"""
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
改写
import Vue from 'vue' // 加载vue环境
import App from './App.vue' // 加载根组件
import router from './router' // 加载路由环境
import store from './store' // 加载数据仓库环境
Vue.config.productionTip = false; // tip小提示
import FirstCP from './views/FirstCP'
new Vue({
el: '#app',
router: router,
store: store,
render: function (readVueFn) {
return readVueFn(FirstCP); // 读取FirstCP.vue替换index.html中的占位
}
});
路由与根组件(重点)
路由核心配置:router/index.js
// import 别名 from '文件'
import Home from '../views/Home'
import About from '../views/About'
import First from '../views/FirstCP'
// 路由配置
// 1)当用户在浏览器中访问的路由是 / ,router插件就会加载 Home.vue文件,同理 /about 就是 About.vue文件
// 2)将加载的 Home.vue文件 或者 About.vue文件,去替换App.vue文件中的 <router-view />占位符
// 3)用redirect配置来实现路由的重定向
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/home',
redirect: '/', // 路由的重定向
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/first',
name: 'First',
component: First
}
];
根组件占位渲染页面组件
<!--
1)App.vue是项目的根组件,是唯一由main.js加载渲染的组件,就是替换index.html页面中的<div id="app"></div>的占位标签
2)实际开发中App.vue文件中,只需要书写下方五行代码即可(可以额外增加其他代码)
3)router-view是一个占位标签,由router插件控制,可以在router的配置文件中进行配置
4)router-view就是根据router在index.js中配置的路由关系被 指定路径 匹配 指定页面组件 渲染
router-view或被不同的页面组件替换,就形成了页面跳转
-->
<template>
<div id="app">
<!-- 前台路由占位标签,末尾的/代表单标签的结束 -->
<router-view />
</div>
</template>
页面组件渲染小组件(重点)
页面组件作为父组件:views/*.vue
<template>
<div class="home">
<!-- vue项目下的html是支持大小写,且区分大小写 -->
<Nav />
</div>
</template>
<script>
// 父组件加载子组件:父组件通常是页面组件,是被一个个小组件这些子组件组装成的页面
// 1)导入语法要在 export default{} 之上完成
// 2)@符合标识 项目src文件夹 绝对路径
// 3)要在export default{} 的括号中用 components 注册
// 4)在该组件的模板中就可以渲染子组件了(html代码中是区别大小写的)
// 5)步骤:i)导入子组件 ii)注册子组件 iii)使用子组件
import Nav from '@/components/Nav'
export default {
components: {
Nav,
}
}
</script>
<style scoped>
.home {
width: 100vw;
height: 100vh;
background-color: orange;
}
</style>
导航栏小组件(封装路由跳转):components/*.vue
<template>
<div class="nav">
<img src="" />
<ul>
<li>
<!-- router控制的路由,不是用a标签完成跳转:
1)a标签会刷新页面,错误的
2)router-link标签也能完成跳转,且不会刷新页面,就是router提供的a标签(最终会被解析为a标签,还是用a来控制样式)
3)router-link标签的to属性控制跳转路径,由两种方式
i) to="路径字符串"
ii :to="{name: '路由名'}"
-->
<a href="/">主页</a>
</li>
<li>
<router-link to="/about">关于页</router-link>
</li>
<li>
<!-- to="字符串",v-bind:to="变量",可以简写为 :to="变量" -->
<router-link :to="{name: 'First'}">第一页</router-link>
</li>
</ul>
</div>
</template>
<style scoped>
.nav {
width: 100%;
height: 80px;
background: rgba(0, 0, 0, 0.3);
}
img {
width: 200px;
height: 80px;
background: tan;
float: left;
}
ul {
float: left;
list-style: none;
margin: 0;
padding: 0;
height: 80px;
background: pink;
}
ul li {
float: left;
height: 80px;
padding: 30px 20px 0;
}
a {
color: black;
}
</style>
总结
"""
1)计算属性:computed
定义方法属性,返回值为属性值,方法内的变量都会被监听
案例:计算器
2)监听属性:watch
监听与方法名同名的属性,被监听的数据更新调用方法
案例:拆分姓名,k线图
3)vue项目环境:
node -> npm -> cnmp -> vue/cli
4)新建vue项目:在当前终端所在目录下
vue create 项目
5)pycharm配置项目启动
在pycharm中设置npm启动
6)项目目录结构
7)组件:vue文件
8)入口文件:main.js
9)根组件、页面组件、小组件 与 路由关系(router-view、router-link)
"""
四、内容大纲
"""
1)路由:逻辑跳转、路由传参
2)项目组件的数据局部化处理:data: {} => data: function(){ return {} } => data(){ return{} }
3)组件的声明周期
4)组件间通信
5)各种第三方插件:vuex、axios、element-ui、(jq+bs)
"""
项目初始化
"""
1)根组件:App.vue
<template>
<div id="app">
<router-view />
</div>
</template>
2)路由配置:router/index.js
const routes = [
{
path: '/',
name: 'Home',
component: Home
}
];
3)组件:views和components文件夹
i)删除除Home.vue以为的所有组件
ii)初始化Home.vue
<template>
<div class="home">
</div>
</template>
4)分类管理资源:assets文件夹
建立img、css、js子文件夹,删除原来的资源
5)如果要修改页面标签图标
替换public文件夹下的favicon.ico图片文件
"""
组件数据局部化处理
"""
1)不管页面组件还是小组件,都可能会被多次复用
2)复用组件的原因,其实就是复用组件的 页面结构、页面样式、页面逻辑
3)但是页面上的数据需要区分(被复用的两个组件数据多少是有区别的),所以组件的数据要做局部化处理
4)借助函数可以产生局部作用域的特点,为每一次复用组件产生一个独立的作用域
语法:
data () {
return {
// 数据们
}
}
"""
子组件
<template>
<div class="beat" @click="count += 1">
{{ count }}下
</div>
</template>
<script>
export default {
name: "Beat",
// 不管是页面组件还是小组件,都可能被复用,页面结构与样式都可以采用一套,但是数据一定要相互独立
data () {
return {
count: 0
}
}
}
</script>
<style scoped>
.beat {
width: 100px;
height: 100px;
background-color: orange;
text-align: center;
line-height: 100px;
border-radius: 50%;
}
</style>
父组件
<template>
<div class="home">
<Beat/>
<Beat/>
</div>
</template>
<script>
import Beat from '@/components/Beat'
export default {
components: {
Beat,
}
}
</script>
路由逻辑跳转
"""
1)很多时候,我们需要通过普通按钮的逻辑,或是直接在某些逻辑中完成页面的跳转
2)可以通过在逻辑中用 this.$router.push() 来完成前往目标页,两种语法如下
this.$router.push('路径')
this.$router.push({name: '路由名'})
3)在做移动端项目时,没有像浏览器那样的前进后台键,页可以用 this.$router.go() 来完成前进后退,语法如下
前进后退:this.$router.go(正负整数),正式代表前进,负数代表后台,数值就是步长
"""
案例
<template>
<div class="home">
<Nav/>
<h1>主页</h1>
<button @click="goPage('/first')">前往第一页</button>
|
<button @click="goPage('/second')">前往第二页</button>
|
<button @click="goBack(-1)">后退一页</button>
|
<button @click="goBack(-2)">后退二页</button>
|
<button @click="goBack(1)">前进一页</button>
</div>
</template>
<script>
import Nav from '@/components/Nav'
export default {
methods: {
goPage(path) {
// 可以通过 this.$router 完成逻辑跳转
this.$router.push();
},
goBack(num) {
// 一般在移动端项目上运用
this.$router.go(num);
}
},
components: {
Nav,
}
}
</script>
组件传参
父传子
"""
一、组件传参 - 父传子
1)在子组件内部通过props设置组件的自定义属性
props: ['abc', 'goods']
2)在父组件渲染子组件是对自定义属性赋值即可
<GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods"/>
"""
子组件
<template>
<div class="goods-box">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</div>
</template>
<script>
export default {
name: "GoodsBox",
// 在组件内部通过props定义组件的自定义属性
props: ['abc', 'goods'],
}
</script>
<style scoped>
.goods-box {
width: 260px;
height: 300px;
border: 1px solid black;
border-radius: 5px;
margin: 20px;
float: left;
overflow: hidden;
text-align: center;
}
img {
width: 260px;
height: 260px;
}
</style>
父组件
<template>
<div class="goods">
<div class="main">
<!-- 在使用子组件是对自定义属性赋值即可 -->
<GoodsBox v-for="goods in goods_list" :abc="goods" :goods="goods" />
</div>
</div>
</template>
<script>
import GoodsBox from "../components/GoodsBox";
let goods_list = [
{
img: require('@/assets/img/001.jpg'),
title: '小猫',
},
{
img: require('@/assets/img/002.jpg'),
title: '小猫儿',
},
{
img: require('@/assets/img/003.jpg'),
title: '小狗',
},
{
img: require('@/assets/img/004.jpg'),
title: '小狗儿',
},
];
export default {
name: "Goods",
data () {
return {
goods_list,
}
},
components: {
GoodsBox,
},
}
</script>
子传父
"""
二、组件传参 - 子传父
前提:子组件是被父组件渲染的,所以子组件渲染要晚于父组件
1)子组件一定要满足一个条件,才能对父组件进行传参(某个时间节点 === 某个被激活的方法)
eg:i)子组件刚刚加载成功,给父组件传参 ii)子组件某一个按钮被点击的时刻,给父组件传参 iii)子组件要被销毁了,给父组件传参
2)在子组件满足条件激活子组件的方法中,对父组件发生一个通知,并将数据携带处理(自定义组件事件)
<div class="goods-box" @click="boxClick"></div>
methods: {
boxClick () { this.$emit('receiveData', this.goods.title, '第二个数据', '第三个数据') }
}
3)在父组件渲染子组件时,为自定义事件绑定方法
<GoodsBox @receiveData="recFn"/>
4)在父组件实现绑定方法时,就可以拿到子组件传参的内容(接收到了通知并在父组件中相应)
recFn(title, data2, data3) {
console.log('接收到了' + title);
}
组件标签不能绑定系统定义的事件,没有意义,子组件的事件都是在自己内部完成
"""
子组件
<template>
<div class="goods-box" @click="boxClick">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</div>
</template>
<script>
export default {
props: ['abc', 'goods'],
methods: {
boxClick () {
// 通知父级 - 自定义组件的事件
this.$emit('receiveData', this.goods.title)
}
}
}
</script>
父组件
<template>
<div class="goods">
<div class="main">
<!-- 实现自定义事件,接收子组件通知的参数 -->
<GoodsBox v-for="goods in goods_list" @receiveData="recFn"/>
</div>
</div>
</template>
<script>
import GoodsBox from "../components/GoodsBox";
export default {
name: "Goods",
data () {
return {
goodsTitle: '哪个',
}
},
methods: {
recFn(title) {
console.log('接收到了' + title);
this.goodsTitle = title;
}
},
components: {
GoodsBox,
},
}
</script>
组件的生命周期钩子
"""
一、组件的生命周期:一个组件从创建到销毁的整个过程
二、生命周期钩子:在一个组件生命周期中,会有很多特殊的时间节点,且往往会在特定的时间节点完成一定的逻辑,特殊的事件节点可以绑定钩子
注:钩子 - 提前为某个事件绑定方法,当满足这个事件激活条件时,方法就会被调用 | 满足特点条件被回调的绑定方法就称之为钩子
"""
<template>
<div class="goods">
<Nav />
</div>
</template>
<script>
import Nav from "../components/Nav";
export default {
name: "Goods",
components: {
Nav,
},
beforeCreate() {
console.log('该组件要被加载了')
},
created() {
console.log('该组件要被加载成功了')
},
updated() {
console.log('数据更新了')
},
destroyed() {
console.log('该组件销毁了')
}
}
</script>
路由传参
"""
路由传参:
一、通过url正则传递数据
i)设置
路由: path: '/goods/detail/:pk' | '/goods/:pk/detail/:xyz'
请求: '/goods/detail/任意字符' | '/goods/任意字符/detail/任意字符'
ii)如何传
<router-link :to="`/goods/detail/${pk}`"></router-link>
this.$router.push(`/goods/detail/${pk}`)
iii)如何取
this.$route对象是管理路由参数的,传递的参数会在this.$route.params字典中
this.$route.params.pk
二、通过url参数传递数据
i)设置
路由: path: '/goods/detail'
请求: '/goods/detail?pk=数据'
ii)如何传
<router-link :to="`/goods/detail?pk=${pk}`"></router-link>
<router-link :to="{name:'GoodsDetail', query:{pk: pk}}"></router-link>
this.$router.push(`/goods/detail?pk=${pk}`)
this.$router.push({name:'GoodsDetail', query:{pk: pk}})
iii)如何取
this.$route对象是管理路由参数的,传递的参数会在this.$route.query字典中
this.$route.query.pk
"""
第一种
配置:router/index.js
const routes = [
{
path: '/goods/detail/:pk',
name: 'GoodsDetail',
component: GoodsDetail
},
]
传递:GoodsBox.vue
<router-link class="goods-box" :to="`/goods/detail/${goods.pk}`">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</router-link>
<!------------------- 或者 ------------------->
<div class="goods-box" @click="goDetail(goods.pk)">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</div>
<script>
export default {
name: "GoodsBox",
methods: {
goDetail (pk) {
this.$router.push(`/goods/detail/${pk}`);
}
}
}
</script>
接收:GoodsDetail.py
<script>
export default {
name: "GoodsDetail",
data () {
return {
pk: '未知',
}
},
// 通常都是在钩子中获取路由传递的参数
created() {
this.pk = this.$route.params.pk || this.$route.query.pk;
}
}
</script>
第二种
配置:router/index.js
const routes = [
{
path: '/goods/detail',
name: 'GoodsDetail',
component: GoodsDetail
},
]
传递:GoodsBox.vue
<router-link class="goods-box" :to="`/goods/detail?pk=${goods.pk}`">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</router-link>
<!------------------- 或者 ------------------->
<div class="goods-box" @click="goDetail(goods.pk)">
<img :src="goods.img" alt="">
<p>{{ goods.title }}</p>
</div>
<script>
export default {
name: "GoodsBox",
methods: {
goDetail (pk) {
// this.$router.push(`/goods/detail?pk=${goods.pk}`);
// 或者
this.$router.push({
name: 'GoodsDetail',
query: {
pk,
}
});
}
}
}
</script>
接收:GoodsDetail.py
<script>
export default {
name: "GoodsDetail",
data () {
return {
pk: '未知',
}
},
// 通常都是在钩子中获取路由传递的参数
created() {
this.pk = this.$route.params.pk || this.$route.query.pk;
}
}
</script>
全家配置自定义css与js
global.css
html, body {
margin: 0;
}
a {
color: black;
text-decoration: none;
}
ul {
margin: 0;
padding: 0;
}
settings.js
export default {
base_url: 'https://127.0.0.1:8000'
}
main.js
//1) 配置全局css
import '@/assets/css/global.css'
// import global_css from '@/assets/css/global.css' // 资源需要用变量保存,方便以后使用
// require('@/assets/css/global.css')
// let global_css = require('@/assets/css/global.css') // 资源需要用变量保存,方便以后使用
// 2) 配置自定义js设置文件
import settings from '@/assets/js/settings.js'
Vue.prototype.$settings = settings;
// 在任何一个组件中的逻辑,可以通过 this.$settings访问settings.js文件的{}数据
小结
"""
项目:
环境;node -> npm -> cnpm -> vue/cli
创建:vue create proj
配置:配置npm启动项
项目目录结构:依赖、环境、入口、核心代码们
组件:
构成:template + script + style
导入:import 别名 from '路径'
父加子:1)导入 2)注册 3)使用
组件数据:组件化处理 data(){ return {} }
传参:父传子 - 自定义组件属性 | 子传父 - 自定义组件事件
生命周期钩子:created() { //完成后台请求等 }
路由:
根组件中的页面占位:<router-view />
导航栏中的页面跳转:<router-link to=""></router-link>
代码中的逻辑跳转:this.$router.push() | this.$router.go()
路由传参:两种方式
两个路由对象:
this.$router - 控制路由跳转
this.$route - 控制路由数据
"""
五、内容大纲
"""
第三方插件:
1)vuex:组件间交互的(移动端)
2)axios - 前后台(django):ajax
3)element-ui:页面布局
4)jq+bs:jQuery+BootStrap
"""
vuex插件:可以完成任意组件间信息交互(移动端) - 了解
"""
1)vuex是实现任何组件间的信息交互的,可以理解为全局的一个单例,为任何一个组件共享vue仓库里的数据
2)在任何一个组件的逻辑里,都可以访问仓库
i)现在仓库里(store/index.js)定义变量,用来存储共享数据
state: {
info: '共享数据的初始值'
},
ii)在组件逻辑中获取仓库值
let 变量 = this.$store.state.info
iii)在组件逻辑中更新仓库值
this.$store.state.info = '新值'
注:vuex通常运用在开发移动端项目,pc端项目可以用localStorege和localStorege数据库来替换
原因:vuex中的数据,会在页面刷新后,重置到store/index.js配置的默认值
"""
前端存储数据大汇总
"""
1)cookie:以字符串形式存储,数据有过期时间(过期时间到,数据失效吗,否则永远有效)
2)localStorage:以对象形式存储,数据永久保存
3)sessionStorage:以对象形式存储,生命周期同所属页面标签(页面不关闭,数据就有效)
4)vuex(store):以对象形式存储,当页面刷新数据就重置(移动端不能刷新,所以只有应用大退才会重置)
"""
前后台交互方式(重点)
"""
1)form表单方式
i)get | post 两种请求方式,get请求包含直接在浏览器中输入url回车后发送的请求
ii)该方式的特点是一定会发生页面的跳转(刷新页面叫本页跳转) - 后台决定页面路由
2)ajax异步方式
i)get | post | patch | put | delete 等众多请求方式,请求的目的都是异步获取后台的数据
ii)该方式的特点是不会刷新页面,只是得到新的数据,前台自己完成页面的局部刷新、整体刷新、页面跳转 - 前台决定页面路由
注:
i)前后台不分离项目,采用form表单请求,可以完成页面跳转,同步ajax异步请求完成页面局部刷新
ii)前后台分离项目,不采用form表单请求,页面刷新、页面跳转的请求,都是由ajax完成,只不过页面跳转,后台相应的是跳转的目标url,前台再自己完成跳转
iii)前后台分离项目,前台也会出现大量的form表单,但是form表单的提交按钮,走的不是form表单的submit提交,而是ajax请求
"""
axios插件:完成前后台ajax交互的
"""
1)安装:在前端项目根目录下的终端
cnpm install axios
2)项目配置:main.js
import axios from 'axios'
Vue.prototype.$axios = axios;
3)在任何一个组件的逻辑中,都可以访问 this.$axios()
beforeMount() {
// 请求后台
this.$axios({
url: this.$settings.base_url + '/test/',
method: 'delete',
})
}
"""
同源策略 - 跨域问题
"""
一、django默认是同源策略,所以前后台分离项目,访问django会出现CORS跨域问题的报错
二、什么叫跨域
i)ip不同:前后台(两个服务器)不在一台主机上运行的
ii)port不同:前后台(两个服务器)是相互独立的,运行在不同的端口之上
iii)协议不同:http与https之间也同样是跨域问题
注:三者满足一个,就是跨域
三、解决跨域
i)伪装:将前台请求伪装成后台自己对自己发生的请求
ii)后台主动允许跨域:后台配置允许跨域即可(在响应头中处理)
四、Django解决跨域
i)安装模块:
pip install django-cors-headers
ii)注册app:
INSTALLED_APPS = [
...
'corsheaders'
]
iii)添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware'
]
iv)允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
"""
前后台分离项目交互流程
"""
1)启动前后台项目
2)前台配置页面路由,渲染前台页面 | 后台配置数据路由,响应数据(处理好跨域问题)
3)前台通过ajax请求后台接口
i)将前台数据提交给后台
ii)得到后台的响应结果
iii)根据响应结果的数据,最后完成页面的局部刷新、整体刷新、页面跳转
"""
异步请求细节
"""
1)vue框架用axios完成ajax异步请求
语法:this.$axios().then().catch();
解读:$axios()是请求逻辑 | then()是正常响应逻辑 | catch()是错误响应逻辑
具体语法:
this.$axios({
url: '后台接口链接',
method: '请求方式',
params: {}, // url拼接参数
data: {}, // 数据包参数
headers: {} // 请求头参数
}).then(response => {
// response是http状态2xx的响应结果,响应数据是response.data
}).catch(error => {
// error是http状态4xx、5xx的响应结果,错误响应对象是error.response,错误响应数据是error.response.data
})
2)前台提交数据的两种方式:
i)url拼接参数:
所有请求都拥有的提交数据的方式
该方式会将数据都在请求url后用?拼接的方式提交给后台
提交数据只能采用url字符串方式提交给后台,数据是不安全的
axios插件可以用params属性携带url拼接参数
ii)数据包参数:
除get请求外的所有请求都拥有的提交数据的方式
该方式会将数据进行加密,打包成数据包方式提交给后台
打包加密数据有三种方式:urlencoded(form默认的方式)、form-data(可以提交文件)、json(提交json数据)
axios插件可以用data属性携带数据包参数
"""
"""
注意项:
1)this.$axios({}).then(response => {}).catch(error => {}) 中的then和catch回调函数,不能写function,因为实际vue项目开发,一定会在回调逻辑用到this语法(代表vue对象),而在function中使用了this语法,function就不是普通函数了(可以理解为类,this就不能代表vue对象了)
2)原生django没有提供所有类型的数据包数据解析规则,但是数据会在request.body中,可以自己解析;Django-rest-framework框架是提供了三种类型的数据包参数解析
"""
element-ui插件
"""
element-ui就类似于BootStrap框架,前者是在vue项目中运用,后者是在原生项目中运用,当然也可以在vue项目中运用
环境搭建:
1)安装:在前端项目根目录下的终端
cnpm install element-ui
2)配置:main.js
import ElementUI from 'element-ui'
Vue.use(ElementUI);
import 'element-ui/lib/theme-chalk/index.css';
3)使用:根据视频和官方API接口
"""
jq+bs插件
"""
一、jq环境搭建:
1)安装:在前端项目根目录下的终端
cnpm install jquery
2)配置:自己在项目根目录下新建 vue.config.js
const webpack = require("webpack");
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.$": "jquery",
"window.jQuery": "jquery",
Popper: ["popper.js", "default"]
})
]
}
};
二、bs环境搭建:
1)安装:在前端项目根目录下的终端
cnpm install bootstrap@3
2)配置:自己在项目根目录下新建 vue.config.js
import BootStrap from "bootstrap"
import "bootstrap/dist/css/bootstrap.css"
Vue.use(BootStrap)
"""
Django国际化配置
"""
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
"""
小结
"""
1)vuex
仓库,拥有组件间传参
前台存储数据的位置:cookie、localStorage、sessionStorage、vuex
2)axios
配置:安装 => 配置给Vue.prototype.$axios
使用:this.$axios({}).then(response => {}).catch(error => {})
两种请求:form(页面跳转,前后台不分离) | ajax(只刷新数据,所有类型项目都可以)
前后台分离项目工作流程:前台启动提供页面 => 后台启动提供数据 => 前台渲染页面并请求后台数据
请求方式:get、post、patch、put、delete...
请求数据:
url拼接数据:所有请求都可以携带
数据包数据:只有get不能携带
数据包三种格式:urlencoded、form-data、json
3)element-ui
提供一堆布局
4)jq+bs
提供一堆布局
"""