习题详解
用table表格标签渲染以上数据,表格第一列是学生总分
'''
...
...
<tr>
... # 表头字段
</tr>
<tr v-for="(score, i) in scores">
<td>{{i + 1}}</td> # 1
<td v-for="(v, k, i) in score">{{v}}</td> # Bob 97 89 67 253
</tr>
...
...
...
// 模拟页面加载成功, 从后台获取数据
`let scores = null;
$.ajax({
url: '',
success(response) {
scores = response.data
}
});`;
let scores = [
...
];
// // for in遍历的是取值索引或者key|for of 遍历的是值(字典除外)
// for (v in scores) {
// console.log(v) // 0 1 2 3 4
// }
for (score of scores) {
score.total = score.math + score.chinese + score.english
}
for (let i = 0; i < scores.length - 1; i++) {
for (let j = 0; j < scores.length - 1 - i; j++) {
if (scores[j].total < scores[j + 1].total) { // 总分排序
// 调整整个数据对象顺序
let temp = scores[j];
scores[j] = scores[j + 1];
scores[j + 1] = temp
}
}
}
new Vue({
...
data: {
// scores:scores
scores // 属性名与变量名相同可省略只写一个
},
...
})
...
'''
只渲染所有科目都及格了的学生
'''
<tr v-for="(score, i) in scores" v-if="score.math >= 60 && score.chinese >= 60 && score.english >= 60">
...
</tr>
'''
i)有三个按钮:语文、数学、外语,点击谁谁高亮,且当前筛选规则采用哪门学科
ii)两个输入框,[]~[],前面填最小分数,后面填最大分数,全部设置完毕后,表格的数据会被更新: 只渲染满足所有条件的结果
'''
<style>
.click {
background-color: pink;
}
</style>
<div id="app">
<button type="button" @click="subject = 'chinese'" :class="{click: subject === 'chinese'}">语文</button>
...
<p>
请输入分数段:
<input type="number" min="0" max="100" v-model="min">
~
<input type="number" min="0" max="100" v-model="max">
</p>
<table border="1" style="margin: auto"> # margin: auto, 居中
<tr>
<th>排名</th> # 添加排名字段
# 单独的v-if, 条件满足则渲染该标签, 不满足则不渲染该标签
<th v-for="(v, k, i) in scores[0]" v-if="k === 'name' || k === subject || !subject">{{k}}</th>
</tr>
<tr v-for="(score, i) in scores" v-if="(score[subject] >= +min && score[subject] <= +max) || (!max || !min)">
<td>{{i + 1}}</td>
<td v-for="(v, k, i) in score" v-if="k=== 'name' || k === subject || !subject">{{v}}</td> # 循环嵌套及v-if嵌套
</tr>
</table>
</div>
...
data: {
...
subject: '',
min: '',
max: '',
},
...
'''
组件介绍
组件: HTML + CSS + JS 封装的集合体, 组件具有复用性
组件分类
- 根组件: new Vue() 生成的组件
- 局部组件: 组件名 = {}, {} 内部采用的是vue语法
- 全局组件: Vue.component('组件名', {}), {}内部采用的是vue语法
组件都有管理其HTML页面结果的template实例成员
'''
<div id="app">
{{info}}
</div>
new Vue({
el: '#app', // 挂载点本质是被组件中的template成员指定的虚拟DOM替换的占位符
data: {
info: '根组件信息',
},
...
template: '<div>{{info}}</div>'
})
// 根组件可以不明确template, 此时template默认采用挂载点的HTML页面结构
// 如果设置了template, 挂载点的HTML页面结构失效
// 挂载点不能为body标签和html标签
'''
子组件
- 根组件都是作为最顶层的父组件, 局部与全局组件作为根组件的子组件, 组件间的父子关系是相对的
- 子组件间的数据是隔离的, 每一个子组件拥有自己独立的数据空间
- 局部组件必须注册后才能使用, 而全局组件不需要注册(提前加载到了内存中, 占用内存), 推荐使用局部组件(使用时才占用内存)
- 变量在哪个组件中出现就由该组件提供变量值并管理该变量
'''
# 样式复习
<style>
body {
margin: 0; /*取出浏览器页边留白*/
}
.box {
250px; /*调整图片宽度, 长度自动等比缩放*/
border-radius: 20px; /*图片四周设置20px圆角弧度*/
overflow: hidden; /*图片超出部分隐藏*/
background-color: aqua; /*设置图片及文字背景颜色*/
float: left;
margin: 10px;
}
.box img {
100%; /*设置图片宽度占比为父标签的100%*/
}
.box h2 {
margin: 0; /*取出标题标签与父标签留白*/
text-align: center; /*标题居中*/
}
.wrap {
1100px;
margin: 0 auto; /*标签居中*/
border: 3px solid red; /*标签边框样式*/
}
.wrap:after { /*清除浮动影响*/
content: '';
display: block;
clear: both;
}
</style>
'''
'''
<div id="app">
<div class="wrap">
<local-tag></local-tag> <!--能渲染-->
<local-Tag></local-Tag> <!--能渲染-->
<global-tag></global-tag>
</div>
</div>
let localTag = { // 定义局部组件, 需要在使用它的父组件中注册才能正常渲染
template: `
<div class="box" @click="fn">
<img src="img/444.jpg" alt="">
<h2>美女</h2>
</div>
`,
methods: {
fn() {
alert(123)
},
}
};
Vue.component('globalTag', { // 定义全局组件, 不需要注册就可以正常渲染
template: `
<div class="box">
<img src="img/555.jpg" alt="">
<h2>旺仔牛奶</h2>
</div>
`
});
new Vue({
...
components: {
// localTag: localTag, // css语法不识别大小写, js中的驼峰体对应css中的-
localTag // // 注册局部组件, 属性名与变量名相同时可省略只写一个
}
})
// 局部, 全局, 和根组件都是一个vue实例, 一个实例对应一套html, css, js结构
'''
组件数据局部化
类比
类比:
class A:
name = 'Owen'
def __init__(self, name): # 实例化一次自动执行一次__init__函数产生一个局部作用域
self.name = name
a1 = A('jason')
a2 = A('tank')
a1.name
a2.name
'''
let localTag = { // 定义局部组件, 需要在使用它的父组件中注册才能正常渲染
template: `
<div class="box" @click="fn">
<img src="img/444.jpg" alt="">
<h2>锤了美女{{count}}下</h2>
</div>
`,
methods: {
fn() {
this.count++
},
},
// data: function () {
// return {count: 0,} // 返回对象类型数据
// },
data() { // 简写形式, 局部或全局组件可能会被复用多次, 每次被渲染的组件都有自己独立的变量名称空间
return {count: 0}; // 执行方法会产生局部作用域, 所以方法的返回值作为局部化数据
},
};
'''
组件传参
父传子
- 子组件以字符串形式在props中自定义组件属性, 该字符串可以通过反射机制在子组件中以变量形式使用
- 子组件在父组件中渲染时, 会将父组件的对应变量绑定给子组件的自定义属性, 实现父组件向子组件传参
'''
<div id="app">
<div class="wrap">
<local-tag v-for="girl in girls" :xxx="girl"></local-tag>
</div>
</div>
<script>
let girls = [
{
name: '美女四号',
img_path: 'img/444.jpg',
},
...
];
let localTag = {
props: ['xxx',],
template: `
<div class="box">
<img :src="xxx.img_path" alt="">
<h2>{{xxx.name}}</h2>
</div>
`,
};
'''
子传父
- 子组件中的template中最多只能写一个根标签, 因为挂载点只能挂载一个标签
- 子组件中定义的事件, 事件是属于子组件的, 但事件绑定的方法由父组件实现
- 在子组件中通过
this.emit('自定义事件名', 参数)
控制自定义事件在子组件中触发的位置
'''
<div id="app">
<h1>{{h1}}</h1>
<h2>{{h2}}</h2>
<tag @action1="action1Fn" @action2="action2Fn"></tag> <!--方法action1Fn属于根组件, 由根组件实现, 事件action1属于子组件-->
</div>
let tag = {
template: `
<div>
主标题内容: <input type="text" v-model="input_h1" @input="h1Change">
子标题内容: <input type="text" v-model="input_h2">
</div>
`,
data() {
return {
input_h1: '',
input_h2: '',
};
},
methods: {
h1Change() {
this.$emit('action1', this.input_h1);
},
},
watch: {
input_h2() {
this.$emit('action2', this.input_h2);
},
},
};
new Vue({
el: '#app',
methods: {
action1Fn(a) {
if (!a) {
this.h1 = '主标题';
}
else {
this.h1 = a;
}
},
...,
},
components: {
tag
},
data: {
girls,
h1: '主标题',
h2: '子标题',
}
});
'''