当前位置: 首页 > news >正文

前端课设Web2

App.vue

一、模板结构 (Template)

  1. ​布局结构​

    • 使用 Element UI 的栅格系统 <el-row> 和 <el-col> 实现 24 分栏布局。
    • :gutter="20" 表示列之间的水平间距为 20px。
    • 左侧导航栏占 4 列 (span="4"),右侧内容区域占 20 列 (span="20")。
  2. ​左侧导航菜单​

    • <el-menu> 组件实现导航菜单:
      • router 属性开启路由模式,点击菜单项会自动跳转到对应路由。
      • default-active="$route.path" 根据当前路由路径高亮对应菜单项。
      • 样式属性设置背景色、文字颜色和高亮颜色。
    • v-for 遍历 navList 生成菜单项,每个菜单项绑定路由路径 (:index="item.name"),显示图标和文字。
  3. ​右侧内容区域​

    • <router-view> 是 Vue Router 的出口,根据当前路由动态渲染对应组件。
    • .menu-right 类通过 margin-left 微调内容区域位置。

二、脚本逻辑 (Script)

        ​​数据对象​

  • navList 定义了导航菜单项的路由路径和显示名称,例如:
    // 点击跳转到该路由,显示“计算机器”
    { name: '/components/Compurte', navItem: '计算机器' } 
    ​​方法​
    • handleOpen 和 handleClose 是 Element 菜单组件的事件回调,目前仅打印日志,可扩展功能(如菜单展开/折叠动画)。

三、样式设计 (Style)

  1. 全局样式​
    • #app 设置字体、颜色和顶部边距。
  2. ​内容区域调整​
    • .menu-right 添加左外边距,避免内容与左侧导航栏重叠。

四、实现思路

五、代码

<template><div id="app"><!-- 将布局元素包裹在 el-row 中(ElementUI 规范) --><el-row :gutter="20"><!-- 左侧导航栏 --><el-col :span="4"><el-menu:default-active="$route.path"routermode="horizontal"class="el-menu-vertical-demo"@open="handleOpen"@close="handleClose"background-color="#545c64"text-color="#fff"active-text-color="#ffd04b"><el-menu-item v-for="(item, i) in navList" :key="i" :index="item.name"><template slot="title"><i class="el-icon-s-platform" /><span>{{ item.navItem }}</span></template></el-menu-item></el-menu></el-col><!-- 主内容区域 --><el-col :span="20"><router-view class="menu-right" /></el-col></el-row></div>
</template><!-- <script>export default {components:{Test,},name: 'App'
}
</script> --><style>
#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
.menu-right{margin-left:200px;}
</style><script>export default {data() { return { navList:[  {name:'/components/Compurte',navItem:'计算机器'},{name:'/components/Province',navItem:'城市选择'},{name:'/components/RegisterForm',navItem:'百度注册'},{name:'/components/Shoping',navItem:'购物界面'},{name:'/components/ClockComponent',navItem:'时间界面'},{name:'/components/StuScore',navItem:'学生成绩'},{name:'/components/Speakin',navItem:'留言界面'},{name:'/components/StuCont',navItem:'学生管理'},{name:'/components/WorkMone',navItem:'员工工资'},{name:'/components/ZutheCe',navItem:'用户注册'},     ] } },methods: {handleOpen(key, keyPath) {console.log(key, keyPath);},handleClose(key, keyPath) {console.log(key, keyPath);}}}
</script><!-- <style>.menu-right{margin-left:200px;}</style> -->

index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Compurte from '@/components/Compurte'
import Province from '@/components/Province'
import RegisterForm from '@/components/RegisterForm'
import RegisterSuccess from '@/components/RegisterSuccess'
import Shoping from '@/components/Shoping'
import ClockComponent from '@/components/ClockComponent'
import StuScore from '@/components/StuScore'
import Speakin from '@/components/Speakin'
import WorkMone from '@/components/WorkMone'
import StuCont from '@/components/StuCont'
import ZuTheCe from '@/components/ZutheCe'
Vue.use(Router)export default new Router({routes: [{path: '/',name: 'HelloWorld',component: HelloWorld},{path:'/components/Compurte',name:'Compurte',component: Compurte},{path:'/components/Province',name:'Province',component: Province},{path: '/components/RegisterForm',name: 'Register',component: RegisterForm},{path: '/RegisterSuccess',name: 'RegisterSuccess',component: RegisterSuccess},{path:'/components/Shoping',name: 'Shoping',component: Shoping},{path:'/components/ClockComponent',name: 'ClockComponent',component: ClockComponent},{path:'/components/StuScore',name: 'StuScore',component: StuScore},{path:'/components/Speakin',name: 'Speakin',component: Speakin},{path:'/components/WorkMone',neam: 'WorkMone',component: WorkMone},{path:'/components/StuCont',neam: 'StuCont',component: StuCont},{path: '/components/ZutheCe',name: 'ZutheCe',component: ZuTheCe},{path: '*',redirect: '/components/HelloWorld' // 默认重定向到注册页面}]
})

 main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui' 
import 'element-ui/lib/theme-chalk/index.css'import axios from 'axios'Vue.use(ElementUI)
Vue.config.productionTip = false/* eslint-disable no-new */
new Vue({el: '#app',router,components: { App },template: '<App/>'
})

组件—components 

Compurte.vue

一、模板结构 (Template)

  1. ​计算器界面​​:

    • 输入框:<input type="text" v-model="displayValue"> 绑定到 displayValue,用于显示输入和结果。
    • 按钮布局:数字、运算符和功能按钮(AC、=)按计算器常见布局排列。
    • 事件绑定:按钮通过 @click 调用方法:
      • 数字/运算符:appendToInput
      • 清空:clear
      • 计算:calculate
  2. ​代码展示区块​​:

    • 通过 v-if="showCode" 动态显示/隐藏代码。
    • toggleCodeDisplay 方法切换显示状态。
    • <pre> 标签展示格式化后的 codeSnippet 字符串。

二、脚本逻辑 (Script)

  1. ​数据对象​​:

    • currentInput: 存储当前输入的表达式(如 "1+2")。
    • displayValue: 显示在输入框中的内容。
    • showCode: 控制代码区块的可见性。
    • codeSnippet: 字符串形式的方法代码(用于演示)。
  2. ​核心方法​​:

    • appendToInput(value)​:

      • 禁止以运算符开头(如直接输入 +)。
      • 禁止连续输入运算符(如 ++)。
      • 更新 currentInput 和 displayValue
    • clear()​:清空输入和显示内容。

    • calculate()​:

      • 替换运算符(如 % 转为 /100)。
      • 使用 eval 计算结果,处理异常(如除以零)。
      • 显示结果或错误信息(1秒后自动清空)。
    • toggleCodeDisplay()​:切换代码区块显示状态。


三、样式设计 (Style)

  1. ​计算器样式​​:

    • 黑色背景、圆角边框、白色按钮。
    • 按钮悬停动画:背景色和文字颜色渐变切换。
    • 特殊按钮(AC、0)加宽处理。
  2. ​代码展示区样式​​:

    • 灰色背景、居中对齐。
    • 切换按钮样式简洁,悬停效果平滑。

四、关键逻辑分析

  1. ​输入验证​​:

    • 运算符不能作为第一个字符。
    • 禁止连续输入运算符,确保表达式合法。
  2. ​计算逻辑​​:

    • eval 的使用​​:虽然方便但存在安全风险,此处因场景简单而接受。
    • ​百分比处理​​:% 替换为 /100,实现 50% → 0.5
  3. ​错误处理​​:

    • 异常捕获后显示“错误”,1秒后自动清空。
    • setTimeout(this.clear, 1000) 确保 this 指向正确。

 

五、代码 

<template><div><div id="calculator"><input type="text" id="txt" v-model="displayValue" readonly><br><input type="button" id="AC" value="AC" @click="clear"><input type="button" @click="appendToInput('/')" value="/"><input type="button" @click="appendToInput('%')" value="%"><br><input type="button" id="Seven" @click="appendToInput('7')" value="7"><input type="button" id="Eight" @click="appendToInput('8')" value="8"><input type="button" id="Nine" @click="appendToInput('9')" value="9"><input type="button" @click="appendToInput('+')" value="+"><br><input type="button" id="Four" @click="appendToInput('4')" value="4"><input type="button" id="Five" @click="appendToInput('5')" value="5"><input type="button" id="Six" @click="appendToInput('6')" value="6"><input type="button" @click="appendToInput('-')" value="-"><br><input type="button" id="One" @click="appendToInput('1')" value="1"><input type="button" id="Two" @click="appendToInput('2')" value="2"><input type="button" id="Three" @click="appendToInput('3')" value="3"><input type="button" @click="appendToInput('*')" value="*"><br><input type="button" id="Zero" @click="appendToInput('0')" value="0"><input type="button" id="Dot" @click="appendToInput('.')" value="."><input type="button" @click="calculate" value="="></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div></template><script>
export default {name: 'Calculator',data() {return {currentInput: '',displayValue: '',showCode: false,codeSnippet:`appendToInput(value) {// 如果是运算符且当前输入为空,则不处理if (['+', '-', '*', '/', '%'].includes(value) && this.currentInput === '') {return;}// 如果当前输入已经是运算符,不允许连续输入运算符lastChar = this.currentInput.slice(-1);if (['+', '-', '*', '/', '%'].includes(lastChar) && ['+', '-', '*', '/', '%'].includes(value)) {return;}// 添加新输入this.currentInput += value;this.displayValue = this.currentInput;},clear() {this.currentInput = '';this.displayValue = '';},calculate() {try {// 替换显示的运算符为JavaScript可识别的运算符let expression = this.currentInput.replace(/×/g, '*').replace(/÷/g, '/').replace(/%/g, '/100');// 使用eval计算表达式result = eval(expression);// 检查结果是否为有限数字if (!isFinite(result)) {throw new Error('无效的计算');}// 显示结果this.displayValue += '=';this.displayValue += result;} catch (error) {this.displayValue = '错误';setTimeout(this.clear, 1000);延时函数}}`}},methods: {appendToInput(value) {// 如果是运算符且当前输入为空,则不处理if (['+', '-', '*', '/', '%'].includes(value) && this.currentInput === '') {return;}// 如果当前输入已经是运算符,不允许连续输入运算符const lastChar = this.currentInput.slice(-1);if (['+', '-', '*', '/', '%'].includes(lastChar) && ['+', '-', '*', '/', '%'].includes(value)) {return;}// 添加新输入this.currentInput += value;this.displayValue = this.currentInput;},clear() {this.currentInput = '';this.displayValue = '';},calculate() {try {// 替换显示的运算符为JavaScript可识别的运算符let expression = this.currentInput.replace(/×/g, '*').replace(/÷/g, '/').replace(/%/g, '/100');// 使用eval计算表达式let result = eval(expression);// 检查结果是否为有限数字if (!isFinite(result)) {throw new Error('无效的计算');}// 显示结果this.displayValue += '=';this.displayValue += result;} catch (error) {this.displayValue = '错误';setTimeout(this.clear, 1000);}},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
#calculator {margin: 0 auto;border: #000  2px solid;border-radius: 15px 15px 15px 15px;width: 300px;height: 460px;background: #000000;
}#hiddentxt {height: 100px;
}#txt {width: 88%;height: 80px;border-radius: 12px 12px 12px 12px;font-size: 24px;font-weight: bold;background: #000;color: white;border: #fff 5px solid;margin-top: 15px;margin-left:12px;font-family: "Comic Sans MS", "Leelawadee UI";
}input[type=button] {width: 56px;height: 56px;margin-top: 10px;margin-left: 13px;border-radius: 10px;font-size: 20px;font-weight: bold;background: #fff;font-family:"Comic Sans MS";
}#Zero, #AC {width: 129px;
}input[type=button]:hover {color: #fff;background: #000;animation-name: mybutton;animation-duration: 0.8s;animation-timing-function: ease-in-out;
}@keyframes mybutton {0% {background: #fff;color: #000;}100% {background:#000;color: #fff;}
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

Provinece.vue

一、模板部分解析

<template><div><!-- 级联选择器容器 --><div class="cascader-container"><form><div class="select-group">省份:<!-- 省份选择框 --><select v-model="selectedProvince" @change="loadCity" required><option value="">--请选择--</option><!-- 遍历省份数据生成选项 --><option v-for="province in provinces" :key="province.name" :value="province">{{ province.name }}</option></select>城市:<!-- 城市选择框 --><select v-model="selectedCity"><option value="">--请选择--</option><!-- 遍历城市数据生成选项 --><option v-for="city in cities" :key="city" :value="city">{{ city }}</option></select></div></form></div><!-- 代码展示区域 --><div id="code-div"><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre> <!-- 显示代码片段 --></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }} <!-- 动态按钮文本 --></button></div></div>
</template>

二、脚本部分解析

<script>
export default {name: 'ProvinceCityCascader',data() {return {selectedProvince: '',       // 当前选中的省份对象selectedCity: '',           // 当前选中的城市cities: [],                 // 当前省份对应的城市列表provinces: [                // 硬编码的省份数据{"name":"广东省","info":['广州市','深圳市','佛山市', '珠海市']},{"name":"四川省","info":['成都市','德阳市','绵阳市','广元市']},{"name":"云南省","info":['昆明市','大理市','丽江市']},{"name":"贵州省","info":['贵阳市','遵义市']}],showCode: false,            // 控制代码显示状态codeSnippet:`loadCity() {   // 要显示的代码片段// ...方法实现}`}},methods: {loadCity() {this.selectedCity = '';      // 重置城市选择if (!this.selectedProvince) {this.cities = [];          // 清空城市列表return;}this.cities = this.selectedProvince.info; // 获取对应城市},toggleCodeDisplay() {this.showCode = !this.showCode; // 切换代码显示状态}}
}
</script>

 三、样式部分解析

<style scoped>
/* 容器居中、选择框样式 */
.cascader-container { text-align: center; margin: 20px auto; }
select { width: 120px; padding: 8px; border-radius: 4px; }/* 代码区块样式 */
.code-section { background: #f5f5f5; padding: 15px; }
.code-toggle { background: #eef; margin: 20px auto; }
</style>

四、实验实现思路分析

  1. ​数据驱动设计​

    • 使用provinces数组存储结构化数据,每个省份对象包含name和城市列表info
    • 通过v-model实现双向数据绑定:
selectedProvince // 绑定省份选择框
selectedCity     // 绑定城市选择框

​级联更新机制​

  • 省份选择框的@change事件触发loadCity方法
  • 核心逻辑代码:
loadCity() {this.selectedCity = ''; // 清空已选城市this.cities = this.selectedProvince?.info || []; 
}

​响应式更新流程

 数据流向图示

 

 五、代码

<template><div><div class="cascader-container"><form><div class="select-group">省份:<select v-model="selectedProvince" @change="loadCity" required><option value="">--请选择--</option><option v-for="province in provinces" :key="province.name" :value="province">{{ province.name }}</option></select>城市:<select v-model="selectedCity"><option value="">--请选择--</option><option v-for="city in cities" :key="city" :value="city">{{ city }}</option></select></div></form></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {name: 'ProvinceCityCascader',data() {return {selectedProvince: '',selectedCity: '',cities: [],// JSON对象数据provinces: [{"name":"广东省","info":['广州市','深圳市','佛山市', '珠海市']},{"name":"四川省","info":['成都市','德阳市','绵阳市','广元市']},{"name":"云南省","info":['昆明市','大理市','丽江市']},{"name":"贵州省","info":['贵阳市','遵义市']}],showCode: false,codeSnippet:`loadCity() {// 重置选中的城市this.selectedCity = '';if (!this.selectedProvince) {this.cities = [];return;}// 从JSON对象中获取对应省份的城市列表this.cities = this.selectedProvince.info;}`}},methods: {loadCity() {// 重置选中的城市this.selectedCity = '';if (!this.selectedProvince) {this.cities = [];return;}// 从JSON对象中获取对应省份的城市列表this.cities = this.selectedProvince.info;},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
.cascader-container {text-align: center;margin: 20px auto;
}.select-group {display: inline-block;
}select {width: 120px;padding: 8px;margin: 5px 10px;border: 1px solid #ddd;border-radius: 4px;font-size: 14px;
}select:focus {outline: none;border-color: #409eff;
}select:disabled {background-color: #f5f5f5;cursor: not-allowed;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

RegisterForm.vue / RegisterSucess.vue

一、 <template> 部分​

二、 <script> 部分

三、 <style> 部分​ 

 四、实验实现的主要思路​

  1. ​双向绑定与响应式​​:

    • 使用 v-model 实现表单输入与 data 的自动同步。
    • 错误信息(如 usernameError)动态更新,实时反馈验证结果。
  2. ​前端验证策略​​:

    • ​即时验证​​:通过 @blur 事件在输入框失去焦点时触发验证。
    • ​提交时二次验证​​:在 submitForm 中调用所有验证方法,确保数据最终正确性。
    • ​密码一致性检查​​:在 validatePassword 中同时验证密码和确认密码。
  3. ​动态数据生成​​:

    • 年、月、日选项通过 Array.from 动态生成,避免硬编码。
  4. ​路由与状态传递​​:

    • 使用 vue-router 跳转到成功页面,通过 query 参数传递用户名。
  5. ​调试辅助功能​​:

    • 通过 toggleCodeDisplay 切换显示表单提交和验证的代码片段,便于调试或教学。

 五、代码

RegisterForm.vue 

<template><div><div class="center"><img src="../assets/header1.png" /><form @submit.prevent="submitForm"><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td class="left">用户名:</td><td><input v-model="form.username" type="text" class="inputs" @blur="validateUsername"/><div id="userId" class="red">{{ usernameError }}</div></td></tr><tr><td class="left">密码:</td><td><input v-model="form.password" type="password" class="inputs" @blur="validatePassword"/><div id="pwdId" class="red">{{ passwordError }}</div></td></tr><tr><td class="left">确认密码:</td><td><input v-model="form.repassword" type="password" class="inputs" @blur="validatePassword"/><div id="repwdId" class="red">{{ repasswordError }}</div></td></tr><tr><td class="left">性别:</td><td><div style="float:left;"><input v-model="form.sex" name="sex" type="radio" value="男" checked/>男 <input v-model="form.sex" name="sex" type="radio" value="女"/>女</div><div id="sexId" class="red">{{ sexError }}</div></td></tr><tr><td class="left">电子邮件地址</td><td><input v-model="form.email" type="text" class="inputs" @blur="validateEmail"/><div id="emailId" class="red">{{ emailError }}</div></td></tr><tr><td class="left">出生日期:</td><td><select v-model="form.year" id="year"><option v-for="year in years" :value="year" :key="year">{{ year }}</option></select>年<select v-model="form.month" id="month"><option v-for="month in months" :value="month" :key="month">{{ month }}</option></select>月<select v-model="form.day" id="day"><option v-for="day in days" :value="day" :key="day">{{ day }}</option></select>日</td></tr><tr><td>&nbsp;</td><td><input name="sub" type="submit" value="注册"/> <input name="cancel" type="reset" value="清除" @click="resetForm"/></td></tr></table></form></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {name: 'RegisterForm',data() {return {form: {username: '',password: '',repassword: '',sex: '男',email: '',year: new Date().getFullYear(),month: 1,day: 1},usernameError: '',passwordError: '',repasswordError: '',emailError: '',sexError: '',years: Array.from({length: 110}, (_, i) => 1900 + i),months: Array.from({length: 12}, (_, i) => 1 + i),days: Array.from({length: 31}, (_, i) => 1 + i),showCode: false,codeSnippet:` submitForm() {this.clearErrors();const isUsernameValid = this.validateUsername();const isPasswordValid = this.validatePassword();const isEmailValid = this.validateEmail();if (isUsernameValid && isPasswordValid && isEmailValid) {// 表单验证通过,跳转到成功页面this.$router.push({path: '/RegisterSuccess',query: {username: this.form.username}});}},validateUsername() {const value = this.form.username.trim();if (value === '') {this.usernameError = '用户名不能为空';return false;}if (value.length < 4 || value.length > 12) {this.usernameError = '用户名长度应为4-12个字符';return false;}if (!/^[a-zA-Z0-9_]+$/.test(value)) {this.usernameError = '用户名只能包含字母、数字和下划线';return false;}this.usernameError = '';return true;},validatePassword() {const value = this.form.password.trim();if (value === '') {this.passwordError = '密码不能为空';return false;}if (value.length < 6 || value.length > 12) {this.passwordError = '密码长度应为6-12个字符';return false;}// 验证两次密码是否一致const repwdValue = this.form.repassword.trim();if (repwdValue === '') {this.repasswordError = '请确认密码';return false;}if (value !== repwdValue) {this.repasswordError = '两次输入的密码不一致';return false;}this.passwordError = '';this.repasswordError = '';return true;},validateEmail() {const value = this.form.email.trim();if (value === '') {this.emailError = '邮箱不能为空';return false;}if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) {this.emailError = '请输入有效的邮箱地址';return false;}this.emailError = '';return true;},clearErrors() {this.usernameError = '';this.passwordError = '';this.repasswordError = '';this.emailError = '';this.sexError = '';},resetForm() {this.form = {username: '',password: '',repassword: '',sex: '男',email: '',year: new Date().getFullYear(),month: 1,day: 1};this.clearErrors();}`}},methods: {submitForm() {this.clearErrors();const isUsernameValid = this.validateUsername();const isPasswordValid = this.validatePassword();const isEmailValid = this.validateEmail();if (isUsernameValid && isPasswordValid && isEmailValid) {// 表单验证通过,跳转到成功页面this.$router.push({path: '/RegisterSuccess',query: {username: this.form.username}});}},validateUsername() {const value = this.form.username.trim();if (value === '') {this.usernameError = '用户名不能为空';return false;}if (value.length < 4 || value.length > 12) {this.usernameError = '用户名长度应为4-12个字符';return false;}if (!/^[a-zA-Z0-9_]+$/.test(value)) {this.usernameError = '用户名只能包含字母、数字和下划线';return false;}this.usernameError = '';return true;},validatePassword() {const value = this.form.password.trim();if (value === '') {this.passwordError = '密码不能为空';return false;}if (value.length < 6 || value.length > 12) {this.passwordError = '密码长度应为6-12个字符';return false;}// 验证两次密码是否一致const repwdValue = this.form.repassword.trim();if (repwdValue === '') {this.repasswordError = '请确认密码';return false;}if (value !== repwdValue) {this.repasswordError = '两次输入的密码不一致';return false;}this.passwordError = '';this.repasswordError = '';return true;},validateEmail() {const value = this.form.email.trim();if (value === '') {this.emailError = '邮箱不能为空';return false;}if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)) {this.emailError = '请输入有效的邮箱地址';return false;}this.emailError = '';return true;},clearErrors() {this.usernameError = '';this.passwordError = '';this.repasswordError = '';this.emailError = '';this.sexError = '';},resetForm() {this.form = {username: '',password: '',repassword: '',sex: '男',email: '',year: new Date().getFullYear(),month: 1,day: 1};this.clearErrors();},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
/* 保留原有的样式 */
.center {float: none;width: 503px;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;
}.inputs {border: 1px solid #333;width: 120px;float: left;
}.left {width: 120px;text-align: right;padding-right: 5px;
}.red {color: #ff0000;padding-left: 10px;font-size: 12px;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

RegisterSucess.vue

<template><div class="success-page"><img src="../assets/top.png" /><br /><h1>欢迎您{{ username }}注册成为百度用户!</h1></div>
</template><script>
export default {name: 'RegisterSuccess',data() {return {username: ''}},created() {// 从路由参数中获取用户名this.username = this.$route.query.username || '';}
}
</script><style scoped>
.success-page {margin: 0;text-align: center;font-size: 24px;font-weight: bold;
}
</style>

shopping.vue

一、模板部分(Template) 

 二、脚本部分(Script)

三、样式部分(Style)

四、实验思路分析

五、代码

<template><div><div class="content"><div class="logo"><img :src="require('../assets/shoplogo.png')" alt="当当购物车"><span @click="closePlan">关闭</span></div><div class="cartList"><ul v-for="(item, index) in cartItems" :key="index"><li><p @click="moveToCollection(index)">移入收藏</p><p @click="deleteItem(index)">删除</p></li><li>¥{{ item.price.toFixed(2) }}</li><li><input type="button" name="minus" value="-" @click="decreaseQuantity(index)"><input type="text" name="amount" v-model.number="item.quantity" @change="updatePrice(index)"><input type="button" name="plus" value="+" @click="increaseQuantity(index)"></li><li>¥<input type="text" name="price" :value="(item.price * item.quantity).toFixed(2)" readonly></li></ul><ol><li>¥{{ totalPrice.toFixed(2) }}</li><li><span @click="checkout">结 算</span></li></ol></div></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {name: 'DangdangCart',data() {return {cartItems: [{ price: 159.00, quantity: 1 },{ price: 132.00, quantity: 1 }],showCode: false,codeSnippet:`closePlan() {// 关闭购物车逻辑console.log('关闭购物车')this.$emit('close-cart')},moveToCollection(index) {// 移入收藏夹逻辑const item = this.cartItems[index]console.log('将商品移入收藏夹:', item)this.$emit('add-to-favorites', item)},deleteItem(index) {// 删除商品逻辑this.cartItems.splice(index, 1)},increaseQuantity(index) {this.cartItems[index].quantity++this.updatePrice(index)},decreaseQuantity(index) {if (this.cartItems[index].quantity > 1) {this.cartItems[index].quantity--this.updatePrice(index)}},updatePrice(index) {// 确保数量是数字且大于0if (isNaN(this.cartItems[index].quantity) || this.cartItems[index].quantity < 1) {this.cartItems[index].quantity = 1}},checkout() {// 结算逻辑console.log('结算总价:', this.totalPrice)this.$emit('checkout', {items: this.cartItems,total: this.totalPrice})}`}},computed: {totalPrice() {return this.cartItems.reduce((total, item) => {return total + (item.price * item.quantity)}, 0)}},methods: {closePlan() {// 关闭购物车逻辑if (window.confirm('确定要关闭购物车吗?')) {console.log('关闭购物车')this.$emit('close-cart')}},moveToCollection(index) {// 移入收藏夹逻辑const item = this.cartItems[index]console.log('将商品移入收藏夹:', item)this.$emit('add-to-favorites', item)},deleteItem(index) {// 删除商品逻辑// 添加确认对话框if (window.confirm('确定要删除该商品吗?')) {// 安全删除逻辑if (index > -1 && index < this.cartItems.length) {this.cartItems.splice(index, 1)}}},increaseQuantity(index) {this.cartItems[index].quantity++this.updatePrice(index)},decreaseQuantity(index) {if (this.cartItems[index].quantity > 1) {this.cartItems[index].quantity--this.updatePrice(index)}},updatePrice(index) {// 确保数量是数字且大于0if (isNaN(this.cartItems[index].quantity) || this.cartItems[index].quantity < 1) {this.cartItems[index].quantity = 1}},checkout() {// 结算逻辑const itemsInfo = this.cartItems.map((item, idx) => `商品${idx + 1}: ¥${item.price.toFixed(2)} × ${item.quantity}件`).join('\n')window.alert(`购买商品明细:\n${itemsInfo}\n\n总计:¥${this.totalPrice.toFixed(2)}`)this.$emit('checkout', {items: this.cartItems,total: this.totalPrice})},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
/* 保留原有的CSS样式 */
body, ul, li, div, p, h1, h2, ol {margin: 0;padding: 0;
}
ul, li, ol {list-style: none;
}
.content {width: 910px;margin: 0 auto;font-family: "微软雅黑";
}
.logo {margin: 10px 0;
}
.logo span {display: inline-block;width: 60px;height: 30px;line-height: 30px;font-size: 14px;background: #ff0000;color: #ffffff;text-align: center;border-radius: 10px;margin-top: 5px;margin-right: 10px;cursor: pointer;font-weight: bold;
}
.cartList {background: url("../assets/shoppingBg.png") no-repeat;background-size: 100%;height: 414px;overflow: hidden;
}
.cartList ul {float: right;width: 550px;
}
.cartList ul:nth-of-type(1) {margin-top: 96px;
}
.cartList ul:nth-of-type(2) {margin-top: 70px;
}
.cartList ul li {font-family: "微软雅黑";font-size: 12px;color: #666666;text-align: center;line-height: 25px;float: right;
}
.cartList ul li input[name="price"] {border: none;background: transparent;width: 45px;text-align: center;
}
.cartList ul li input[name="amount"] {width: 45px;text-align: center;border: 1px solid #999999;border-left: none;border-right: none;height: 21px;
}
.cartList ul li input[name="minus"],
.cartList ul li input[name="plus"] {height: 25px;border: 1px #999999 solid;width: 25px;text-align: center;cursor: pointer;
}
.cartList ul li:nth-of-type(1) {width: 130px;
}
.cartList ul li:nth-of-type(2) {width: 100px;
}
.cartList ul li:nth-of-type(3) {width: 130px;
}
.cartList ul li p {cursor: pointer;
}
.cartList ol {float: right;clear: both;margin-top: 60px;
}
.cartList ol li {float: left;
}
.cartList ol li:nth-of-type(1) {color: #ff0000;width: 100px;font-weight: 900;
}
.cartList ol li span {display: inline-block;width: 80px;height: 35px;line-height: 35px;font-size: 14px;font-family: "微软雅黑";background: #ff0000;color: #ffffff;text-align: center;margin-top: 5px;margin-right: 15px;cursor: pointer;font-weight: bold;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

ClockComponent.vue

一、模板部分(Template)

 二、脚本部分(Script)

三、样式部分(Style)

四、实验思路分析

五、代码

<template><div><div class="clock-container"><div class="content"><div id="title">{{ title }}</div><div id="date">{{ dateString }}</div><div id="myclock">{{ currentTime }}</div><div id="weekday">{{ weekday }}</div></div></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {data() {return {title: '当前时间',currentTime: '',weekday: '',dateString: '',showCode: false,codeSnippet:`updateTime() {const date = new Date()this.currentTime = {this.pad(date.getHours())}:{this.pad(date.getMinutes())}:{this.pad(date.getSeconds())}this.weekday = this.getChineseWeekday(date.getDay())this.dateString = {date.getFullYear()}年{this.pad(date.getMonth()+1)}月{this.pad(date.getDate())}日},pad(n) {return n < 10 ? '0' + n : n},getChineseWeekday(day) {const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']return weekdays[day]}`}},mounted() {this.updateTime()this.timer = setInterval(this.updateTime, 1000)},beforeDestroy() {clearInterval(this.timer)},methods: {updateTime() {const date = new Date()this.currentTime = `${this.pad(date.getHours())}:${this.pad(date.getMinutes())}:${this.pad(date.getSeconds())}`this.weekday = this.getChineseWeekday(date.getDay())this.dateString = `${date.getFullYear()}年${this.pad(date.getMonth()+1)}月${this.pad(date.getDate())}日`},pad(n) {return n < 10 ? '0' + n : n},getChineseWeekday(day) {const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']return weekdays[day]},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
.clock-container {background: #000;min-height: 100vh;display: flex;align-items: center;
}.content {width: 400px;margin: 0 auto;color: #fff;text-align: center;padding: 20px 0;
}#title {font-size: 25px;margin-bottom: 10px;
}#myclock {margin-top: 20px;font-size: 60px;font-weight: 900;
}#weekday {font-size: 30px;margin: 15px 0;
}#date {font-size: 28px;margin-top: 10px;color: #ccc;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}</style>

StuScore.vue

 一、模板部分(Template)

  1. ​学生信息展示​

    • 显示学生姓名、性别和年龄,数据来自组件的data属性。
    • 使用双大括号 {{ }} 进行数据绑定。
  2. ​成绩表格​

    • 表头包括学期、数学、物理、化学、英语、计算机和总分。
    • 使用 v-for 循环遍历 grades 数组,动态生成每个学期的成绩行。
    • 各科分数从 grade.scores 对象中获取,总分通过 calculateTotal 方法计算。
  3. ​代码展示交互​

    • 通过按钮切换显示/隐藏代码片段(showCode 状态控制)。
    • 使用 <pre> 标签保留代码格式,展示 codeSnippet 中的方法代码。

二、脚本部分(Script)

  1. ​数据对象(data)​

    • namesexage: 学生基本信息。
    • grades: 包含多个学期成绩的数组,每个学期有各科分数。
    • showCode: 控制代码块显示状态的布尔值。
    • codeSnippet: 存储计算总分方法的代码字符串。
  2. ​方法(methods)​

    • calculateTotal(scores):
      使用 Object.values 将分数对象转为数组,通过 reduce 累加求和。
    • toggleCodeDisplay(): 切换 showCode 状态,实现代码块的显示/隐藏。

三、样式部分(Style)

  1. 布局样式​

    • 成绩表居中显示(margin: 30px auto),宽度固定为 560px。
    • 使用浮动(float: left)实现表头和内容的横向排列。
  2. ​视觉设计​

    • 表头背景色为浅灰色(#f6f6f6)。
    • 边框和间距提升可读性(border: 1px solid #ddd)。
    • 按钮具有悬停动效(transition: all 0.3s)和圆角边框(border-radius: 4px)。
  3. ​代码块样式​

    • 浅灰色背景(#f5f5f5)突出显示代码区域。
    • 通过 margin: 0 auto 实现居中布局。

四、实验思路分析

五、代码

speakin.vue 

一、模板部分(Template)

  1. ​留言表单​

    • 使用<form>包裹,提交时调用add方法(.prevent修饰符阻止默认提交行为)
    • 三个输入项通过v-model实现双向绑定:
      • 姓名绑定username
      • 标题绑定title
      • 内容绑定content
    • 包含背景图片的表格布局
  2. ​留言展示区​

    • 使用v-for循环渲染messages数组
    • 显示每条留言的标题、用户名、内容和时间戳
  3. ​调试代码面板​

    • 通过v-if="showCode"控制代码段的显示/隐藏
    • 使用<pre>标签保持代码格式
    • 切换按钮显示当前状态(显示代码/隐藏代码)

二、脚本部分(Script)

三、样式部分(Style)

  • ​背景图片系统​​:使用多张背景图(a_03.jpg, a_05.jpg等)构建视觉层级
  • ​响应式布局​​:
    • 主容器宽度754px居中
    • 代码面板宽度600px居中
    • 留言内容区左侧200px留白
  • ​交互效果​​:
    • 按钮悬停动画(0.3s过渡)
    • 代码面板灰色背景+圆角设计

四、实验思路分析

 

五、代码

<template><div><div id="app"><div id="ddiv"><form @submit.prevent="add"><table width="761" border="0" align="center"><tr><td align="center" bgcolor="#F9F8EF"><table width="749" border="0" style="border-collapse: collapse"><tr><td height="57" background="../assets/images/a_03.jpg">&nbsp;</td></tr><tr><td height="36" background="../assets/images/a_05.jpg">&nbsp;&nbsp;姓名:<input v-model="username" maxlength="64"></td></tr><tr><td height="36" background="../assets/images/a_05.jpg">&nbsp;&nbsp;标题:<input v-model="title" maxlength="64" size="30"></td></tr><tr><td background="../assets/images/a_05.jpg">&nbsp;&nbsp;内容:<textarea v-model="content" cols="60" rows="8" style="background:url(../assets/images/mrbccd.gif)"></textarea><table width="734" align="center"><tr><td height="40" align="center"><input type="submit" value="填写留言"></td></tr></table></td></tr></table></td></tr></table></form><div class="dhead"></div><div class="dcon"><div v-for="(msg, index) in messages" :key="index">标题:{{ msg.title }}<br>用户名:{{ msg.username }}<br>留言内容:{{ msg.content }}<br>时间:{{ msg.time }}</div></div></div></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {data() {return {username: '',title: '',content: '',messages: [],showCode: false,codeSnippet:`add() {if (!this.username || !this.title || !this.content) {alert('请填写所有字段')return}this.messages.unshift({username: this.username,title: this.title,content: this.content,time: new Date().toLocaleString()})this.username = ''this.title = ''this.content = ''}`}},methods: {add() {if (!this.username || !this.title || !this.content) {alert('请填写所有字段')return}this.messages.unshift({username: this.username,title: this.title,content: this.content,time: new Date().toLocaleString()})this.username = ''this.title = ''this.content = ''},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style>
.dhead {margin: 0 auto;width: 754px;height: 57px;background: url("../assets/images/b_03.jpg") no-repeat;
}
#ddiv {margin: 0 auto;width: 754px;background: url("../assets/images/a_05.jpg") repeat-y;
}
.dcon {width: 754px;padding-top: 20px;padding-left: 200px;
}
.dfoot {margin: 0 auto;width: 754px;height: 35px;background: url("../assets/images/a_07.jpg") no-repeat;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

StuCont.vue

一、模板部分(Template)

  1. ​新增学生表单​

    • 包含姓名(必填)、年龄(数字校验)、性别(下拉选择)
    • 使用 v-model.trim 和 v-model.number 自动处理输入
    • 点击「添加学生」调用 addStudent 方法
  2. ​数据操作区​

    • 显示平均年龄按钮触发 showAverage
    • 升降序切换按钮通过 toggleSort 实现
    • 搜索框通过 v-model 绑定 searchQuery
  3. ​学生列表表格​

    • 动态表头支持点击排序(sortBy 方法)
    • 使用 filteredStudents 计算属性渲染数据
    • 每行附带编辑和删除操作按钮
  4. ​编辑模态框​

    • 通过 showEditModal 控制显示
    • 编辑时深拷贝学生数据防止直接修改原数据
  5. ​代码展示区块​

    • 通过 showCode 控制调试代码的显隐

二、脚本部分(Script)

三、样式部分(Style)

  • 响应式布局使用 flex 和 max-width
  • 表格斑马纹效果:tr:nth-child(even)
  • 模态框居中定位:position: fixed + flex 布局
  • 操作按钮使用颜色编码:
    • 绿色:添加/保存
    • 蓝色:通用操作
    • 黄色:编辑
    • 红色:删除

四、实验思路分析

主流程架构 

添加学生流程 

 

 删除学生流程

 编辑学生流程 

排序控制流程 

 搜索过滤流程 

数据流动全景 

五、代码

<template><div><div class="student-manager"><!-- 新增学生表单 --><div class="form-section"><h3>学生信息管理</h3><div class="form-row"><div class="form-group"><label>姓名:</label><input type="text" v-model.trim="newStudent.name" required></div><div class="form-group"><label>年龄:</label><input type="number" v-model.number="newStudent.age" min="1" required></div><div class="form-group"><label>性别:</label><select v-model="newStudent.gender"><option value="男">男</option><option value="女">女</option></select></div><button @click="addStudent" class="btn-add">添加学生</button></div></div><!-- 数据操作区 --><div class="data-section"><div class="controls"><button @click="showAverage" class="btn-action">显示平均年龄</button><button @click="toggleSort" class="btn-action">{{ sortOrder === 'asc' ? '降序排列' : '升序排列' }}</button><input type="text" v-model="searchQuery" placeholder="搜索姓名" class="search-input"></div><!-- 学生列表 --><table><thead><tr><th v-for="(col, index) in columns" :key="index" @click="sortBy(col.key)">{{ col.title }}<span v-if="sortKey === col.key">{{ sortOrder === 'asc' ? '↑' : '↓' }}</span></th><th>操作</th></tr></thead><tbody><tr v-for="(student, index) in filteredStudents" :key="student.id"><td>{{ student.name }}</td><td>{{ student.age }}</td><td>{{ student.gender }}</td><td><button @click="editStudent(index)" class="btn-edit">编辑</button><button @click="deleteStudent(index)" class="btn-delete">删除</button></td></tr></tbody></table></div><!-- 编辑模态框 --><div v-if="showEditModal" class="modal"><div class="modal-content"><h3>编辑学生信息</h3><div class="form-group"><label>姓名:</label><input type="text" v-model="editingStudent.name"></div><div class="form-group"><label>年龄:</label><input type="number" v-model.number="editingStudent.age"></div><div class="button-group"><button @click="saveEdit" class="btn-save">保存</button><button @click="cancelEdit" class="btn-cancel">取消</button></div></div></div></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
export default {data() {return {students: [{ id: 1, name: '张三', age: 20, gender: '男' },{ id: 2, name: '李四', age: 22, gender: '男' },{ id: 3, name: '王五', age: 21, gender: '女' }],newStudent: {name: '',age: null,gender: '男'},searchQuery: '',sortKey: 'age',sortOrder: 'asc',showEditModal: false,editingStudent: {},editingIndex: -1,columns: [{ title: '姓名', key: 'name' },{ title: '年龄', key: 'age' },{ title: '性别', key: 'gender' }],showCode: false,codeSnippet: `addStudent() {if (!this.validateStudent()) returnthis.students.push({id: Date.now(),...this.newStudent})this.resetForm()},deleteStudent(index) {if (confirm('确定删除该学生吗?')) {this.students.splice(index, 1)}},editStudent(index) {this.editingStudent = { ...this.students[index] }this.editingIndex = indexthis.showEditModal = true},saveEdit() {this.students.splice(this.editingIndex, 1, this.editingStudent)this.cancelEdit()},cancelEdit() {this.showEditModal = falsethis.editingStudent = {}this.editingIndex = -1},showAverage() {const average = this.students.reduce((sum, stu) => sum + stu.age, 0) / this.students.lengthalert(学生平均年龄:{average.toFixed(2)})},toggleSort() {this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc'},sortBy(key) {if (this.sortKey === key) {this.toggleSort()} else {this.sortKey = keythis.sortOrder = 'asc'}},validateStudent() {if (!this.newStudent.name.trim()) {alert('请输入学生姓名')return false}if (!this.newStudent.age || this.newStudent.age < 1) {alert('请输入有效年龄')return false}return true},resetForm() {this.newStudent = { name: '', age: null, gender: '男' }}`}},computed: {sortedStudents() {return [...this.students].sort((a, b) => {const modifier = this.sortOrder === 'asc' ? 1 : -1return a[this.sortKey] > b[this.sortKey] ? 1 * modifier : -1 * modifier})},filteredStudents() {const query = this.searchQuery.toLowerCase()return this.sortedStudents.filter(student => student.name.toLowerCase().includes(query))}},methods: {addStudent() {if (!this.validateStudent()) returnthis.students.push({id: Date.now(),...this.newStudent})this.resetForm()},deleteStudent(index) {if (confirm('确定删除该学生吗?')) {this.students.splice(index, 1)}},editStudent(index) {this.editingStudent = { ...this.students[index] }this.editingIndex = indexthis.showEditModal = true},saveEdit() {this.students.splice(this.editingIndex, 1, this.editingStudent)this.cancelEdit()},cancelEdit() {this.showEditModal = falsethis.editingStudent = {}this.editingIndex = -1},showAverage() {const average = this.students.reduce((sum, stu) => sum + stu.age, 0) / this.students.lengthalert(`学生平均年龄:${average.toFixed(2)}`)},toggleSort() {this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc'},sortBy(key) {if (this.sortKey === key) {this.toggleSort()} else {this.sortKey = keythis.sortOrder = 'asc'}},validateStudent() {if (!this.newStudent.name.trim()) {alert('请输入学生姓名')return false}if (!this.newStudent.age || this.newStudent.age < 1) {alert('请输入有效年龄')return false}return true},resetForm() {this.newStudent = { name: '', age: null, gender: '男' }},toggleCodeDisplay() {this.showCode = !this.showCode;}}
}
</script><style scoped>
.student-manager {max-width: 800px;margin: 20px auto;padding: 20px;font-family: '微软雅黑';
}.form-section {background: #f5f5f5;padding: 20px;border-radius: 8px;margin-bottom: 20px;
}.form-row {display: flex;gap: 15px;flex-wrap: wrap;
}.form-group {flex: 1;min-width: 200px;
}.form-group label {display: block;margin-bottom: 5px;font-weight: bold;
}input, select {width: 100%;padding: 8px;border: 1px solid #ddd;border-radius: 4px;
}.controls {display: flex;gap: 10px;margin-bottom: 15px;flex-wrap: wrap;
}.btn-add, .btn-action {padding: 8px 15px;border: none;border-radius: 4px;cursor: pointer;transition: background 0.3s;
}.btn-add {background: #28a745;color: white;align-self: flex-end;
}.btn-action {background: #007bff;color: white;
}.search-input {flex: 1;max-width: 200px;padding: 8px;
}table {width: 100%;border-collapse: collapse;margin-top: 15px;
}th, td {border: 1px solid #ddd;padding: 12px;text-align: left;
}th {background: #007bff;color: white;cursor: pointer;
}tr:nth-child(even) {background: #f9f9f9;
}.btn-edit, .btn-delete {padding: 5px 10px;margin: 0 3px;border: none;border-radius: 3px;cursor: pointer;
}.btn-edit {background: #ffc107;color: black;
}.btn-delete {background: #dc3545;color: white;
}.modal {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0,0,0,0.5);display: flex;justify-content: center;align-items: center;
}.modal-content {background: white;padding: 20px;border-radius: 8px;width: 90%;max-width: 400px;
}.button-group {margin-top: 15px;text-align: right;
}.btn-save {background: #28a745;color: white;
}.btn-cancel {background: #6c757d;color: white;margin-left: 10px;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

 WorkMone.vue

一、模板结构(Template)

  1. ​工资表格部分​

    • 表头(.header)显示"姓名、月度收入、专项扣除、个税、工资"五列
    • 使用v-for循环渲染员工数据(staff数组)
    • 每行显示:
      • 员工姓名
      • 原始收入(income)
      • 固定专项扣除(insurance)
      • 计算后的个税(calculateTax)
      • 税后工资(calculateSalary)
  2. ​代码查看部分​

    • 通过按钮切换显示/隐藏代码片段(toggleCodeDisplay方法)
    • 使用v-if条件渲染代码区块
    • 显示预格式化的代码内容(codeSnippet字符串)

 二、脚本部分(Script)

三、样式部分(Style)

  1. ​表格布局​

    • 使用flex布局实现表头和表格行
    • 固定列宽100px
    • 边框和背景色区分表头与内容
  2. ​代码显示区​

    • 灰色背景突出显示代码
    • 按钮居中显示,带淡蓝色背景
    • 600px固定宽度容器
  3. ​响应式交互​

    • 按钮点击有过渡动画(transition)
    • 代码区块带圆角边框

四、实验思路分析

五、代码 

<template><div><div class="salary-container"><div class="header"><div class="header-item">姓名</div><div class="header-item">月度收入</div><div class="header-item">专项扣除</div><div class="header-item">个税</div><div class="header-item">工资</div></div><div class="row"v-for="employee in staff":key="employee.name"><div class="cell">{{ employee.name }}</div><div class="cell">{{ employee.income }}</div><div class="cell">{{ insurance }}</div><div class="cell">{{ calculateTax(employee) }}</div><div class="cell">{{ calculateSalary(employee) }}</div></div></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div></template><script>export default {data() {return {insurance: 1000,threshold: 5000,tax: 0.03,staff: [{ name: '张无忌', income: 6600 },{ name: '令狐冲', income: 8000 },{ name: '韦小宝', income: 7000 }],showCode: false,codeSnippet:`calculateTax(employee) {const taxable = employee.income - this.threshold - this.insurancereturn taxable > 0 ? Math.round(taxable * this.tax) : 0},calculateSalary(employee) {return employee.income - this.calculateTax(employee)}`}},methods: {calculateTax(employee) {const taxable = employee.income - this.threshold - this.insurancereturn taxable > 0 ? Math.round(taxable * this.tax) : 0},calculateSalary(employee) {return employee.income - this.calculateTax(employee)},toggleCodeDisplay() {this.showCode = !this.showCode;}}}</script><style scoped>.salary-container {text-align: center;font-family: 微软雅黑;font-size: 14px;width: 500px;}.header {display: flex;background: #f6f6f6;font-size: 18px;border: 1px solid #ddd;}.row {display: flex;border: 1px solid #ddd;border-top: none;}.header-item, .cell {width: 100px;text-align: center;line-height: 36px;height: 36px;flex-shrink: 0;}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}#code-div {margin: 0 auto;width:600px;
}.code-section {margin-top: 20px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}</style>

ZutheCe.vue

一、模板部分(Template)

  1. 登录表单​​:

    • 包含用户名和密码输入框,使用v-model.trim绑定数据并自动去除首尾空格
    • 表单提交触发login方法,.prevent修饰符阻止默认提交行为
  2. ​状态控制​​:

    • 登录按钮通过:disabled="loading"在请求期间禁用
    • 按钮文字动态显示"登录中..."或"登录"
  3. ​调试功能​​:

    • 可切换显示的代码区块(v-if="showCode")
    • 使用<pre>标签展示代码片段(codeSnippet)
    • 通过toggleCodeDisplay方法切换显示状态

 二、脚本部分(Script)

三、样式部分(Style)

  • 响应式布局​​:容器使用max-width: 300pxmargin: 50px auto居中
  • ​视觉设计​​:
    • 阴影效果(box-shadow)
    • 输入框过渡动画(transition)
    • 按钮悬停效果
  • ​代码展示区​​:
    • 灰色背景(background: #f5f5f5)
    • 固定宽度500px(应考虑响应式适配)

四、实验思路分析

五、代码

<template><div><div class="login-container"><div class="title">用户登录</div><form @submit.prevent="login" class="login-form"><div class="form-item"><label class="form-label">用户名:</label><div class="input-wrapper"><inputtype="text"v-model.trim="username"placeholder="请输入用户名"></div></div><div class="form-item"><label class="form-label">密码:</label><div class="input-wrapper"><inputtype="password"v-model.trim="password"placeholder="请输入密码"></div></div><div class="action-group"><button type="submit" class="submit-btn" :disabled="loading">{{ loading ? '登录中...' : '登录' }}</button><button type="button" class="reset-btn" @click="handleReset">重置</button></div></form></div><div id="code-div"><!-- 调试用代码展示区块 --><div class="code-section" v-if="showCode"><pre>{{ codeSnippet }}</pre></div><button @click="toggleCodeDisplay" class="code-toggle">{{ showCode ? '隐藏代码' : '显示代码' }}</button></div></div>
</template><script>
import axios from 'axios';export default {name: 'LoginPage',data() {return {username: '',password: '',loading: false,showCode: false,codeSnippet: `async login() {this.loading = true;try {// 基本输入验证if (!this.username.trim()) {alert("请输入用户名");return;}const response = await axios.get('http://localhost:8080/api/test');const users = response.data;// 用户存在性验证const userExists = users.some(user => user.name === this.username);if (userExists) {alert("登录成功");// 典型登录成功处理:// 1. 存储用户状态// 2. 跳转到仪表盘// this.$router.push('/dashboard');} else {alert("用户名不存在");}} catch (error) {console.error("登录失败:", error);alert("登录失败,请稍后重试");} finally {this.loading = false;}},handleReset() {this.username = '';this.password = '';},`};},methods: {async login() {this.loading = true;try {// 基本输入验证if (!this.username.trim()) {alert("请输入用户名");return;}const response = await axios.get('http://localhost:8080/api/test');const users = response.data;// 用户存在性验证const userExists = users.some(user => user.name === this.username);if (userExists) {alert("登录成功");// 典型登录成功处理:// 1. 存储用户状态// 2. 跳转到仪表盘// this.$router.push('/dashboard');} else {alert("用户名不存在");}} catch (error) {console.error("登录失败:", error);alert("登录失败,请稍后重试");} finally {this.loading = false;}},handleReset() {this.username = '';this.password = '';},toggleCodeDisplay() {this.showCode = !this.showCode;}}
};
</script><style scoped>
/* 保持原有样式不变 */
.login-container {max-width: 300px;margin: 50px auto;padding: 30px;background: #fff;border-radius: 8px;box-shadow: 0 2px 12px rgba(0,0,0,0.1);
}.title {font-size: 24px;text-align: center;margin-bottom: 30px;color: #333;
}.form-item {margin-bottom: 24px;
}.form-label {display: block;margin-bottom: 8px;color: #666;
}.input-wrapper {position: relative;
}input {width: 95%;height: 40px;padding: 8px 15px;border: 1px solid #ddd;border-radius: 4px;transition: border-color 0.3s;
}.action-group {margin-top: 30px;text-align: center;
}button {padding: 10px 24px;margin: 0 10px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s;
}.code-section {margin-top: 20px;width: 500px;padding: 15px;background: #f5f5f5;border-radius: 4px;
}.code-toggle {display: block;margin: 20px auto 0;background: #eef;
}
</style>

相关文章:

  • 微服务——网关
  • 第九章 云平台开发
  • 测试工程师如何通俗理解和入门RAG:从“查资料”到“写答案”的智能升级
  • 如何使用Webpack实现异步加载?
  • OC语言学习——Foundation框架回顾及考核补缺
  • Three.js 海量模型加载性能优化指南
  • 页表:从虚拟内存到物理内存的转换
  • 11.8 LangGraph生产级AI Agent开发:从节点定义到高并发架构的终极指南
  • 资源-又在网上淘到金了-三维模型下载
  • 【AI论文】QuickVideo:通过系统算法协同设计实现实时长视频理解
  • window 显示驱动开发-Direct3D 呈现性能改进(四)
  • 11|省下钱买显卡,如何利用开源模型节约成本?
  • 分库分表深度解析
  • 基于RedisBloom的JWT黑名单管理方案
  • ISO 20000体系:需求管理与容量管理含义与解释
  • DeepSeek 驱动智能交通调度:从传统到智慧的跃迁之路
  • 前端绘图基础——SVG详解
  • 使用f5-tts训练自己的模型笔记
  • MySQL中简单的操作
  • 【分割字符串 / 贪心 + 字符串 + 暴力】
  • 西安北郊网站建设/女生学网络营销这个专业好吗
  • 南京谁做免费网站/推广普通话宣传语100字
  • 南宁小程序定制开发公司/南山网站seo
  • 网站建设小工具/白杨seo课程
  • 让其他公司做网站应注意什么/百度信息流推广技巧
  • 在线购物商城平台/我是seo关键词