基础语法(3)
# axios
ajax是前后端交互的一个技术.
原生的js就可以实现发送ajax请求,但存在不同浏览器之间兼容性的问题. jquery实现的ajax了解决这个问题.
但在vue里不推崇使用jquery.. 所以在vue里一般使用第三方的axios模块实现向后端发送ajax请求!!
Ps: 第三方模块fetch 不是所有浏览器都支持, 无需掌握.
扩展: xml - json, 还有一个ProtoBuf(微服务中广泛应用,远程调用中会经常使用到)
服务网格istio
# 发送get请求
后端代码
这里使用flask来实现后端.. 因为简单的案例使用轻量的flask比较方便.
from flask import Flask, jsonify, make_response
app = Flask(__name__)
@app.route('/')
def index():
obj = make_response(jsonify({"name": "lqz", "age": 19}))
obj.headers['Access-Control-Allow-Origin'] = '*' # -- 在请求头里加入数据,解决跨域问题
return obj
if __name__ == '__main__':
app.run()
"""若是Django,也需要在请求头中进行配置
def index(request):
res = JsonResponse({"name":"lqz","age":19})
res['Access-Control-Allow-Origin'] = '*' # 允许任何域(协议+域名+端口)向我发送请求!
return res
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跟后端交互</title>
<script src="./js/vue.js"></script>
<!-- 引入axios的CDN -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">获取数据</button>
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
name: "",
age: 0,
},
methods: {
handleClick() {
// 用axios向后端发送get请求. res就是返回的数据
// 报错:csrf跨域问题.虽然前端和后端地址都是127.0.0.1,但端口号不一样. --浏览器的安全策略.
// 前后端混合发送get请求没有报错,是因为前后端的ip端口是同一个.
// 浏览器为啥要有这个安全策略?若无此策略,可只写前端去其它服务器偷数据.Hhh
// 解决:在后端处理跨域问题.需要往响应头里加东西.
axios.get('http://127.0.0.1:5000/').then(res => {
// 我们需要的数据/后端给的数据 在res这个对象的data属性里,no why.
console.log(res.data) // {age: 19, name: 'lqz'}
this.name = res.data.name
this.age = res.data.age
// 出了异常执行catche中的代码
}).catche(res=>{})
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 前端显示电影
a.json
{
"status": 0,
"data": {
"films": [
{
"filmId": 6165,
"name": "阿凡达:水之道",
"poster": "https://pic.maizuo.com/usr/movie/fceeb41a1660d097d02fbcbda3191d8f.jpg",
"actors": [
{
"name": "詹姆斯·卡梅隆",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/4da6b697aabe63657edd65aa1b660a04.jpg"
},
{
"name": "萨姆·沃辛顿",
"role": "杰克·萨利 Jake Sully",
"avatarAddress": "https://pic.maizuo.com/usr/movie/c0802754994c52632632fa14a9d8b2c6.jpg"
},
],
"director": "詹姆斯·卡梅隆",
"category": "动作|冒险|科幻",
},
{
"filmId": 6179,
"name": "绝望主夫",
"poster": "https://pic.maizuo.com/usr/movie/495ff91096e9de224acc3746ec42d002.jpg",
"actors": [
{
"name": "张琦",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/6a74150ccda394799bea5762f100a458.jpg"
},
{
"name": "郭祥鹏",
"role": "王富球",
"avatarAddress": "https://pic.maizuo.com/usr/movie/7560bab5eaef8e60ecfc333a49c082d8.jpg"
}
],
"director": "张琦",
"category": "喜剧",
}
],
"total": 21
},
"msg": "ok"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
后端代码
from flask import Flask, jsonify, make_response
import json
app = Flask(__name__)
@app.route('/')
def index():
with open('a.json', 'r', encoding='utf-8') as f:
res = json.load(f)
obj = make_response(jsonify(res))
obj.headers['Access-Control-Allow-Origin'] = '*'
return obj
if __name__ == '__main__':
app.run()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>显示电影</title>
<script src="./js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<ul>
<li v-for="item in dataList">
<p>电影标题 - {{item.name}}</p>
<p>电影主演 - {{item.director}}</p>
<img :src="item.poster" alt="" style="height: 100px">
</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
dataList: []
},
// 在生命周期函数create里向后端发送请求拿电影数据!
// 在mounted里发不好,因为mounted已经加载页面了,拿到数据后是更新.会消耗资源.
created() {
axios.get('http://127.0.0.1:5000/').then(res => {
console.log(res.data)
this.dataList = res.data.data.films
})
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 计算属性
计算属性是基于它们的依赖 进行缓存 的. 计算属性只有在它的相关依赖发生改变时才会重新求值.
这就意味着只要 msg2 未发生改变, 多次访问 getMsg 计算属性会立即返回之前的计算结果,而不必再次执行函数.在页面中出现多次,只会出现一次, 该方法当属性用!!方法内会return值.
既然当属性用,就可以v-for v-if
其实, 看官方文档是最直接的. 我看了一遍, 很好理解!! https://cn.vuejs.org/guide/essentials/computed.html
# 首字母大写
把用户输入的字符串首字母变大写并显示.
如果使用普通的方法去显示, 那么每次其他地方的数据更新时, 这个方法也会执行, why? (实验下来,确实如此.)
"即使用函数的方式实现, 只要页面更新/页面中有地方变化, 就会再次执行页面中有的函数!!"所以就需要用到计算属性..
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
{{one()}}
<!-- 方式一:直接在插值中使用js语法实现..-->
<input type="text" v-model="msg">
<p>js语法实现:{{msg.substring(0,1).toUpperCase()+msg.substring(1)}}</p>
<br>
<!-- 方式二:写成一个函数..-->
<!-- getMsg函数返回什么,这里就显示什么.-->
<input type="text" v-model="msg1">
<p>{{getMsgMethod()}} {{getMsgMethod()}}</p>
<br>
<!-- 方式三:使用计算属性..-->
<input type="text" v-model="msg2">
<p>{{getMsg}} {{getMsg}}</p>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
msg: "lqz",
msg1: "dc",
msg2: "egon",
},
methods: {
getMsgMethod() {
console.log('func do.')
return this.msg1.substring(0, 1).toUpperCase() + this.msg1.substring(1)
},
one() {
console.log('hello')
}
},
computed: {
getMsg() { // 依赖的状态改变了,才会重新计算 getMsg这个计算属性相关的依赖就是msg2这个变量
console.log('attr do.')
return this.msg2.substring(0, 1).toUpperCase() + this.msg2.substring(1)
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
注意观察, html中代码写了两个 {/{getMsg}},但只打印了一个 ‘attr do’. 证明, 计算属性相对于函数的方式节约了资源!!
Ps: 针对截图中的疑问, 不用纳闷纠结为什么, 只需要知道用函数方式实现, 很耗费资源, 所以就有了计算属性!!
# 过滤案例
通过计算属性重写过滤案例
相比以前的写法.
1> 不需要在input标签中写@input事件,因为 相关依赖改变, 计算属性会重新执行一遍!
2> 不需要额外定义newDataList变量.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤案例</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
{{datalist}}
<p><input type="text" v-model="my_text"></p>
<ul>
<!-- 计算属性newList,newList函数返回啥,newList就是啥 -->
<li v-for="data in newList">{{data}}</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
my_text: '',
datalist: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac'],
},
computed: {
newList() {
/*
let newList = this.datalist.filter(item => {
return item.indexOf(this.my_text) > -1
})
return newList
*/
// 只要input框中my_text数据发生变化,newList就会重新计算
// 只要一重新运算,虚拟dom会重新渲染补丁,v-for重新循环,实现联动.
return this.datalist.filter(item => item.indexOf(this.my_text) > -1)
},
},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 修改计算属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
firstText: <input type="text" v-model="firstText"> <br>
lastText: <input type="text" v-model="lastText"> <br>
computed Only read: <input type="text" v-model="mergeText1"> <br>
computed Read And write: <input type="text" v-model="mergeText2">
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
firstText: "Hello",
lastText: "world",
},
computed: {
mergeText1() {
return this.firstText + ' ' + this.lastText;
},
mergeText2: {
get() {
return this.firstText + ' ' + this.lastText;
},
set(newValue) {
console.log(newValue);
[this.firstText, this.lastText] = newValue.split(' ')
}
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 监听属性
监听属性, 即vue对象中data中的变量发生了变化就会执行对应函数, 函数名要用变量名.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>监听属性</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" v-model="name">
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
name: ""
},
watch: {
name() {
console.log('name值发生了变化')
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
应用场景: 分类筛选时使用.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>监听属性</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<span @click="categoryType='美女'">美女</span> |
<span @click="categoryType='帅哥'">帅哥</span> |
<span @click="categoryType='其他'">其他</span>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
categoryType: ""
},
watch: {
categoryType(val) {
console.log('categoryType值发生了变化')
console.log(val)
// ★ 在此处向后端发送请求,得到相应分类的数据,在页面上通过for循环进行展示!!
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 组件化开发
1> 自定义组件需要有一个root element, 一般包裹在一个div中 模版的内容有且仅只能包裹在一个标签里
2> 父子组件的data是无法共享 -- 所以需要 组件通信 !
3> 组件可以有data,methods,computed等, 但是data 必须是一个函数
经过实验, 根组件vm要写在子组件后面.. 别问为啥, 就是这么一个现象.
# 全局组件
全局组件即整个页面中都可以使用的组件. 注意,多次复用的话,它们是相互隔离,互不影响的!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box1">
<child></child>
<br>
<child></child>
</div>
<div id="box2">
<child></child>
</div>
</body>
<script>
obj = {
// ★ 注意 - 模版的内容有且仅只能包裹在一个标签里!!当然不一定非得是div.
template: `
<div>
<h3>我是子组件</h3>
<button @click="handleClick">点击我!-{{ name }}</button>
</div>
`,
// ★ data必须是个函数,只不过这里用es6语法简写了, data:function(){}
// ★ 并且该函数必须返回一个对象!
/* why?
因为该组件可以在多个地方使用,若data是一个对象,那么这多个地方使用的是同一个引用/同一内存地址,数据容易混乱
但若写成函数,每次都返回一个新的对象/一份新的数据,就不会出现数据混乱的问题!!
*/
data() { // 相当于vue实例中的data
return { // return里面写变量
name: 'lqz'
}
},
methods: {
handleClick() { // 其余的定义与vue实例一样
console.log('Hello World!')
}
}
}
// -- 定义一个全局组件
// 参数一:组件名字;参数二:传一个对象(有模版、数据、方法、生命周期钩子函数、计算属性等),此处单独提出来写了.
Vue.component('child', obj)
let vm1 = new Vue({
el: '#box1',
data: {},
})
let vm2 = new Vue({
el: '#box2',
data: {},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 局部组件
局部组件只能在某个组件中使用,即定义它的vue对象绑定的标签中使用.
示例代码是在全局组件中定义了一个局部组件, 当然你可以在 vue实例中定义一个局部组件!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<child></child>
</div>
</body>
<script>
// 在全局组件中定义一个局部组件
Vue.component('child', {
template: `
<div>
<h3>我是子组件</h3>
<button @click="handleClick">点击我!-{{name}}</button>
<header1></header1>
</div>
`,
data() {
return {
name: 'lqz'
}
},
methods: {
handleClick() {
console.log('Hello World!')
}
},
// 定义局部组件,可以写多个.
// 此处的局部组件只能在名为'child'的全局组件中使用
/* 举一反三:
在该名为header1的局部组件中,再定义一个名为header2的局部组件
那么名为header2的局部组件《只能在header1的局部组件的模版中》通过<header2></header2>的方式使用*/
components: {
// 'header1'的引号可省略.
'header1': {
template: `<h6>我是局部组件!-{{msg}}</h6>`,
data() {
return {
msg:'SB.'
}
},
methods: {},
}
}
})
let vm = new Vue({
el: '#box',
data: {},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 组件通信
# 父子通信之父传子
通过 自定义属性 实现!
需求: 子组件child中想使用vm父组件中的数据msg和age.
直接在子组件child中通过{//{msg}}、{//{age}}来调用,是会报错的,报错没有定义.
step1: 在子组件标签上自定义一个属性,属性名随便起,通过属性指令绑定父组件中的一个变量.
step2: 在子组件中定义一个props,它是一个数组,在其中进行注册,写子组件标签上["自定义的属性名"]
.
step3: 可通过{\{自定义的属性名}}
的方式在子组件中使用!
此处在子组件中注册了两个变量my_msg、my_age, 对应父组件中的msg、age!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父传子</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 在组件上自定义属性,通过属性指令绑定好变量!-->
<child :my_msg="msg" :my_age="age"></child>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
<h3>我是子组件</h3>
父组件传递到子组件的内容是:>><br>
{{my_msg}} .. {{my_age}}
</div>
`,
methods: {},
// 在props进行注册
props: ['my_msg', 'my_age'],
// ★ 扩展:还可以写成对象形式,进行属性认证,限制自定义属性类型
// 若父组件传递过来的数据不是指定的类型,会warn.但也会显示.
// props: {
// my_msg: String, // 意味着接受父组件传过来的my_msg,必须是String类型的数据!!S是大写的!!
// my_age: Number,
// }
})
let vm = new Vue({
el: '#box',
data: {
msg: "我是父组件的数据!",
age: 19,
},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 父子通信之子传父
通过 自定义事件 实现!
step1: 在子组件标签上自定义一个事件,该事件绑定一个函数; 固定写法 @自定义事件名="函数名"
(该事件函数是编写在父组件里的)
该函数定义在父组件里,定义时需要接受子组件传递过来的参数.子组件传递了几个参数该函数定义时就有多少个形参!
step2: 点击子组件中的按钮, 在该点击事件中, 触发父组件中自定义事件对应函数的执行,并且传入当前子组件需要传给父组件的变量.
如何实现呢? 固定写法 this.$emit('自定义事件名', 自定义事件绑定方法所需参数1, 参数2)
# 事例1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box" style="border: 1px solid red;width: 270px;height: 250px">
<h4>父组件接受到子组件传递的值:{{parentName}}</h4>
<!-- myevent是随便起的一个事件名,其值直接写函数名即可!! -->
<!--
虽然handleReceive函数需要接受值,但这里写成handleReceive(childName)不得行!!
因为父组件中没有childName变量,会报错未定义.
经过实验,这里写成handleReceive()也不得行!! ★ so,切记,子传父时,此处写个函数名即可!固定用法.
-->
<child @myevent="handleReceive"></child>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div style="border: 1px solid orange;width: 250px;height: 160px;margin-left: 10px">
<input type="text" v-model="childName"> --> {{ childName }}
<br>
<button @click="handleClick">点击我</button>
<br>
<div style="color: lightcoral">
1> 输入框中输入值,输入框里的内容双向绑定到子组件的childName变量里 <br>
2> 再点击按钮,将该变量传递给父组件!
</div>
</div>
`,
data() {
return {
childName: ""
}
},
methods: {
handleClick(childName) {
// 点击该按钮,触发父组件中自定义事件handleReceive的执行,并且传入当前子组件中的变量childName
// 如何做? 记住,固定写法 this.$emit('自定义事件名', 自定义事件绑定方法所需参数1, 参数2)
this.$emit('myevent', this.childName)
}
}
})
new Vue({
el: '#box',
data: {
parentName: ""
},
methods: {
handleReceive(childName) {
this.parentName = childName
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 事例2
需求: 想点击按钮,让子组件消失.Hhh -- 普通方式;子传父的方式.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<div>
<!-- **普通方式-->
<button @click="isShow_0=!isShow_0">点击隐藏显示</button>
<child v-show="isShow_0"></child>
</div>
<div>
<!-- **子传父方式-->
<!-- 通过自定义事件实现,事件名随便起,事件绑定方法 -->
<!-- ★ 注意:尽管绑定的方法需要参数,这里也只写方法名即可,子组件会传过去的!! -->
<child v-if="isShow" @myevent="handleShow"></child>
</div>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
<h3>我是子组件</h3>
<button @click="handleClick">点击子组件消失.</button>
</div>
`,
data() {
return {
b: false
}
},
methods: {
handleClick() {
// 想点击子组件里的按钮,触发父组件中子组件标签里自定义的myevent事件的执行!!
// myevent绑定的函数需要几个参数,就可以传几个参数
this.$emit('myevent', this.b) // 把子组件中的变量b传入myevent事件对应的方法中
// this.$emit('myevent', false) // 直接传递bool值false
}
},
})
let vm = new Vue({
el: '#box',
data: {
isShow_0: true,
isShow: true,
},
methods: {
handleShow(b) {
this.isShow = b
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# ref属性
在Vue中通过
this.$refs.ref属性的属性值
拿到的是:
如果 普通标签 设置ref属性, 拿到的就是 原生节点/普通标签本身, 可以执行原生的dom操作; (用的很少)
如果 子组件 设置ref属性, 拿到的就是 子组件对象
- 即通过子组件对象.直接获取修改子组件的变量,直接执行子组件的方法,子组件的方法有参数就传值,有返回值就接收.
ref属性很常用,也很好用.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ref属性</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" ref="myinput" name="lqz" v-model="msg">
<child ref="mychild"></child>
<button @click="handleClick">点击我试一试!</button>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
<h3>我是子组件</h3>
{{b}}
</div>
`,
data() {
return {
b: true
}
},
methods: {
handle1(msg){
console.log('执行子组件的方法handle1!')
console.log(msg)
return 'hello'
}
},
})
let vm = new Vue({
el: '#box',
data: {
msg: 'Hello',
xxx: '',
},
methods: {
handleClick() {
// -- 放到普通标签上
// this.$refs.myinput就是input标签
console.log(this.$refs.myinput) // <input type="text" name="lqz">
// 可以拿到input框里的内容和input的name属性的值 -- 原生js就支持这么做
console.log(this.$refs.myinput.value, this.$refs.myinput.name) // Hello lqz
// -- 放到子组件标签上
// this.$refs.mychild就是子组件对象,相当于拿到了子组件中的this!! 就无需纠结子传父还是父传子了.
console.log(this.$refs.mychild)
// 拿到子组件对象中的变量
console.log(this.$refs.mychild.b) // true
// 可以改子组件对象中的变量的值
this.$refs.mychild.b = !this.$refs.mychild.b
// 当然可以将子的b给了父的xxx
this.xxx = this.$refs.mychild.b
// 在父组件中直接调用子组件对象的方法 传值,接收返回值
let res = this.$refs.mychild.handle1("致命打鸡")
console.log(res)
}
}
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 动态组件
# 基本使用
动态切换组件主要通过component配合is属性, 决定哪一个组件显示.
<component :is='组件名'></component>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动态组件</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box" style="margin: 10px">
<button @click="who='index'">首页</button>
<button @click="who='girl'">美女</button>
<button @click="who='boy'">帅哥</button>
<div style="border: orange 1px solid;width: 123px;height: 50px;margin-top: 10px">
<!-- 可以用v-if来实现组件的显示与否,但这种方式不好,我们可以用动态组件来实现 -->
<!-- is属性的值是哪个组件名,就显示哪个组件的内容! -->
<component :is="who"></component>
</div>
</div>
</body>
<script>
Vue.component('index', {template: `<div>这是首页</div>`,})
Vue.component('girl', {template: `<div>这是美女页面</div>`,})
Vue.component('boy', {template: `<div>这是帅哥页面</div>`,})
new Vue({
el: '#box',
data: {
who: 'index'
},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
PS: 该需求的实现方案有很多, 比如还可以通过 if-else来实现, 但不如 动态组件写起来简便.
# keep-alive的使用
页面内容保留.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>keep-alive</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box" style="margin: 10px">
<button @click="who='index'">首页</button>
<button @click="who='girl'">美女</button>
<button @click="who='boy'">帅哥</button>
<div style="border: orange 1px solid;width: 158px;height: 50px;margin-top: 10px">
<keep-alive>
<component :is="who"></component>
</keep-alive>
</div>
</div>
</body>
<script>
Vue.component('index', {template: `<div>这是首页</div>`,})
Vue.component('girl', {
template: `<div>这是美女页面 <input type="text"></div>`,
})
Vue.component('boy', {template: `<div>这是帅哥页面</div>`,})
new Vue({
el: '#box',
data: {
who: 'index'
},
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# slot插槽
# 不具名插槽
默认插槽: 将子组件标签包裹的所有内容,放到solt标签所在的位置!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<home>
<!-- 若无插槽,子标签里的html代码是不会在页面上显示的 -->
<div>人类终将毁灭,世界属于三体.</div>
</home>
<hr>
<home>
<!-- 若无插槽,子标签里的html代码是不会在页面上显示的 -->
<div>愿我一生欢喜,不为世俗所及.</div>
</home>
</div>
</body>
<script>
Vue.component('home', {
template:`
<div>
<h4>This is home.</h4>
<slot></slot>
</div>
`
})
new Vue({
el: '#box',
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 具名插槽
标签属性slot的值对应slot标签name属性的值!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插槽</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<home>
<div slot="top">哇哦!</div>
<div slot="bottom">起飞!</div>
<!-- PS:若无不具名插槽,那么该行代码不会在页面上渲染显示出来;有不具名插槽的话,会显示在不具名插槽处! -->
<div>...</div>
</home>
</div>
</body>
<script>
Vue.component('home', {
template:`
<div>
<slot name="top"></slot>
<h4>This is home.</h4>
<slot name="bottom"></slot>
</div>
`
})
new Vue({
el: '#box',
})
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32