牡丹区住房和城乡建设局网站搜索引擎营销的案例
全新专栏带你快速掌握Vue2+Vue3

1.插值表达式{{}}
插值表达式是一种Vue的模板语法
我们可以用插值表达式渲染出Vue提供的数据
1.作用:利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
以下的情况都是表达式:
money + 100
money - 100
money * 10
money / 10
price >= 100 ? '真贵':'还行'
obj.name
arr[0]
fn()
obj.fn()
2.语法
插值表达式语法:{{ 表达式 }}
<h3>{{title}}<h3><p>{{nickName.toUpperCase()}}</p><p>{{age >= 18 ? '成年':'未成年'}}</p><p>{{obj.name}}</p><p>{{fn()}}</p>
3.错误用法
1.在插值表达式中使用的数据 必须在data中进行了提供
<p>{{hobby}}</p> //如果在data中不存在 则会报错2.支持的是表达式,而非语句,比如:if for ...
<p>{{if}}</p>3.不能在标签属性中使用 {{ }} 插值 (插值表达式只能标签中间使用)
<p title="{{username}}">我是P标签</p>
2.基础指令
1.内容渲染指令(v-html)
什么是指令?在 Vue中,带有 v- 前缀 的 特殊 标签属性
指令的作用:Vue会根据不同的【指令】,针对标签实现不同的【功能】
2.条件渲染指令(v-show,v-if,v-else,v-else-if)
v-show与v-if
作用:v-show和v-if 用来控制元素的显示与隐藏
语法:
●v-show = "表达式" 表达式值为 true 显示, false 隐藏
●v-if= "表达式" 表达式值 true显示, false 隐藏
原理:
●v-show 原理: 切换 display:none 控制显示隐藏
●v-if 原理:基于条件判断,是否创建 或 移除元素节点
场景:
●v-show 用在 频繁切换显示隐藏的场景 (京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物! 的手机京东)
●v-if 用在要么显示,要么隐藏,不频繁切换的场景(京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物! 底部提示)
v-else,v-else-if
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"><p v-if="gender ==1">性别:♂ 男</p><p v-else>性别:♀ 女</p><hr /><p v-if="score>90">成绩评定A</p><p v-else-if="score>80">成绩评定B</p><p v-else-if="score>70">成绩评定C</p><p v-else>成绩评定D</p></div><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {gender: 2,score: 95,},});</script></body>
</html>
3.事件绑定指令(v-on)
作用:注册事件 (注册流程:事件名+ 事件处理逻辑 ,事件源哪去了?)
语法:
- v-on:事件名="内联语句"
- v-on:事件名="methods中的函数名"
- v-on:事件名="methods中的函数名(参数)"
举例:button注册事件的三种写法
- <button v-on:事件名="内联语句">按钮</button>
- <button v-on:事件名="处理函数">按钮</button>
- <button v-on:事件名="处理函数(实参)">按钮</button>
注意:v-on:
简写为 @
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"><button @click="count--">-</button><span>{{ count }}</span><button v-on:click="count++">+</button><hr /><button @click="del">-</button><span>{{ num }}</span><button v-on:click="num++">+</button><hr /><button @click="changenNum(-5)">-5</button><span>{{ num }}</span><button v-on:click="changenNum(10)">+10</button></div><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {count: 100,num: 0,},methods: {del() {if (this.num > 0) {this.num--;}},changenNum(num) {this.num += num;},},});</script></body>
</html>
4.属性绑定指令(v-bind)
作用: 给元素的属性动态绑定数据 ->例如: <img src=" " >
语法: v-bind:属性名 ="表达式 "
<img v-bind:src="imgUrl" alt="">
简写: v-bind: 可以简写成 => :bind
<img :src="imgUrl" alt="">
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"><button v-show="index > 0" @click="index--">上一页</button><div><img :src="list[index]" alt="" /></div><button v-show="index < list.length - 1" @click="index++">下一页</button></div><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {index: 0,list: ['./imgs/11-00.gif','./imgs/11-01.gif','./imgs/11-02.gif','./imgs/11-03.gif','./imgs/11-04.png','./imgs/11-05.png',],},});</script></body>
</html>
5.列表渲染指令(v-for)
作用:基于数据循环,多次渲染整个元素
v-for可以基于哪些数据进行遍历呢?
数组,对象,数字,其中基于【数组】遍历是我们常用的方式
遍历数组的语法:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"><h3>小黑水果店</h3><ul><li v-for="(item, index) in list">{{ item }} - {{ index }}</li></ul><ul><li v-for="item in list">{{ item }}</li></ul></div><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {list: ['西瓜', '苹果', '鸭梨', '榴莲'],},});</script></body>
</html>
不加 key-原地修改元素 (就地复用)
v-for的默认行为会尝试原地修改元素(就地复用)
就是根据数据重新渲染li标签,此时要渲染三次性能不好
加key - 正确排序复用
加key的作用:给元素添加唯一标识
加了key之后就只会删除一开始的li
6.双向数据绑定(v-model)
作用: v-model是给 表单元素 双向数据绑定的,可以快速 获取 或 设置 表单元素内容
双向数据绑定是什么?
① 数据变化 → 视图自动更新
② 视图变化 → 数据自动更新
语法: v-model = '变量'
扩展: v-model还可以给select、checkbox、radio、textarea等表单元素使用
<!--* @Date: 2025-01-02 17:38:11* @LastEditors: zl 1077167261@qq.com* @LastEditTime: 2025-01-02 17:51:40* @FilePath: \vue\vue基本语法\5.v-model.html
-->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="app"><!-- v-model 可以让数据和视图,形成双向数据绑定(1) 数据变化,视图自动更新(2) 视图变化,数据自动更新可以快速[获取]或[设置]表单元素的内容-->文本:<input type="text" v-model="msg" /><p>{{ msg }}</p><hr /><input type="radio" value="true" name="option" /> 是<input type="radio" value="false" name="option" /> 否<hr /><input type="checkbox" v-model="ischecked" /><p>当前选择: {{ ischecked }}</p><hr /><label for="fruit">选择水果:</label><select v-model="selectedFruit" id="fruit"><option disabled value="">请选择</option><option value="apple">苹果</option><option value="banana">香蕉</option><option value="orange">橙子</option></select><p>你选择了: {{ selectedFruit }}</p><hr />账户:<input type="text" v-model="username" /> <br /><br />密码:<input type="password" v-model="password" /> <br /><br /><button @click="login">登录</button><button @click="reset">重置</button></div><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {username: '',password: '',msg: 'hello',ischecked: true,selectedFruit: '',},methods: {login() {console.log(this.username, this.password);},reset() {this.username = '';this.password = '';},},});</script></body>
</html>
html,
body {margin: 0;padding: 0;
}
body {index.cssbackground: #fff;
}
button {margin: 0;padding: 0;border: 0;background: none;font-size: 100%;vertical-align: baseline;font-family: inherit;font-weight: inherit;color: inherit;-webkit-appearance: none;appearance: none;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}body {font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;line-height: 1.4em;background: #f5f5f5;color: #4d4d4d;min-width: 230px;max-width: 550px;margin: 0 auto;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;font-weight: 300;
}:focus {outline: 0;
}.hidden {display: none;
}#app {background: #fff;margin: 180px 0 40px 0;padding: 15px;position: relative;box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#app .header input {border: 2px solid rgba(175, 47, 47, 0.8);border-radius: 10px;
}
#app .add {position: absolute;right: 15px;top: 15px;height: 68px;width: 140px;text-align: center;background-color: rgba(175, 47, 47, 0.8);color: #fff;cursor: pointer;font-size: 18px;border-radius: 0 10px 10px 0;
}#app input::-webkit-input-placeholder {font-style: italic;font-weight: 300;color: #e6e6e6;
}#app input::-moz-placeholder {font-style: italic;font-weight: 300;color: #e6e6e6;
}#app input::input-placeholder {font-style: italic;font-weight: 300;color: gray;
}#app h1 {position: absolute;top: -120px;width: 100%;left: 50%;transform: translateX(-50%);font-size: 60px;font-weight: 100;text-align: center;color: rgba(175, 47, 47, 0.8);-webkit-text-rendering: optimizeLegibility;-moz-text-rendering: optimizeLegibility;text-rendering: optimizeLegibility;
}.new-todo,
.edit {position: relative;margin: 0;width: 100%;font-size: 24px;font-family: inherit;font-weight: inherit;line-height: 1.4em;border: 0;color: inherit;padding: 6px;box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);box-sizing: border-box;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}.new-todo {padding: 16px;border: none;background: rgba(0, 0, 0, 0.003);box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}.main {position: relative;z-index: 2;
}.todo-list {margin: 0;padding: 0;list-style: none;overflow: hidden;
}.todo-list li {position: relative;font-size: 24px;height: 60px;box-sizing: border-box;border-bottom: 1px solid #e6e6e6;
}.todo-list li:last-child {border-bottom: none;
}.todo-list .view .index {position: absolute;color: gray;left: 10px;top: 20px;font-size: 22px;
}.todo-list li .toggle {text-align: center;width: 40px;/* auto, since non-WebKit browsers doesn't support input styling */height: auto;position: absolute;top: 0;bottom: 0;margin: auto 0;border: none; /* Mobile Safari */-webkit-appearance: none;appearance: none;
}.todo-list li .toggle {opacity: 0;
}.todo-list li .toggle + label {/*Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/*/background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');background-repeat: no-repeat;background-position: center left;
}.todo-list li .toggle:checked + label {background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}.todo-list li label {word-break: break-all;padding: 15px 15px 15px 60px;display: block;line-height: 1.2;transition: color 0.4s;
}.todo-list li.completed label {color: #d9d9d9;text-decoration: line-through;
}.todo-list li .destroy {display: none;position: absolute;top: 0;right: 10px;bottom: 0;width: 40px;height: 40px;margin: auto 0;font-size: 30px;color: #cc9a9a;margin-bottom: 11px;transition: color 0.2s ease-out;
}.todo-list li .destroy:hover {color: #af5b5e;
}.todo-list li .destroy:after {content: '×';
}.todo-list li:hover .destroy {display: block;
}.todo-list li .edit {display: none;
}.todo-list li.editing:last-child {margin-bottom: -1px;
}.footer {color: #777;padding: 10px 15px;height: 20px;text-align: center;border-top: 1px solid #e6e6e6;
}.footer:before {content: '';position: absolute;right: 0;bottom: 0;left: 0;height: 50px;overflow: hidden;box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,0 17px 2px -6px rgba(0, 0, 0, 0.2);
}.todo-count {float: left;text-align: left;
}.todo-count strong {font-weight: 300;
}.filters {margin: 0;padding: 0;list-style: none;position: absolute;right: 0;left: 0;
}.filters li {display: inline;
}.filters li a {color: inherit;margin: 3px;padding: 3px 7px;text-decoration: none;border: 1px solid transparent;border-radius: 3px;
}.filters li a:hover {border-color: rgba(175, 47, 47, 0.1);
}.filters li a.selected {border-color: rgba(175, 47, 47, 0.2);
}.clear-completed,
html .clear-completed:active {float: right;position: relative;line-height: 20px;text-decoration: none;cursor: pointer;
}.clear-completed:hover {text-decoration: underline;
}.info {margin: 50px auto 0;color: #bfbfbf;font-size: 15px;text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);text-align: center;
}.info p {line-height: 1;
}.info a {color: inherit;text-decoration: none;font-weight: 400;
}.info a:hover {text-decoration: underline;
}/*Hack to remove background from Mobile Safari.Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio: 0) {.toggle-all,.todo-list li .toggle {background: none;}.todo-list li .toggle {height: 40px;}
}@media (max-width: 430px) {.footer {height: 50px;}.filters {bottom: 10px;}
}
<!--* @Date: 2025-01-02 17:54:51* @LastEditors: zl 1077167261@qq.com* @LastEditTime: 2025-01-02 18:12:25* @FilePath: \vue\vue基本语法\6.小黑记事本.html
-->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="./css/index.css" /><title>记事本</title></head><body><!-- 主体区域 --><section id="app"><!-- 输入框 --><header class="header"><h1>小黑记事本</h1><input placeholder="请输入任务" class="new-todo" v-model="value" /><button class="add" @click="add">添加任务</button></header><!-- 列表区域 --><section class="main"><ul class="todo-list"><li class="todo" v-for="(item,index) in lists" :key="item.id"><div class="view"><span class="index">{{index+1}}.</span><label>{{item.name}}</label><button class="destroy" @click="del(index)"></button></div></li></ul></section><!-- 统计和清空 --><footer class="footer"><!-- 统计 --><span class="todo-count">合 计:<strong> {{lists.length}} </strong></span><!-- 清空 --><button class="clear-completed" @click = delAll()>清空任务</button></footer></section><!-- 底部 --><script src="./vue2.7.16.js"></script><script>const app = new Vue({el: '#app',data: {id: 3,value: '',lists: [{ id: 1, name: '吃饭饭' },{ id: 2, name: '睡觉觉' },{ id: 3, name: '打豆豆' },],},methods: {del(idx) {this.lists.splice(idx, 1);},add() {if (this.value.trim()) {this.lists.unshift({id: this.id++,name: this.value,});this.value = '';} else {alert('请输入任务');}},delAll() {this.lists = [];}},});</script></body>
</html>
3.指令补充
1.指令修饰符
什么是指令修饰符?
指令修饰符就是通过“.”增加一些指令的后缀 ,让这个指令有不同的作用
常用:
① 按键修饰符 @keyup.enter → 键盘回车监听
② v-model修饰符
- v-model.trim → 去除首尾空格
- v-model.number → 转数字
③ 事件修饰符
- @事件名.stop → 阻止冒泡
- @事件名.prevent → 阻止默认行为
- @事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
<!--* @Date: 2025-01-03 09:45:28* @LastEditors: zl 1077167261@qq.com* @LastEditTime: 2025-01-03 09:45:33* @FilePath: \vue\2.watch与computed\1.指令修饰符.html
-->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>.father {width: 200px;height: 200px;background-color: pink;margin-top: 20px;}.son {width: 100px;height: 100px;background-color: skyblue;}</style></head><body><div id="app"><h3>v-model修饰符 .trim .number</h3>姓名:<input v-model.trim="username" type="text" /><br />年纪:<input v-model.number="age" type="text" /><br /><h3>@事件名.stop → 阻止冒泡</h3><div @click="fatherFn" class="father"><div @click.stop="sonFn" class="son">儿子</div></div><h3>@事件名.prevent → 阻止默认行为</h3><a @click.prevent href="http://www.baidu.com">阻止默认行为</a></div><script src="./vue.2.7.js"></script><script>const app = new Vue({el: '#app',data: {username: '',age: '',},methods: {fatherFn() {alert('老父亲被点击了');},sonFn(e) {// e.stopPropagation()alert('儿子被点击了');},},});</script></body>
</html>
2.v-model在表单元素中的使用
常见的表单元素都可以用 v-model 绑定关联 → 快速 获取 或 设置 表单元素的值
它会根据 控件类型 自动选取 正确的方法 来更新元素
值得注意的是在单选框与下拉菜单中v-model的使用有一些不一样
<!--* @Date: 2025-01-03 10:10:31* @LastEditors: zl 1077167261@qq.com* @LastEditTime: 2025-01-03 10:30:41* @FilePath: \vue\2.watch与computed\2.v-model操作表单.html
-->
<style>textarea {display: block;width: 240px;height: 100px;margin: 10px 0;}
</style><div id="app"><h3>小黑学习网</h3>姓名:<input type="text" v-model="user.username" /><br /><br />是否单身:<input type="checkbox" v-model="user.isSingle" /><br /><br /><!-- 前置理解:1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥2. value: 给单选框加上 value 属性,用于提交给后台的数据结合 Vue 使用 → v-model-->性别:<input type="radio" name="sex" value="1" v-model="user.sex" />男<input type="radio" name="sex" value="2" v-model="user.sex" />女 <br /><br /><!-- 前置理解:1. option 需要设置 value 值,提交给后台2. select 的 value 值,关联了选中的 option 的 value 值结合 Vue 使用 → v-model-->所在城市:<select v-model="user.city"><option value="101">北京</option><option value="102">上海</option><option value="103">成都</option><option value="104">南京</option></select><br /><br />自我描述:<textarea v-model="user.desc"></textarea><button @click="show">立即注册</button><hr />{{ user }}
</div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {user: {username: 'zs',isSingle: true,sex: '1',city: '101',desc: '你好我叫zs',},},methods: {show() {console.log(this.user);},},});
</script>
3.v-bind对样式的操作
为了方便开发者进行样式控制,
Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式 进行控制
① 操作class 类名 语法 :class = "对象/数组"
② 操作style行内样式 语法 :style = "样式对象"
1.操作class类名
操作class 类名 语法 :class = "对象/数组"
- 对象形式
如:
适用场景:一个类名,来回切换
- 数组形式
如:
适用场景:批量添加或删除类
<style>* {margin: 0;padding: 0;}ul {display: flex;border-bottom: 2px solid #e01222;padding: 0 10px;}li {width: 100px;height: 50px;line-height: 50px;list-style: none;text-align: center;}li a {display: block;text-decoration: none;font-weight: bold;color: #333333;}li a.active {background-color: #e01222;color: #fff;}
</style>
<div id="app"><ul><li v-for="(item,idx) in list" :key="item.id"><a @click="getActive(idx)" href="#" :class="{active:item.isActive}">{{item.name}}</a></li></ul>
</div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>const app = new Vue({el: '#app',data: {list: [{ id: 1, name: '京东秒杀', isActive: true },{ id: 2, name: '每日特价', isActive: false },{ id: 3, name: '品类秒杀', isActive: false },],},methods: {getActive(idx) {this.list.forEach((item, index) => {if (idx === index) {item.isActive = true;} else {item.isActive = false;}});},},});
</script>
2.操作style样式
语法 :style = "样式对象"
如:
适用场景:某个具体属性的动态设置
<style>#app {margin: 100px auto;text-align: center;}.progress {margin: 100px auto;height: 25px;width: 400px;border-radius: 15px;background-color: #272425;border: 3px solid #272425;box-sizing: border-box;margin-bottom: 30px;}.inner {width: 50%;height: 20px;border-radius: 10px;text-align: right;position: relative;background-color: #409eff;background-size: 20px 20px;box-sizing: border-box;transition: all 1s;}.inner span {position: absolute;right: -20px;bottom: -25px;}
</style><div id="app"><div class="progress"><div class="inner" :style="{width:percent +'%'}"><span>{{percent}}%</span></div></div><button @click="setPercent(25)">设置25%</button><button @click="setPercent(50)">设置50%</button><button @click="setPercent(75)">设置75%</button><button @click="setPercent(100)">设置100%</button><br /><br /><button @click="add">开始</button><button @click="percent=0">重置</button><button @click="clear">停止</button>
</div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script>const app = new Vue({el: '#app',data: {percent: 50,timer: null,},methods: {setPercent(num) {this.percent = num;},add() {//清除定时器this.clear();this.timer = setInterval(() => {this.percent += 1;if (this.percent >= 100) {this.clear();}}, 300);},clear() {clearInterval(this.timer);this.timer = null;},},});
</script>