vue组件
一、fetch
vue项目和后端交互,可以使用ajax
1、通过jq中的ajax实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">点击加载美女数据</button>
{{myText}}
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
myText: ''
},
methods: {
handleClick() {
$.ajax({
url: 'http://127.0.0.1:5000/',
method: 'get',
success: (data) => {
console.log(data)
this.myText = data
}
})
}
}
})
</script>
</html>
后端flask代码:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
# 跨域请求
res = make_response('hello_world')
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
2、fetch向后端发动请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">点击加载美女数据</button>
<br>
后端加载的数据:
<br>
姓名:{{name}}
<br>
年龄:{{age}}
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
name: '',
age: ''
},
methods: {
handleClick() {
fetch('http://127.0.0.1:5000/info').then(response => {
return response.json()
}).then(json => {
console.log('后端获取的json数据', json)
this.name = json.name
this.age = json.age
}).catch(ex => {
console.log('出了异常', ex)
})
}
}
})
</script>
</html>
后端代码:
from flask import Flask,make_response,jsonify
app=Flask(__name__)
@app.route('/info')
def info():
res=jsonify({'name':'jason','age':18})
# 这两行代码处理跨域
res=make_response(res)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
二、axios
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="js/vue.js"></script>
<title>Title</title>
</head>
<body>
<div id="box">
<button @click="handleClick">点击加载电影数据</button>
<ul>
<li v-for="item in datalist">
<p>影片名:{{item.name}}</p>
<p>导演:{{item.director}}</p>
<img :src="item.poster">
</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
datalist: [],
},
methods: {
handleClick() {
axios.get('http://127.0.0.1:5000/filminfo').then(res => {
console.log(res.data)
if (res.data.status === 0) {
this.datalist = res.data.data.films
}
})
}
}
})
</script>
</html>
后端flask代码:
from flask import Flask, make_response, jsonify
import json
app = Flask(__name__)
@app.route('/filminfo')
def film():
with open('db/film.json', 'rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res = make_response(res)
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
三、计算属性
# 1、直接在{{}}中写js代码, html中尽量少写js代码
# 2、使用函数 {{函数()}} 使用几次就会函数执行几次,影响效率
# 3、使用计算属性 当做变量来使用,多次使用只会执行一次,效率高
1、通过计算属性来实现人名首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<h1>直接在{{}} 中写js代码 </h1>
<p>{{name.substring(0,1).toUpperCase()+name.substring(1)}}</p>
<h1>函数</h1>
<p>{{upperName()}}</p>
<p>{{upperName()}}</p>
<p>{{upperName()}}</p>
<h1>计算属性</h1>
<p>{{getName}}</p>
<p>{{getName}}</p>
<p>{{getName}}</p>
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
name: 'jason'
},
methods: {
upperName() {
console.log('upperName函数执行了')
return this.name.substring(0, 1).toUpperCase() + this.name.substring(1)
}
},
computed: {
getName() {
console.log('计算属性执行')
return this.name.substring(0, 1).toUpperCase() + this.name.substring(1)
},
},
})
</script>
</html>
2、通过计算属性重写过滤小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" v-model="myInput" @input="handleChange"> {{myInput}}
<br>
<div>
<p v-for="data in new_arr">{{data}}</p>
</div>
</div>
</body>
<script>
new Vue({
el: '#box',
data: {
myInput: '',
arr: ['aabb', 'aadf', 'qwer', 'xyz'],
},
computed: {
new_arr() {
return this.arr.filter(item => {
return item.indexOf(this.myInput) > -1
})
}
}
})
</script>
</html>
四、虚拟dom与diff算法key的作用
# 1、vue使用的是虚拟dom,和真实的dom做替换,使用的算法是diff算法
# 2、diff算法的几种方案
- 分层级比较,只做同层级的对比
- 同key值比较(循环中尽量加key),出现新的key就插入
- 通组件对比:组件或者标签的比较去替换
五、组件化开发
1、组件化开发的介绍
# 1、组件
扩展html元素,封装可重用的代码,目的是复用
示例:
有一个轮播图,可以在很多的页面中使用,一个轮播有js、css、html,组件会把js,css,html放到一起,有逻辑,有样式,有html
# 2、分类
- 全局组件
- 局部组件
# 3、工程化以后,一个组件就是一个 xxx.vue
# 4、elementui 本质就是一堆组件,可以直接拿过来使用
2、定义并使用全局组件
# 注意:在组件中写data,需要写成函数的形式
# 示例:
data() {
return {isShow: true}
}
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<div @click="handleClick" :style="styleObj">根组件的div</div>
<mydiv></mydiv>
<h1>再来一遍</h1>
<mydiv></mydiv>
</div>
</body>
<script>
//创建组价对象(全局组件),mydiv是自定义的组件的名字
Vue.component('mydiv', {
template: `
<div>
<div style="background: green" v-if="isShow">mydiv组件的头部</div>
<div @click="handleClick">点击显示/消失</div>
</div>
`,
methods: {
handleClick() {
console.log('组件被点击了')
this.isShow = !this.isShow
}
},
data() {
return {isShow: true}
}
})
var vm = new Vue({
el: '#box',
data: {
isShow: true,
styleObj: {background: 'red', fontSize: '90px'}
},
methods: {
handleClick() {
console.log('根组件被点击了')
}
}
})
</script>
</html>
3、局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="js/vue.js"></script>
<title>Title</title>
</head>
<body>
<div id="box">
<child1></child1>
<child></child>
</div>
</body>
<script>
// 全局组件
Vue.component('child1', {
template: `
<div>
<div style="background: red" v-show="isShow">我是头部</div>
<div @click="handleClick">显示/消失</div>
</div>
`,
methods: {
handleClick() {
console.log('全局组件被点击了')
this.isShow = !this.isShow
}
},
data() {
return {
isShow: true
}
},
})
var vm = new Vue({
el: '#box',
data: {
isShow: true,
},
methods: {
handleClick() {
console.log('根组件被点击了')
}
},
// 创建局部组件
components: {
child: { // 组件名:child
template: `
<div @click="handleClick">{{name}}</div>
`, // 组件模板
methods: {
handleClick() {
console.log('局部组件被点击了')
}
},
data() {
return {
name: 'cc'
}
}
}
}
})
</script>
</html>
全局组件的点击事件和数据 和局部组件之间互相隔离:
4、总结:组件编写方式和vue实例的区别
# 1、自定义的组件需要一个 root element,一般报过在一个div中,和vue实例一样
# 2、父子组件的data是不共享的
# 3、组件可以有data,methods,computed....,但是data 必须是一个函数
代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="js/vue.js"></script>
<title>Title</title>
</head>
<body>
<div id="box">
<navbar></navbar>
{{aa}}
<!--aa是局部组件的数据,与box是不共享的,所以会报错-->
</div>
</body>
<script>
// 全局组件
Vue.component('navbar', {
template: `
<div>
<button @click="handleClick">点击显示</button>
我是navbar---{{aa}}
<button style="background: red">主页</button>
<br>
<child></child>
</div>
`,
methods: {
handleClick() {
console.log('nav nav')
},
},
components: {
child: {
template: `<button>全局组件的子组件</button>`
}
},
data() {
return {aa: 'cc'}
}
})
var vm = new Vue({
el: '#box',
data: {
name: 'cc',
}
})
</script>
</html>
补充:HTTP之跨域请求
HTTP协议本身是没有跨域请求的设置的,跨域请求的限制是浏览器为了安全考虑加上去的。
实际上,浏览器对于HTTP请求是直接发送给server
浏览器提供了2种方式来突破跨域请求的限制,
- 在sever返回的Response Head中添加Access-Control-Allow-Origin
- 浏览器不限制script标签、img标签、link标签的跨域请求。
对于现在的突破跨域请求的方式,比如使用JSONP方式,它的底层原理就是使用script标签。
对于一些可控的跨域请求,通常我们使用Access-Control-Allow-Origin头。
但是,使用这个头也有一些限制:
- 请求方法的限制: 默认的突破跨域请求的限制只支持GET、POST、HEAD方法,使用其他方法使用方式预请求。
- 自定义的头部信息: 默认的突破跨域限制的请求中,自定义的头部信息会被屏蔽掉,如果需要使用自定义的头部信息需要发送预请求。
- Content-Type: 默认的突破跨域限制的请求的response格式也有限制,只支持text/plain、multipart/form-data、application/x-www-form-urlencoded,如果需要其他格式,需要发送预请求。
预请求:
由于需要突破CORS跨域请求的限制,浏览器一般需要发送预请求。预请求就是为了验证是否可以发送跨域请求而先发送的,它的method是OPTIONS。得到200的响应后,如果在Response Head中设置了
Access-Control-Allow-Headers、Access-Control-Allow-Methods类型的值,浏览器拿到这些头部信息就会和真正需要发送的请求的头部进行比对,如果存在的话就可以发送真正的请求了。不然会报error。
可以设置Access-Control-Max-Age时间,在这个时间内再次发起相同的跨域请求时就不需要预请求了。