基础语法
v-for
该指令可以用来遍历数组或对象
渲染列表-原生做法
代码示例
<ul>
</ul>
food = [
{
id: 0, name: "牛肉", price: 49 },
{
id: 1, name: "五花肉", price: 35 },
{
id: 2, name: "老母鸡", price: 29 },
{
id: 3, name: "生蚝", price: 69 },
{
id: 4, name: "龙虾", price: 18 }
]
let lis = ''
food.forEach((item,index) => {
lis += `<li>${food[index].name} ${food[index].price}</li>`
})
document.querySelector('ul').innerHTML = lis
渲染列表-Vue做法
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-for</title>
<script src="vue.js"></script>
</head>
<body bgcolor="pink">
<div id="app">
<h1>今日菜单</h1>
<ul>
<li v-for="item in foods"> 菜名:{
{item.name}} 价格:{
{item.price}} </li>
</ul>
<hr>
<h2>今日新闻</h2>
<ul>
<!-- 数组元素,元素下标 -->
<li v-for="(lis,index) in news">{
{index + 1}}-新闻:{
{lis.new}}</li>
</ul>
<hr>
<h1>今日人物</h1>
<ul>
<li v-for="value in user">
{
{value}}
</li>
</ul>
<hr>
<h1>今日动物</h1>
<ul>
<!-- 属性值,属性名,下标索引 -->
<li v-for="(value,key,index) in fish">{
{index + 1}}-{
{key}}:{
{value}}</li>
</ul>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
foods: [
{
id: 0, name: "牛肉", price: 49 },
{
id: 1, name: "五花肉", price: 35 },
{
id: 2, name: "老母鸡", price: 29 },
{
id: 3, name: "生蚝", price: 69 },
{
id: 4, name: "龙虾", price: 18 }
],
news: [
{
id: 0, new: "日本省爆炸" },
{
id: 1, new: "美国省爆炸" },
{
id: 2, new: "台湾省爆炸" },
{
id: 3, new: "乌克兰省爆炸" },
{
id: 4, new: "俄罗斯省爆炸" },
],
user: {
name: "吴亦凡",
age: "18",
sex: "男"
},
fish: {
name: "小金鱼",
city: "共青城",
num: 1000
}
}
})
</script>
</body>
</html>
效果图例
key 的原理
面试题:react、vue中的key有什么作用?(key的内部原理)
- 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key,则创建新的真实DOM,随后渲染到到页面。①.若虚拟DOM中内容没变, 直接使用之前的真实DOM! ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
- 用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
- 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
- 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
怎么用呢
组织架构管理:实现一个组织架构管理系统,展示公司内部的组织结构关系,包括部门、员工、上下级关系等。使用树形结构来展示组织架构,并实现相关功能,如添加、删除、编辑部门或员工信息。
<template>
<div>
<h1>组织架构管理系统</h1>
<!-- 添加部门 -->
<form @submit.prevent="addDepartment">
<label for="departmentName">部门名称:</label>
<input type="text" id="departmentName" v-model="newDepartmentName" required>
<button type="submit">添加部门</button>
</form>
<!-- 添加员工 -->
<form @submit.prevent="addEmployee">
<label for="employeeName">员工姓名:</label>
<input type="text" id="employeeName" v-model="newEmployeeName" required>
<label for="departmentSelect">所属部门:</label>
<select id="departmentSelect" v-model="newEmployeeDepartment" required>
<option v-for="department in departments" :key="department.id" :value="department.id">{
{ department.name }}</option>
</select>
<button type="submit">添加员工</button>
</form>
<!-- 展示组织架构 -->
<h2>组织架构</h2>
<ul>
<li v-for="department in departments" :key="department.id" class="department">
<div>
{
{ department.name }}
<button @click="deleteDepartment(department.id)">删除部门</button>
</div>
<ul>
<li v-for="employee in department.employees" :key="employee.id" class="employee">
{
{ employee.name }}
<button @click="deleteEmployee(employee.id)">删除员工</button>
</li>
</ul>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
departments: [
{
id: 1,
name: '技术部',
employees: [
{
id: 1, name: '张三' },
{
id: 2, name: '李四' }
]
},
{
id: 2,
name: '市场部',
employees: [
{
id: 3, name: '王五' },
{
id: 4, name: '赵六' }
]
}
],
newDepartmentName: '',
newEmployeeName: '',
newEmployeeDepartment: ''
};
},
methods: {
addDepartment() {
const newDepartment = {
id: this.departments.length + 1,
name: this.newDepartmentName,
employees: []
};
this.departments.push(newDepartment);
this.newDepartmentName = '';
},
deleteDepartment(departmentId) {
const index = this.departments.findIndex(d => d.id === departmentId);
if (index !== -1) {
this.departments.splice(index, 1);
}
},
addEmployee() {
const newEmployee = {
id: Math.floor(Math.random() * 1000),
name: this.newEmployeeName
};
const department = this.departments.find(d => d.id === Number(this.newEmployeeDepartment));
if (department) {
department.employees.push(newEmployee);
}
this.newEmployeeName = '';
this.newEmployeeDepartment = '';
},
deleteEmployee(employeeId) {
for (let department of this.departments) {
const index = department.employees.findIndex(e => e.id === employeeId);
if (index !== -1) {
department.employees.splice(index, 1);
break;
}
}
}
}
};
</script>
<style>
.department {
margin-bottom: 10px;
}
.employee {
margin-left: 20px;
}
</style>
在数据部分,我们定义了一个 departments 数组,用于存储部门信息。每个部门包含一个 id、name 和 employees 字段,其中 employees 是一个员工数组,用于存储所属该部门的员工信息。
在模板中,我们使用表单和按钮实现了添加部门和添加员工的功能。使用 v-for 指令循环渲染部门和员工的列表,并使用 v-model 指令双向绑定输入框的值。
在方法部分,我们实现了 addDepartment、deleteDepartment、addEmployee 和 deleteEmployee 四个方法,分别用于添加部门、删除部门、添加员工和删除员工的功能。
可以通过在输入框中输入相应的部门名称和员工姓名来添加新的部门和员工。点击 "删除部门" 或 "删除员工" 按钮可以将相应的部门或员工从组织架构中删除。
客户关系管理:开发一个客户关系管理系统,用于管理和跟踪客户信息、交流记录、销售机会等。设计一个客户信息表格,并添加搜索、排序、筛选等功能,以便用户可以方便地管理和查找客户信息。
<template>
<div>
<h1>客户关系管理系统</h1>
<!-- 添加客户 -->
<form @submit.prevent="addCustomer">
<label for="customerName">客户姓名:</label>
<input type="text" id="customerName" v-model="newCustomerName" required>
<label for="customerEmail">客户邮箱:</label>
<input type="email" id="customerEmail" v-model="newCustomerEmail" required>
<button type="submit">添加客户</button>
</form>
<!-- 搜索、排序和筛选 -->
<div>
<label for="searchInput">搜索:</label>
<input type="text" id="searchInput" v-model="searchKeyword">
<label for="sortSelect">排序:</label>
<select id="sortSelect" v-model="sortKey">
<option value="">无</option>
<option value="name">姓名</option>
<option value="email">邮箱</option>
</select>
<label for="filterSelect">筛选:</label>
<select id="filterSelect" v-model="filterKey">
<option value="">无</option>
<option value="highPotential">高潜力客户</option>
<option value="newCustomer">新客户</option>
</select>
</div>
<!-- 客户信息表格 -->
<table>
<thead>
<tr>
<th>姓名</th>
<th>邮箱</th>
<th>交流记录</th>
<th>销售机会</th>
</tr>
</thead>
<tbody>
<tr v-for="customer in filteredCustomers" :key="customer.id">
<td>{
{ customer.name }}</td>
<td>{
{ customer.email }}</td>
<td><button @click="addCommunicationRecord(customer.id)">添加记录</button></td>
<td><button @click="addSalesOpportunity(customer.id)">添加机会</button></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
customers: [
{
id: 1, name: '张三', email: 'zhangsan@example.com', highPotential: true, newCustomer: false },
{
id: 2, name: '李四', email: 'lisi@example.com', highPotential: false, newCustomer: true },
{
id: 3, name: '王五', email: 'wangwu@example.com', highPotential: true, newCustomer: true }
],
newCustomerName: '',
newCustomerEmail: '',
searchKeyword: '',
sortKey: '',
filterKey: ''
};
},
computed: {
filteredCustomers() {
let customers = this.customers;
// 根据搜索关键词筛选
if (this.searchKeyword) {
const keyword = this.searchKeyword.toLowerCase();
customers = customers.filter(customer =>
customer.name.toLowerCase().includes(keyword) ||
customer.email.toLowerCase().includes(keyword)
);
}
// 根据排序键和筛选键排序
if (this.sortKey) {
customers = customers.sort((a, b) => a[this.sortKey].localeCompare(b[this.sortKey]));
}
if (this.filterKey) {
customers = customers.filter(customer => customer[this.filterKey]);
}
return customers;
}
},
methods: {
addCustomer() {
const newCustomer = {
id: this.customers.length + 1,
name: this.newCustomerName,
email: this.newCustomerEmail,
highPotential: false,
newCustomer: true
};
this.customers.push(newCustomer);
this.newCustomerName = '';
this.newCustomerEmail = '';
},
addCommunicationRecord(customerId) {
// 添加交流记录的逻辑,您可以根据实际需求进行扩展
console.log(`添加客户(ID: ${
customerId})的交流记录`);
},
addSalesOpportunity(customerId) {
// 添加销售机会的逻辑,您可以根据实际需求进行扩展
console.log(`添加客户(ID: ${
customerId})的销售机会`);
}
}
};
</script>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ccc;
}
button {
padding: 5px 10px;
}
</style>
在数据部分,我们定义了一个 customers 数组,用于存储客户信息。每个客户包含一个 id、name、email 以及可选的 highPotential(高潜力客户)和 newCustomer(新客户)字段。
在模板中,我们使用表单实现了添加客户的功能。使用 v-model 指令双向绑定输入框的值。
在搜索、排序和筛选部分,我们使用输入框和下拉框实现了搜索、排序和筛选功能。使用计算属性 filteredCustomers 对客户列表进行搜索、排序和筛选,并在表格中展示结果。
在客户信息表格部分,我们使用
<table>
标签以及v-for
指令循环渲染客户列表,并在每行最后一列添加了 "添加记录" 和 "添加机会" 的按钮。您可以根据实际需求,在点击这些按钮时执行相应的操作。
项目管理:创建一个项目管理工具,用于团队协作、任务分配和进度跟踪。实现一个看板视图,将项目分为不同的阶段(如待办、进行中、已完成),并允许用户拖动任务卡片以更新状态。此外,还可添加评论、附件上传等功能,以促进团队协作。
<template>
<div>
<h1>项目管理工具</h1>
<!-- 添加任务 -->
<form @submit.prevent="addTask">
<label for="taskTitle">任务标题:</label>
<input type="text" id="taskTitle" v-model="newTaskTitle" required>
<button type="submit">添加任务</button>
</form>
<!-- 看板视图 -->
<div class="board">
<div class="column" v-for="column in columns" :key="column.id">
<h2>{
{ column.title }}</h2>
<div class="tasks" @drop="dropTask(column.id)" @dragover.prevent>
<div
v-for="task in getTasksByColumnId(column.id)"
:key="task.id"
:data-task-id="task.id"
draggable="true"
@dragstart="dragTask($event, column.id)"
>
<h4>{
{ task.title }}</h4>
<p>{
{ task.description }}</p>
<div>
<button @click="showComments(task.id)">查看评论</button>
<input type="file" @change="uploadAttachment($event, task.id)">
</div>
</div>
</div>
</div>
</div>
<!-- 评论弹窗 -->
<div v-if="selectedTaskId !== null">
<h3>任务评论</h3>
<ul>
<li v-for="comment in getCommentsByTaskId(selectedTaskId)" :key="comment.id">{
{ comment.content }}</li>
</ul>
<textarea v-model="newComment" placeholder="添加评论"></textarea>
<button @click="addComment">提交评论</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
columns: [
{
id: 1, title: '待办' },
{
id: 2, title: '进行中' },
{
id: 3, title: '已完成' }
],
tasks: [
{
id: 1, title: '任务1', description: '任务1的描述', columnId: 1 },
{
id: 2, title: '任务2', description: '任务2的描述', columnId: 2 },
{
id: 3, title: '任务3', description: '任务3的描述', columnId: 3 }
],
comments: [
{
id: 1, taskId: 1, content: '任务1的评论1' },
{
id: 2, taskId: 1, content: '任务1的评论2' },
{
id: 3, taskId: 2, content: '任务2的评论1' }
],
newTaskTitle: '',
selectedTaskId: null,
newComment: ''
};
},
methods: {
addTask() {
const newTask = {
id: this.tasks.length + 1,
title: this.newTaskTitle,
description: '',
columnId: 1
};
this.tasks.push(newTask);
this.newTaskTitle = '';
},
dragTask(event, columnId) {
event.dataTransfer.setData('text/plain', event.target.dataset.taskId);
event.dataTransfer.setData('text/plain', columnId);
},
dropTask(columnId) {
const taskId = parseInt(event.dataTransfer.getData('text/plain'));
const currentColumnId = parseInt(event.dataTransfer.getData('text/plain'));
const task = this.tasks.find(task => task.id === taskId);
if (task && currentColumnId !== columnId) {
task.columnId = columnId;
}
},
showComments(taskId) {
this.selectedTaskId = taskId;
},
addComment() {
const newComment = {
id: this.comments.length + 1,
taskId: this.selectedTaskId,
content: this.newComment
};
this.comments.push(newComment);
this.newComment = '';
},
uploadAttachment(event, taskId) {
const attachmentFile = event.target.files[0];
// 处理上传附件的逻辑,您可以根据实际需求进行扩展
console.log(`上传任务(ID: ${taskId})的附件:${attachmentFile.name}`);
},
getTasksByColumnId(columnId) {
return this.tasks.filter(task => task.columnId === columnId);
},
getCommentsByTaskId(taskId) {
return this.comments.filter(comment => comment.taskId === taskId);
}
}
};
</script>
<style>
.board {
display: flex;
gap: 20px;
}
.column {
width: 300px;
padding: 10px;
background-color: #eee;
}
.tasks {
min-height: 100px;
background-color: #fff;
padding: 10px;
}
.tasks > div {
margin-bottom: 10px;
background-color: #fff;
border: 1px solid #ccc;
padding: 10px;
}
h1, h2, h3, h4 {
margin-top: 0;
}
ul {
padding-left: 20px;
}
textarea {
width: 100%;
height: 100px;
margin-bottom: 10px;
}
</style>
在数据部分,我们定义了 columns 数组,用于存储不同阶段的列信息,每个列包含一个 id 和 title 字段。
我们还定义了 tasks 数组,用于存储任务信息。每个任务包含一个 id、title、description 和 columnId 字段,表示任务的标题、描述和所属列的ID。
我们还定义了 comments 数组,用于存储任务的评论信息。每个评论包含一个 id、taskId 和 content 字段,表示评论的ID、所属任务的ID和评论的内容。
在模板中,我们使用表单实现了添加任务的功能。使用 v-model 指令双向绑定输入框的值。
在看板视图部分,我们使用 v-for 指令循环渲染列和任务卡片,并使用 HTML5 的拖放功能实现了拖动任务卡片的功能。当任务卡片被拖动到不同的列时,其所属列会更新。
在评论弹窗部分,我们根据用户选择的任务ID显示相应的评论,并提供了文本框和按钮来添加新评论。
另外,我们还为每个任务卡片添加了 "查看评论" 的按钮,以及用于上传附件的文件输入框。您可以根据实际需求,在点击这些按钮和上传附件时执行相应的操作。
在线购物平台:构建一个在线购物平台,包括产品目录、购物车、订单管理等功能。设计一个产品列表,允许用户按照分类、价格范围等条件进行筛选和排序。用户可以将产品添加到购物车,并在结账时管理订单。
<template>
<div>
<h1>在线购物平台</h1>
<!-- 筛选和排序 -->
<div>
<label for="category">分类:</label>
<select id="category" v-model="selectedCategory">
<option value="">全部</option>
<option v-for="category in categories" :value="category">{
{ category }}</option>
</select>
<label for="priceRange">价格范围:</label>
<select id="priceRange" v-model="selectedPriceRange">
<option value="">全部</option>
<option value="0-50">0 - 50</option>
<option value="50-100">50 - 100</option>
<option value="100-200">100 - 200</option>
</select>
<label for="sortBy">排序方式:</label>
<select id="sortBy" v-model="selectedSortBy">
<option value="name">名称</option>
<option value="price">价格</option>
</select>
</div>
<!-- 产品列表 -->
<div class="product-list">
<div v-for="product in filteredProducts" :key="product.id">
<h3>{
{ product.name }}</h3>
<p>价格:{
{ product.price }}</p>
<button @click="addToCart(product)">添加到购物车</button>
</div>
</div>
<!-- 购物车 -->
<div>
<h2>购物车</h2>
<ul>
<li v-for="item in cartItems" :key="item.product.id">
{
{ item.product.name }} - 数量:{
{ item.quantity }}
<button @click="removeFromCart(item)">移除</button>
</li>
</ul>
<p>总计:{
{ getTotalPrice() }}</p>
<button @click="checkout">结账</button>
</div>
<!-- 订单管理 -->
<div v-if="orders.length > 0">
<h2>订单管理</h2>
<ul>
<li v-for="order in orders" :key="order.id">
订单ID:{
{ order.id }} - 总计:{
{ order.totalPrice }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
categories: ['电子产品', '家居用品', '服装', '食品'],
products: [
{
id: 1, name: '产品1', category: '电子产品', price: 100 },
{
id: 2, name: '产品2', category: '家居用品', price: 50 },
{
id: 3, name: '产品3', category: '服装', price: 80 },
{
id: 4, name: '产品4', category: '食品', price: 20 }
],
selectedCategory: '',
selectedPriceRange: '',
selectedSortBy: 'name',
cartItems: [],
orders: []
};
},
computed: {
filteredProducts() {
let filtered = this.products;
if (this.selectedCategory) {
filtered = filtered.filter(product => product.category === this.selectedCategory);
}
if (this.selectedPriceRange) {
const [min, max] = this.selectedPriceRange.split('-');
filtered = filtered.filter(product => product.price >= min && product.price <= max);
}
if (this.selectedSortBy === 'price') {
filtered.sort((a, b) => a.price - b.price);
} else if (this.selectedSortBy === 'name') {
filtered.sort((a, b) => a.name.localeCompare(b.name));
}
return filtered;
}
},
methods: {
addToCart(product) {
const cartItem = this.cartItems.find(item => item.product.id === product.id);
if (cartItem) {
cartItem.quantity++;
} else {
this.cartItems.push({
product: product, quantity: 1 });
}
},
removeFromCart(item) {
const index = this.cartItems.indexOf(item);
if (index !== -1) {
this.cartItems.splice(index, 1);
}
},
getTotalPrice() {
return this.cartItems.reduce((total, item) => total + item.product.price * item.quantity, 0);
},
checkout() {
const order = {
id: this.orders.length + 1,
items: [...this.cartItems],
totalPrice: this.getTotalPrice()
};
this.orders.push(order);
this.cartItems = [];
}
}
};
</script>
<style>
.product-list > div {
margin-bottom: 20px;
}
</style>
在数据部分,我们定义了 categories 数组,用于存储产品的分类信息。
我们还定义了 products 数组,用于存储产品信息。每个产品包含一个 id、name、category 和 price 字段,表示产品的标识、名称、分类和价格。
在模板中,我们使用
<select>
元素实现了筛选和排序的功能。通过 v-model 指令将选择的值与 selectedCategory、selectedPriceRange 和 selectedSortBy 变量进行绑定。在产品列表部分,我们使用 v-for 指令循环渲染产品,并根据选择的分类、价格范围和排序方式对产品进行筛选和排序。
我们为每个产品添加了一个 "添加到购物车" 的按钮,点击该按钮会将产品添加到购物车中。
在购物车部分,我们使用 v-for 指令循环渲染购物车中的商品,并显示商品的名称、数量和移除按钮。在购物车底部还显示了购物车中商品的总计金额,并提供了一个 "结账" 的按钮。
当用户点击 "结账" 按钮时,会生成一个订单对象,包含订单ID、商品列表和总计金额。该订单会被添加到 orders 数组中,并清空购物车。
最后,在订单管理部分,我们根据 orders 数组的内容显示订单的信息。
谢谢款待