1. es5和es6基础知识
1.1 前后端分离项目
前后端未分离项目:html文件渲染在django后端完成
--------------------------------------------------------------
前后端分离项目:ajax异步请求,django只负责读取数据和加工数据
前端做前端的事情:页面+交互+兼容+封装+class+优化 (技术栈:vue+vue-router+vuex+axios+element-ui)
后端做后端的事情:接口+表操作+业务逻辑+封装+class+优化 (技术栈:restframework框架+django框架+mysql\redis等)
1.2 MTV模式和MVVM框架
Vue 前端框架(数据驱动视图) MVVM -- model -- view -- viewmodel --- template模板渲染
model--数据
view -- 视图 -- html标签 类似于jquery $('#d1').text('xxx')
viewmodel:数据驱动视图 vue的核心,model数据直接驱动到视图中(html标签中)
django -- MTV模式
model template view + url控制器
template这一块功能就去掉了
view--视图: 后端逻辑 FBV和CBV
1.3 ES6基本语法
1.let声明变量
let 声明的变量只在let命令所在的代码块内有效 ( js里面大括号表示一个代码块 )
{
let a = 10;
var b = 1; //相当于将b的声明放在了作用域的外面前面,var b;然后这里只是赋值
}
不存在变量提升
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
暂时性死区
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
-----------------------------------------------------------------------------------
上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错
不允许重复声明
// 报错
function func() {
let a = 10;
var a = 1;
}
// 报错
function func() {
let a = 10;
let a = 1;
}
//let不允许在相同作用域内,重复声明同一个变量。
2.作用域
let
实际上为 JavaScript 新增了块级作用域。
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
3.const声明常量
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
4.模板字符串
模板字符串就是两个反引号,括起来的字符串,就是模板字符串,var或者let声明的变量都可以被模板字符串直接通过${变量名}来使用
var aa = 'chao';
let bb = 'jj';
var ss = `你好${aa}`;
ss
"你好chao"
var ss2 = `你好${bb}`;
ss2
"你好jj"
let ss3 = `你好${aa}`;
ss3
"你好chao"
5.函数
匿名函数
let add = function (x) {
return x
};
add(5);
箭头函数 (就是上面方法的简写形式)
//ES6的箭头函数,就是上面方法的简写形式
let add = (x) => {
return x
};
console.log(add(20));
//更简单的写法,但不是很易阅读
let add = x => x;
console.log(add(5));
多个参数的时候必须加括号,函数返回值还是只能有一个,没有参数的,必须写一个()
let add = (x,y) => x+y;
自定义对象中封装函数(注意this指向问题)
//ES6中自定义对象中来封装箭头函数的写法
let person2 = {
name:'超',
age:18,
f1: () => { //在自定义的对象中放函数的方法
console.log(this); //this指向的不再是当前的对象了,而是指向了person的父级对象(称为上下文),而此时的父级对象是我们的window对象,Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
console.log(window);//还记得window对象吗,全局浏览器对象,打印结果和上面一样:Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
console.log(this.name) //啥也打印不出来
}
};
person2.f1(); //通过自定对象来使用函数
//而我们使用this的时候,希望this是person对象,而不是window对象,所以还有下面这种写法
let person3 = {
name:'超',
age:18,
f1(){ //相当于f1:function(){},只是一种简写方式,称为对象的单体模式写法,写起来也简单,vue里面会看用到这种方法
console.log(this);//this指向的是当前的对象,{name: "超", age: 18, f1: ƒ}
console.log(this.name) //'超'
}
};
person3.f1()
2.vue的基本使用
1.下载安装
官网地址:https://cn.vuejs.org/
方式1:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
方式2:
<script src="vue.js"></script>
2.vue基本模板
1)在body标签里圈地
2)script 引入vue
3)实例化对象
<div id="app">
<!-- vue的模板语法,和django的模板语法类似 -->
<h2>{{ msg }}</h2><!-- 放的是变量,就会去下面的Vue对象中的data属性中的键去找对应的数据,注意语法规范,中间的数据前后都有一个空格 -->
<h2>{{ 'xxxxx' }}</h2> <!-- 写个字符串就直接显示这个字符串 -->
</div>
<!-- 1.引包 -->
<script src="vue.js"></script>
<script>
//2.实例化对象
new Vue({ //实例化的时候要传一个参数,options配置选项,是一个自定义对象,下面就看看这些配置选项都是什么,是我们必须要知道的东西,el和data是必须要写的
el:'#app', //el是当前我们实例化对象绑定的根元素(标签),会到html文档中找到这个id属性为app的标签,在html里面写一个id属性为app的div标签,意思就是说,我现在实例化的这个Vue对象和上面这个id为app的div绑定到了一起,在这个div里面使用vue的语法才能生效,就像一个地主圈了一块地一样,那么接下来就要种东西了
data:{ //data是数据属性,就是我们要在地里面种的东西了,是一个自定义对象
msg:'黄瓜', //这些数据以后是通过数据库里面调出来,然后通过后端代码的接口接收到的,现在写死了,先看看效果,我们在上面的div标签里面写一个其他的标签,然后写上{{ msg }},这样就相当于我们在id为app的div标签的这个地里面种了一个种子,这个种子产的是黄瓜,那么我们打开页面就直接看到黄瓜了
}
})
</script>
data属性的其他写法:
// 方式2
data:function () {
return {
'msg':'掀起你的盖头来1!'
}
}
// 方式3 (常用)
data(){ // 单体模式 这种写法用的居多,并且后面学习中有个地方一定要这样写,所以我们就记下来这种写法就可以了
return {
'msg':'掀起你的盖头来2!',
}
}
3.vue的指令系统
指令会在vm对象的data属性的数据发生变化时,会同时改变元素中的其控制的内容或属性。
因为vue的历史版本原因,所以有一部分指令都有两种写法:
vue1.x写法 vue2.x的写法
v-html ----> {{ }} # vue2.x 也支持v-html
v-bind:属性名 ----> :属性
v-on:事件名 ----> @事件名
3.1 v-text 和 v-html 文本指令
v-text相当于js代码的innerText
v-html相当于innerHtml,识别标签
<body>
<div id="app">
<!-- vue的模板语法 -->
<div>{{ msg }}</div>
<div v-text="msg"></div>
<div v-html="msg"></div>
</div>
<script src="vue.js"></script>
<script>
new Vue({
el:'#app',
data(){
//记着data中是一个函数,函数中return一个对象,可以是一个空对象,但必须return
return{
msg:'<h2>超</h2>', //后端返回的是标签,那么我们就可以直接通过v-html渲染出来标签效果
}
}
})
</script>
</body>
</html>
3.2 v-if 和 v-show 条件渲染指令
v-if是标签的添加和删除,v-show是标签的显示和隐藏
---------------------------------------------------------------
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-if:
----------------v-if-------------------------------------
标签元素:
<!-- vue对象最终会把条件的结果变成布尔值 -->
<h1 v-if="ok">Yes</h1>
data数据:
data:{
ok:false // true则是显示,false是隐藏
}
-------------v-if 和 v-else-------------------------------
标签元素:
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
data数据:
data:{
ok:false // true则是显示,false是隐藏
}
-------------v-else-if-----------------------------------
标签元素:
<h1 v-if="num===1">num的值为1</h1>
<h1 v-else-if="num===2">num的值为2</h1>
<h1 v-else>num的值是{{num}}</h1>
data数据:
data:{
num:2
}
v-show:
标签元素:
<h1 v-show="ok">Hello!</h1>
data数据:
data:{
ok:false // true则是显示,false是隐藏
}
3.3 v-bind 操作属性
格式:
<标签名 :标签属性="data属性"></标签名>
<a :href="url2">淘宝</a>
<a v-bind:href="url1">百度</a> <!-- v-bind是vue1.x版本的写法 -->
3.4 事件绑定v-on和methods属性
有两种操作时间的写法,
//方式1:
<button v-on:click="num++">按钮</button> <!-- v-on 是vue1.x版本的写法 -->
//方式2:
<button @click="num+=5">按钮2</button>
3.5 v-model 标签数据的双向绑定
v-model : 实现标签和数据的双向绑定,是数据驱动视图的典型表现
v-model本质上是一个语法糖。如下代码<input v-model="test">
本质上是<input :value="test" @input="test = $event.target.value">
如:在input标签中的应用
<div id="app">
<input v-model="text">
<sapn>{{text}}</sapn>
</div>
-------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
text:'',
}
}
})
</script>
如:在单选框中的应用:
<div id="app">
<select v-model="selected">
<option value="A被选">A</option>
<option value="B被选">B</option>
<option value="C被选">C</option>
</select>
<span>被选的是: {{ selected }}</span>
<div>
-----------------------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
selected: '',
}
}
})
</script>
例1:wifi密码切换显示
<div id="index">
<img :src="url" :alt="title"><br>
<input :type="type" placeholder="请输入wifi密码">
<button @click="clickhander">{{type_tips}}</button>
<button @mouseover="clickhander">{{type_tips}}</button> <!--事件名称都是按照js中的事件名称来的,所以可以使用的事件很多-->
<button v-on:click="clickhander">{{type_tips}}</button>
</div>
----------------------------------------------------------------
<script>
let vm = new Vue({
el:"#index",
// 在data可以定义当前vue对象调用的属性,调用格式: this.变量名,例如: this.title
data:{
url:"https://www.luffycity.com/static/img/head-logo.a7cedf3.svg",
title:"路飞学成",
type:"password",
type_tips: "显示密码",
},
methods:{ // 在methods中可以定义当前vue对象调用的方法,调用格式:this.方法名(),例如: this.clickhander()
clickhander(){
// alert(this.type); // 调用上面的data里面的数据
if(this.type=="password"){
this.type="text";
this.type_tips="隐藏密码";
}else{
this.type="password";
this.type_tips="显示密码";
}
}
}
})
</script>
例2:完成商城的商品增加减少数量
<div id="box">
<button @click="++num">+</button>
<input type="text" v-model="num">
<button @click="sub">-</button>
</div>
----------------------------------------------------
<script>
let vm = new Vue({
el:"#box",
data:{
num:0,
},
methods:{
// sub:function(){},下面是这个写法的缩写
sub(){
if(this.num<=1){
this.num=0;
}else{
this.num--;
}
}
}
})
</script>
3.6控制标签class类名
格式:
<h1 :class="值">元素</h1> 值可以是对象、对象名、数组(数组的方式用的比较少)
方式1:布尔值控制
<div id="app">
<div :class="{c1:num==0,c3:num==0}" class="c2">{{msg}}</div>
<input type="text" v-model="num"> //通过v-model控制
</div>
---------------------------------------------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
msg:'hello',
num:0,
}
}
})
</script>
方式2:三目运算符
<div id="app">
<div :class="status?'c1':'c2'">{{msg}}</div>
</div>
---------------------------------------------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
msg:'hello',
status:false,
}
}
})
</script>
方式3:数组控制(不常用)
<div id="app">
<div :class="[m1,]">xxxxx</div>
</div>
----------------------------------------------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
msg:'hello',
m1:{
c1:false,
c2:false,
}
}
}
})
</script>
3.7 控制标签style样式
方式1:值是json对象,对象写在元素的:style属性中
//标签元素:
<div :style="{color: activeColor, fontSize: fontSize + 'px' }"></div><!-- 注意:不能出现中横杠,有的话就套上'font-size',或者去掉横杠,后一个单词的首字母大写,比如fontSize -->
-----------------------------------------------------------------------
//data数据如下:
data: {
activeColor: 'red',
fontSize: 30
}
方式2:值是对象变量名,对象在data中进行声明
标签元素:
<div v-bind:style="styleObject"></div>
---------------------------------------------------------------
data数据如下:
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
方式3:值是数组
标签元素:
<div v-bind:style="[style1, style2]"></div>
--------------------------------------------------------------
data数据如下:
data: {
style1:{
color:"red"
},
style2:{
background:"yellow",
fontSize: "21px"
}
}
例:vue版本选项卡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#card{
width: 500px;
height: 350px;
}
.title{
height:50px;
}
.title span{
width: 100px;
height: 50px;
background-color:#ccc;
display: inline-block;
line-height: 50px; /* 设置行和当前元素的高度相等,就可以让文本内容上下居中 */
text-align:center;
}
.content .list{
width: 500px;
height: 300px;
background-color: yellow;
display: none;
}
.content .active{
display: block;
}
.title .current{
background-color: yellow;
}
</style>
<script src="vue.js"></script>
</head>
<body>
<div id="card">
<div class="title">
<span @click="num=1" :class="{current:num===1}">国内新闻</span>
<span @click="num=2" :class="{current:num===2}">国际新闻</span>
<span @click="num=3" :class="{current:num===3}">银河新闻</span>
<!--<span>{{num}}</span>-->
</div>
<div class="content">
<div class="list" :class="{active:num===1}">国内新闻列表</div>
<div class="list" :class="{active:num===2}">国际新闻列表</div>
<div class="list" :class="{active:num===3}">银河新闻列表</div>
</div>
</div>
<script>
// 思路:
// 当用户点击标题栏的按钮[span]时,显示对应索引下标的内容块[.list]
// 代码实现:
var card = new Vue({
el:"#card",
data:{
num:1,
},
});
</script>
</body>
</html>
3.8 v-for 列表渲染指令
<div id="app">
<ul>
<!--<li v-for="(value,index) in data_list" :key="index">-->
<!--<li v-for="value in data_list" :key="value.id">-->
<li v-for="value in data_list" :key="value.id"> //value.id---> 1 4
{{value.name}}
</li>
<li v-for="(value,index) in personInfo">
{{value}} -- {{index}}
</li>
</ul>
</div>
-------------------------------------------------------------------
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
data_list:[
{id:1,name:'鑫伟1'},
{id:4,name:'鑫伟4'},
],
personInfo:{
name:'chao',
age:18
}
}
}
})
</script>
关于key的说明
v-for不仅可以遍历数组,还可以遍历对象,这里大家记住v-for里面的一个东西 :key, 就是v-bind:key,这个key是干什么的呢,就是为了给现在已经渲染好的li标签做个标记,以后即便是有数据更新了,也可以在这个li标签里面进行数据的更新,不需要再让Vue做重新生成li标签的dom操作,提高页面渲染的性能,因为我们知道频繁的添加删除dom操作对性能是有影响的,我现在将数据中的id绑定到这里,如果数据里面有id,一般都用id,如果没有id,就绑定v-for里面那个index(当然你看你给这个索引取的变量名是什么,我这里给索引取的名字是index),这里面它用的是diff算法.
练习:商品循环实例
goods:[
{"name":"python入门","price":150},
{"name":"python进阶","price":100},
{"name":"python高级","price":75},
{"name":"python研究","price":60},
{"name":"python放弃","price":110},
]
# 把上面的数据采用table表格输出到页面,价格大于60的那一条数据需要添加背景色
<div id="app">
<table border="1">
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody>
<tr v-for="(value,index) in goods" :key="index">
<td>{{value.name}}</td>
<td v-if="value.price>60" style="background-color: red;">{{value.price}}</td>
<td v-else>{{value.price}}</td>
</tr>
</tbody>
</table>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
goods:[
{"name":"python入门","price":150},
{"name":"python进阶","price":100},
{"name":"python高级","price":75},
{"name":"python研究","price":60},
{"name":"python放弃","price":110},
]
}
}
})
</script>
3.Vue对象提供的属性功能
3.1过滤器
过滤器,就是vue允许开发者自定义的文本格式化函数,可以使用在两个地方:输出内容和操作数据中。
定义过滤器的方式有两种,全局和局部过滤器
<div id="app">
<p>{{price}}</p>
<p>{{price.toFixed(2)}}</p>
<p>{{price|yuan}}</p>
<p>{{price|xx}}</p>
<p>{{price|xx|yuan}}</p>
<!-- 过滤器传额外参数 -->
<p>{{price2|yuan2(2)}}</p>
</div>
<script src="vue.js"></script>
<script>
// 全局过滤器
Vue.filter('xx',function (value) {
return value.toFixed(3) + '圆'
});
let vm = new Vue({
el:'#app',
data(){
return {
price:100,
price2:100.126, //四舍五入
}
},
// 局部过滤器
filters:{
yuan(value){
return value + ' 元'
},
yuan2(value,n){
return value.toFixed(n) + ' 元'
}
}
})
3.2 计算属性
<div id="app">
<p>{{add}}</p> //200.126
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
price1:100,
price2:100.126, //四舍五入
}
},
// 计算属性
computed:{
add(){
return this.price1 + this.price2
}
}
})
</script>
3.3 监听属性
监听属性,可以帮助我们侦听data某个数据的变化,从而做相应的自定义操作。
监听属性是一个对象,它的键是要监听的对象或者变量,值一般是函数。
当侦听的data数据发生变化时,会自定执行的对应函数,这个函数在被调用时,vue会传入两个形参,第一个是变化后的数据值,第二个是变化前的数据值。
<div id="app">
<p>{{ num }}</p>
<button @click="num++">按钮</button>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
num:20
},
watch:{
num:function(newval,oldval){
//num发生变化的时候,要执行的代码
console.log("num已经发生了变化!",newval,oldval);
}
}
})
</script>
例:用户名长度限制4-10位
<div id="app">
<form action="">
账号:<input type="text" v-model="form.username"><span :style="user_style">{{user_text}}</span><br><br>
密码:<input type="password" v-model="form.password"><br><br>
确认密码:<input type="password" v-model="form.password2"><br><br>
</form>
</div>
<script src="js/vue.js"></script>
<script src="js/filters.js"></script>
<script>
var vm1 = new Vue({
el:"#app",
data:{
form:{
username:"",
password:"",
password2:"",
},
user_style:{
color: "red",
},
user_text:"用户名长度只能是4-10位"
},
// 监听属性
// 监听属性的变化
watch:{
"form.username":function(value){ //注意,使用数据属性中的某个属性的时候,如果使用的是该数据中的内部属性,别忘了加双引号
if(value.length>=4 && value.length<=10){
this.user_style.color="blue";
this.user_text="用户名长度合法!";
}else{
this.user_style.color="red";
this.user_text="用户名长度只能是4-10位!";
}
}
}
})
</script>
3.4 vue对象的生命周期钩子函数
每个Vue对象在创建时都要经过一系列的初始化过程。在这个过程中Vue.js会自动运行一些叫做生命周期的的钩子函数,我们可以使用这些函数,在对象创建的不同阶段加上我们需要的代码,实现特定的功能。
<body>
<div id="app">
<p>{{num}}</p>
<button @click="num++">按钮</button>
</div>
</body>
<script src="js/vue.min.js"></script>
<script>
window.onload = function(){
//$(function(){})() $.ready() -- window.onload = function(){}
var vm = new Vue({
el:"#app",
data:{
num:0
},
beforeCreate:function(){
console.log("beforeCreate,vm对象尚未创建,num="+ this.num); //undefined,就是说data属性中的值还没有放到vm对象中
this.name=10; // 此时没有this对象呢,所以设置的name无效,被在创建对象的时候被覆盖为0
console.log(this.$el) //undefined
},
created:function(){
// 用的居多,一般在这里使用ajax去后端获取数据,然后交给data属性
console.log("created,vm对象创建完成,设置好了要控制的元素范围,num="+this.num ); // 0 也就是说data属性中的值已经放到vm对象中
this.num = 20;
console.log(this.$el) //undefined
},
beforeMount:function(){
console.log( this.$el.innerHTML ); // <p>{{num}}</p> ,vm对象已经帮我们获取到了这个视图的id对象了
console.log("beforeMount,vm对象尚未把data数据显示到页面中,num="+this.num ); // 20,也就是说vm对象还没有将数据添加到我们的视图中的时候
this.num = 30;
},
mounted:function(){
// 用的居多,一般在这里使用ajax去后端获取数据然后通过js代码对页面中原来的内容进行更改
console.log( this.$el.innerHTML ); // <p>30</p>
console.log("mounted,vm对象已经把data数据显示到页面中,num="+this.num); // 30,也就是说vm对象已经将数据添加到我们的视图中的时候
},
// 后面两个简单作为了解吧,测试的时候最好单独测试下面两个方法
beforeUpdate:function(){
// this.$el 就是我们上面的el属性了,$el表示当前vue.js所控制的元素#app
console.log( this.$el.innerHTML ); // <p>30</p>
console.log("beforeUpdate,vm对象尚未把更新后的data数据显示到页面中,num="+this.num); // beforeUpdate----31
},
updated:function(){
console.log( this.$el.innerHTML ); // <p>31</p>
console.log("updated,vm对象已经把过呢更新后的data数据显示到页面中,num=" + this.num ); // updated----31
},
});
}
</script>
用法:
在vue使用的过程中,如果要初始化操作,把初始化操作的代码放在 mounted 中执行。
mounted阶段就是在vm对象已经把data数据实现到页面以后。一般页面初始化使用。例如,用户访问页面加载成功以后,就要执行的ajax请求。
另一个就是created,这个阶段就是在 vue对象创建以后,把ajax请求后端数据的代码放进 created
3.5 阻止事件冒泡和刷新页面
使用.stop和.prevent
阻止事件冒泡:
<style>
.c1{
background-color: red;
height: 200px;
}
.c2{
background-color: green;
height: 100px;
width: 100px;
}
</style>
<div id="app">
<div class="c1" @click="f1">
<!--<div class="c2" @click.stop="f2" ></div>-->
<div class="c2" @click.stop.prevent="f2" ></div>
<!-- 阻止标签自带的动作 -->
<!--<a href="http://www.baidu.com" @click.stop.prevent="">百度</a>-->
</div>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
price1:100,
}
},
methods:{
f1(){
alert('111');
},
f2(){
alert('222');
}
}
})
</script>
例:todolist
<head>
<meta charset="UTF-8">
<title>todolist</title>
<style type="text/css">
.list_con{
width:600px;
margin:50px auto 0;
}
.inputtxt{
width:550px;
height:30px;
border:1px solid #ccc;
padding:0px;
text-indent:10px;
}
.inputbtn{
width:40px;
height:32px;
padding:0px;
border:1px solid #ccc;
}
.list{
margin:0;
padding:0;
list-style:none;
margin-top:20px;
}
.list li{
height:40px;
line-height:40px;
border-bottom:1px solid #ccc;
}
.list li span{
float:left;
}
.list li a{
float:right;
text-decoration:none;
margin:0 10px;
}
</style>
</head>
<body>
<div class="list_con">
<h2>To do list</h2>
<input type="text" name="" id="txt1" class="inputtxt" v-model="sm">
<input type="button" name="" value="增加" id="btn1" class="inputbtn" @click="add">
<ul id="list" class="list">
<!-- javascript:; # 阻止a标签跳转 -->
<li v-for="(value,index) in dolist" :key="value.id">
<span>{{value.dosm}}</span>
<a href="javascript:;" class="up" @click="up(index)"> ↑ </a>
<a href="javascript:;" class="down" @click="down(index)"> ↓ </a>
<a href="javascript:;" class="del" @click="del(index)">删除</a>
</li>
</ul>
</div>
</body>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el:'.list_con',
data(){
return {
sm:'',
dolist:[
{id:1,dosm:'学习html'},
{id:2,dosm:'学习css'},
{id:3,dosm:'学习javascript'},
{id:4,dosm:'学习python'},
{id:5,dosm:'学习推油'},
]
}
},
methods:{
add(){
let last_ele = this.dolist[this.dolist.length-1];
if (last_ele){
let ele = {
id:++last_ele.id,
dosm:this.sm,
};
this.dolist.push(ele);
}else {
this.dolist.push({id:1,dosm:this.sm});
}
// console.log(this.dolist);
},
del(index){
this.dolist.splice(index,1);
},
up(index){
if (index > 0){
let delEle = this.dolist.splice(index,1)[0];
// console.log(delEle);
this.dolist.splice(index-1,0,delEle)
}
},
down(index){
let delEle = this.dolist.splice(index,1)[0];
this.dolist.splice(index+1,0,delEle)
}
}
})
</script>
补充:a标签的href属性
<a href="#">百度</a>
<!--href属性为空时,刷新页面-->
<!--不写href属性,就是普通文本标签-->
<!-- 当href属性等于某个值时,页面跳转到对应的页面 -->
<!-- 当href属性等于javascript:void (0);简写javascript:;时,不刷新也不跳转 -->
<!-- 当href属性等于#时,不刷新也不跳转,但是会在url上加个#号结尾 -->
4.axios–实现数据请求
4.1axios的基础知识
什么是axios?
vue.js默认没有提供ajax功能的。
所以使用vue的时候,一般都会使用axios的插件来实现ajax与后端服务器的数据交互。
注意,axios本质上就是javascript的ajax封装,所以会被同源策略限制。
axios的下载地址:
https://unpkg.com/axios@0.18.0/dist/axios.js
https://unpkg.com/axios@0.18.0/dist/axios.min.js
4.2 axios常用发送请求的方法
axios.get()和axios.post()
// 发送get请求
// 参数1: 必填,字符串,请求的数据接口的url地址,例如请求地址:http://www.baidu.com?id=200
// 参数2:可选,json对象,要提供给数据接口的参数
// 参数3:可选,json对象,请求头信息
axios.get('服务器的资源地址',{ // http://www.baidu.com
params:{
参数名:'参数值', // id: 200,
}
}).then(function (response) { // 请求成功以后的回调函数
console.log("请求成功");
console.log(response);
}).catch(function (error) { // 请求失败以后的回调函数
console.log("请求失败");
console.log(error.response);
});
// 发送post请求,参数和使用和axios.get()一样。
// 参数1: 必填,字符串,请求的数据接口的url地址
// 参数2:必填,json对象,要提供给数据接口的参数,如果没有参数,则必须使用{}
// 参数3:可选,json对象,请求头信息
axios.post('服务器的资源地址',{
username: 'xiaoming',
password: '123456'
},{
responseData:"json",
})
.then(function (response) { // 请求成功以后的回调函数
console.log(response);
})
.catch(function (error) { // 请求失败以后的回调函数
console.log(error);
});
// b'firstName=Fred&lastName=Flintstone'
例:获取天气信息
<body>
<div id="app">
<h1>{{msg}}</h1>
</div>
</body>
<script src="vue.js"></script>
<script src="jquery.js"></script>
<script src="axios.js"></script>
<script>
let vm = new Vue({
el:'#app',
data(){
return {
price1:100,
msg:'',
}
},
created(){
// let ths = this;
// axios.get('http://wthrcdn.etouch.cn/weather_mini?city=北京&city2=xx',{
axios.get('http://wthrcdn.etouch.cn/weather_mini',{
params:{
city:'北京',
//city:'北京',
}
})
.then( (res) => {
// console.log(res);
// console.log(res.data.data.ganmao);
// console.log(this);
// 注意this指向问题
// ths.msg = res.data.data.ganmao;
this.msg = res.data.data.ganmao;
}).catch(function (res) {
})
// $.ajax({
// url:'http://wthrcdn.etouch.cn/weather_mini?city=北京',
// type:'get',
//
// success:function (res) {
// console.log(res);
// }
//
// })
}
})
</script>
4.3 同源策略
4.3.1 什么是同源策略
同源策略,是浏览器为了保护用户信息安全的一种安全机制。所谓的同源就是指代通信的两个地址(例如服务端接口地址与浏览器客户端页面地址)之间比较,是否协议、域名(IP)和端口相同。不同源的客户端脚本[javascript]在没有明确授权的情况下,没有权限读写对方信息。
总之,协议+域名+端口都相同时,两个网站同源,否则浏览器会拦截读取的信息
4.3.2 同源拦截的报错
Access to XMLHttpRequest at 'http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=%E6%88%91%E7%9A%84%E4%B8%AD%E5%9B%BD%E5%BF%83' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
上面错误,关键词:Access-Control-Allow-Origin
只要出现这个关键词,就是访问受限。出现同源策略的拦截问题。
4.3.3 django中跨域(跨源)方案
CORS:
CORS是一个W3C标准,全称是"跨域资源共享",它允许浏览器向跨源的后端服务器发出ajax请求,从而克服了AJAX只能同源使用的限制。
实现CORS主要依靠后端服务器中响应数据中设置响应头信息返回的。
在django的视图函数中:
def data(request):
ret = HttpResponse('ba jie ok!')
ret['Access-Control-Allow-Origin'] = '*' # 所有源请求我, 都行,浏览器不要阻拦
# ret['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' # 所有源请求我, 都行,浏览器不要阻拦
return ret
5.组件化开发
什么是组件
组件(Component)是自定义封装的功能。在前端开发过程中,经常出现多个网页的功能是重复的,而且很多不同的网站之间,也存在同样的功能。
而在网页中实现一个功能,需要使用html定义功能的内容结构,使用css声明功能的外观样式,还要使用js来定义功能的特效,因此就产生了把一个功能相关的[HTML、css和javascript]代码封装在一起组成一个整体的代码块封装模式,我们称之为“组件”。
所以,组件就是一个html网页中的功能,一般就是一个标签,标签中有自己的html内容结构,css样式和js特效。
这样,前端人员就可以在开发时,只需要书写一次代码,随处引入即可使用。
我们在进行vue开发的时候,还记得我们自己创建的vm对象吗,这个vm对象我们称为一个大组件,根组件(页面上叫Root),在一个网页的开发中,根据网页上的功能区域我们又可以细分成其他组件,或称为子组件
5.1局部组件和全局组件
局部组件:
1 声明子组件
2 挂载子组件
3 使用子组件
<div id="app">
<div class="vheader">
这是头部{{msg}}
</div>
<App/> <!--3 使用子组件-->
</div>
<script>
//子组件的名称尽量不要叫做Header或者vHeader等,以防和最新的H5中的标签名称冲突,导致组件无法使用
// 1 声明子组件
let App = {
data(){
return { //组件中必须写成函数形式的
'appmsg':'hello app!'
}
},
template:`
<div class="content">
内容部分{{appmsg}}
</div>
`
};
let vm = new Vue({
el:'#app',
data(){
return {
'msg':'hello'
}
},
components:{
App, // 2 挂载子组件
}
})
</script>
全局组件(默认组件)
局部组件使用时需要挂载,全局组件使用时不需要挂载。那么他们两个什么时候用呢,局部组件就在某个局部使用的时候,全局组件是大家公用的,或者说每个页面都有这么一个功能的时候,在哪里可能都会用到的时候。
<div id="app">
<addnum></addnum>
</div>
<script>
Vue.component("addnum",{
template:'<div><input type="text" v-model="num"><button @click="num+=1">点击</button></div>',
data: function(){
// 写在这里的数据只有当前组件可以使用
return {
num:1,
}
}
});
var vm = new Vue({
el:"#app",
data:{
}
})
</script>
5.2 组件传值
父组件往子组件传值
1.在子组件中使用props属性声明,然后可以直接在子组件中任意使用
2.父组件要定义自定义的属性
<div id="app">
<h1>你好</h1>
<App></App>
</div>
<script>
// 1 声明子组件 声子
let Naver = {
data(){
return {
navMsg:'这是顶部导航栏'
}
},
template:
`
<div class="Naver">
<h1>{{navMsg}}</h1>
<h2>2222</h2>
<h2>{{xx}}</h2>
</div>
`,
props:['xx',]
};
let App = {
data(){
return {
Msg:'这是App组件',
num:100,
}
},
template:
`
<div class="nav">
<h1 style="color:blue;">{{Msg}}---{{num}}</h1>
<!--
<Naver xx="xiaobei"></Naver> 静态传值
<Naver :xx="num"></Naver> 动态传值
-->
<Naver :xx="num"></Naver>
</div>
`,
components:{
Naver,
}
};
let vm = new Vue({
el:'#app',
data(){
return {
}
},
// 2 挂载子组件 挂子
components:{
// 挂载组件的简写形式
App,
}
})
</script>
注意:
1. 传递数据是变量,则需要在属性左边添加冒号.
传递数据是变量,这种数据称之为"动态数据传递"
传递数据不是变量,这种数据称之为"静态数据传递"
2. 父组件中修改了数据,在子组件中会被同步修改,但是,子组件中的数据修改了,是不是影响到父组件中的数据.
这种情况,在开发时,也被称为"单向数据流"
子组件往父组件传值
1 子组件中使用this.$emit('fatherHandler',val);fatherHandler是父组件中使用子组件的地方添加的绑定自定义事件
(注意,如果fatherHandler报错了,那么可能是你的vue版本不支持自定义键名称fatherHandler中有大写字母,所以我们改成father-handler或者直接就全部小写就可以了)
2 父组件中的methods中写一个自定义的事件函数:appFatherHandler(val){},在函数里面使用这个val,这个val就是上面子组件传过来的数据
子组件:
父组件:
<div id="app">
<h1>你好</h1>
<App></App>
</div>
<script>
// 1 声明子组件 声子
let Naver = {
data(){
return {
navMsg:'这是顶部导航栏',
sonNum:80,
}
},
template:
`
<div class="Naver">
<h1>{{navMsg}}</h1>
<button @click="zouni">走你</button>
</div>
`,
methods:{
zouni(){
//
console.log(this);
// 3 子组件中调用$emit方法,来实现传值动作 $emit(父组件自定义事件名称,数据)
this.$emit('fatherHandler',this.sonNum);
}
}
};
let App = {
data(){
return {
Msg:'这是App组件',
num:100,
xx:'',
}
},
//1. 父组件使用子组件的地方加上自定事件
template:
`
<div class="nav">
<h1 style="color:blue;">{{Msg}}---子组件的num为:{{xx}}</h1>
<Naver @fatherHandler="fuckSon"></Naver>
</div>
`,
components:{
Naver,
},
methods:{
// 2 在父组件中定义自定义事件对应的方法,方法需要写参数,用来接收子组件传递过来的数据
fuckSon(val){
this.xx = val;
}
}
};
let vm = new Vue({
el:'#app',
data(){
return {
}
},
// 2 挂载子组件 挂子
components:{
// 挂载组件的简写形式
App,
}
})
</script>
平行传值
1 new一个vue对象,用来存放和取出数据
2 存放:bus.$emit('kkk',this.t1Num); //(别名 , 需要传递的数据)
3 取出:
bus.$on('kkk', (val) => { //用箭头函数指向父级对象
console.log(this);
this.t1msg = val;
});
<div id="app">
<h1>你好</h1>
<App></App>
</div>
let bus = new Vue();
Vue.component('T1',{
data(){
return {
t1Msg:'我是t1组件',
t1Num:120,
}
},
template:`
<div class="t1">
<h3>{{t1Msg}}--{{t1Num}}</h3>
<button @click="zouni">走你</button>
</div>
`,
methods:{
zouni(){
bus.$emit('kkk',this.t1Num);
}
}
});
Vue.component('T2',{
data(){
return {
t2Msg:'我是t2组件',
t2Num:130,
t1msg:'',
}
},
template:`
<div class="t1">
<h3>{{t2Msg}}</h3>
<h3>t1组件传递过来的数据:{{t1msg}}</h3>
</div>
`,
created(){
bus.$on('kkk', (val) => {
console.log(this);
this.t1msg = val;
});
},
});
let App = {
data(){
return {
Msg:'这是App组件',
num:100,
xx:'',
}
},
template:
`
<div class="nav">
<T1></T1>
<T2></T2>
</div>
`,
};
let vm = new Vue({
el:'#app',
data(){
return {
}
},
// 2 挂载子组件 挂子
components:{
// 挂载组件的简写形式
App,
}
});
6.vue-router的使用
单页应用,看下图:(react、angular也都是做单页面应用,很多大型的网站像网易云音乐,豆瓣等都是react写的单页面应用)
6.1vue-router的下载安装及简单操作
官方地址:https://router.vuejs.org/zh/
下载vue-router的cnd链接地址:https://unpkg.com/vue-router/dist/vue-router.js
你也可以像 https://unpkg.com/vue-router@2.0.0/dist/vue-router.js
这样指定 版本号 或者 Tag。
官网简单操作:
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 下面两个组件可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
// 现在,应用已经启动了!
6.2简单实例
<div id="app">
<h1>你好</h1>
<App></App>
</div>
// 1. 定义 (路由) 组件
let Home = {
data(){
return {
msg:'这是home页面'
}
},
template:`
<div class="home">
<h1>{{msg}}</h1>
</div>
`
};
// 1. 定义 (路由) 组件
let Course = {
data(){
return {
msg:'这是Course页面'
}
},
template:`
<div class="course">
<h1>{{msg}}</h1>
</div>
`
};
let App = {
data(){
return {
}
},
//使用 router-link 组件来导航.
//通过传入 `to` 属性指定链接.
//<router-link> 默认会被渲染成一个 `<a>` 标签
template:
`
<div class="nav">
<router-link to="/home">首页</router-link>
<router-link to="/course">课程页</router-link>
<router-view></router-view>
</div>
`,
//路由出口
//路由匹配到的组件将渲染在这里
};
// 2. 定义路由
const routes = [
{path:'/home', component:Home},
{path:'/course', component:Course},
];
// 3. 创建 router 实例,然后传 `routes` 配置
let router = new VueRouter({
routes,// (缩写) 相当于 routes: routes
})
let vm = new Vue({
el:'#app',
router,
data(){
return {
}
},
// 2 挂载子组件 挂子
components:{
// 挂载组件的简写形式
App,
}
7.vue cli自动化工具
7.1 安装vue cli
Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。
nodejs下载地址:https://nodejs.org/en/download/
使用npm来安装vue-cli
npm install -g vue-cli
npm install -g vue-cli --registry https://registry.npm.taobao.org
npm config -g set registry https://registry.npm.taobao.org # 设置淘宝镜像
npm install -g @vue/cli
npm install -g @vue/cli-init # vue2.x版本需要安装桥接工具
7.2 创建一个vue项目
1 切换目录
2 创建一个项目
vue init webpack ceshi1
3 运行项目
npm run dev
7.3 项目目录结构
├── build/
├── config/
├── index.html
├── node_modules/ # 项目运行的依赖库存储目录[非常大]
├── package.json # 项目运行需要的依赖库记录配置
├── src/
│ ├── App.vue # 父级组件
│ ├── assets/ # 静态资源目录,图片存放在这里
│ ├── components/ # 单文件组件保存目录
│ └── main.js
└── static/ # 静态资源目录,所有的测试时用的,但是不需要交给线上服务器的css,js等文件放在这个目录
src 主开发目录,要开发的单文件组件全部在这个目录下的components目录下
static 静态资源目录,所有的css,js文件放在这个文件夹
dist 项目打包发布文件夹,最后要上线单文件项目文件都在这个文件夹中[后面打包项目,让项目中的vue组件经过编译变成js 代码以后,dist就出现了]
node_modules目录是node的包目录,
config是配置目录,id和端口等等
build是项目打包时依赖的目录
src/router 路由,后面需要我们在使用Router路由的时候,自己声明.