三阶段-vue
- mvvm m数据
-
m --> v
<div id="app"> {{ msg }} </div> <script src="./vue.js"></script> <script> const vm = new Vue({ el:"#app", data: { // 存放数据 msg:'你好vue' } }) </script>
vue中的模板 {{}}
主要用于渲染视图(渲染m) {{}}
-
渲染数据 (写表达式 变量只认识 实例上变量)
-
调用函数 (只会调用实例上的 方法)
const vm = new Vue({ el: '#app', data: { // 定义实例的数据 msg: '你好世界' }, methods: { // 定义实例的方法 act(){ console.log(111) } } }) // new Vue 传入对象 data中属性和 methods中的方法会直接挂在到实例上
'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
'require'
vue指令 扩展了 标签(组件) 属性 如何使用指令 <组件 v-指令名=值/> 指令的值 是一个 js环境 里面的变量 需要是实例上的属性(否则找不到报错)
-
v-model 将表单控件的值和 一个 实例数据进行双向绑定
-
v-text 不需要刻意记
-
v-html 渲染富文本数据
-
v-bind:属性 将标签 普通属性(包含任何自定义属性) 变成动态属性(属性值 与 实例的数据进行绑定) 简写 :属性
-
v-on:事件 将 标签 的事件 与 实例方法进行绑定(事件触发时 ,实例方法会调用) 简写 @事件
- v-once 让元素内部的 数据只渲染一次
// 作为事件函数 事件函数的第一个参数就是事件对象 <button @click="fn"></button> new Vue({ methods: { fn(e){ e.stopPropagation(); // 阻止冒泡 } } }) // 直接调用 需要传参时候 fn不再事件函数,只是在事件发生时,调用了 这个方法 // vue 提供了一个 类似于全局变量 $event <button @click="fn(11, $event)"></button> new Vue({ methods: { fn(n,e){ console.log(n); e.preventDefault(); } } })
<div id="app">
<div id="div1" @click="fn1(1)">
<div id="div2" @click="fn2(2)">
<div id="div3" @click="fn3(3, $event)"></div>
</div>
</div>
</div>
<script src="./vue.js"></script>
<script>
var a = 10;
const vm = new Vue({
el: '#app',
data: {
msg: '你好世界',
},
methods: {
fn1(n){
alert(n)
},
fn2(n){
alert(n)
},
fn3(n, e){
console.log(this);
e.stopPropagation();
console.log(e.target);
alert(3)
}
}
})
</script>
.stop // 阻止事件冒泡 .prevent // 阻止默认事件 .capture // 捕获阶段就提前触发 .once // 只绑定一次 .self // 事件只能由自身触发 后代元素无法触发(不能事件委托了)
//vue的显示隐藏案列
<style> #box1 { position: fixed; top: 0; left: 0; bottom: 0; right: 0; margin: auto; z-index: 1000; background-color: rgba(0, 0, 0, .6); display: flex; align-items: center; justify-content: center; } #connect { width: 40%; height: 40%; background-color: #fff; } </style> </head> <body> <div id="box"> <button @click="tab">{{ isshow?'显示':'消失' }}</button> <div id="box1" v-show='isshow' @click.self="change"> <div id="connect"> //在这阻止此div的冒泡也可达到此效果,@click.stop即可 苗有方之所以放下弓箭,并察觉出这些人有问题,靠的不是智慧,而是武者的危机预感没有反馈。 这说明那群飞兽军没有敌意。 “不对?” 许二郎抬了抬手,挡开要强行护送他离开的百夫长,侧头看向苗有方。 </div> </div> </div> </body> <script src="./vue.js"></script> <script> var vm = new Vue({ el: '#box', data: { isshow: false, }, methods: { tab() { this.isshow = !this.isshow }, change () { this.isshow = false } } }) </script>
v-if 将一个元素显示消失 与 一个变量进行绑定(true显示 false消失)
对比 v-show 相同点:控制元素的显示消失的状态 不同点: v-show 控制元素的 display:none 属性 控制显示消失 v-if 如果值为false时,则 直接移除这个元素(不渲染) 使用场景: v-show 适用于频繁切换 状态时 v-if 初始 不 渲染(初始值为false 且 不频繁切换)
v-if 搭配使用 v-else-if v-else 搭配使用时 一定是连续的兄弟 且 v-if是第一个兄弟 v-else 是最后一个兄弟
<style> #box{ width: 200px; height: 200px; background-color: rgb(211, 24, 24); margin: 100px auto; } #box2{ width: 200px; height: 200px; background-color: rgba(30, 167, 60, 0.459); margin: 100px auto; } #box3{ width: 200px; height: 200px; background-color: rgba(153, 114, 78, 0.459); margin: 100px auto; } </style> </head> <body> <div id="app"> <button @click="change">显示</button> <div id="box" v-if="num%3 === 0">111</div> <div id="box2" v-else-if="num%3===1">222</div> <div id="box3" v-else>333</div> </div> <script src="./vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { num: 0 }, methods: { change(){ this.num++; } } }) // btn.addEventListener('事件',回调函数,[false/true]) </script>
// 循环数组 <ul> <li v-for="item in arr"> {{ item }} </li> </ul> // 循环并定义下标 <ul> <li v-for="(item,index) in arr"> {{ item }} {{ index }} </li> </ul> /* 注意: 循环时声明的循环变量和循环下标,作用域 是循环这个元素内部 如果出现 循环嵌套循环,注意 内层循环变量和下标不要出现命名冲突 否则:在内层循环拿不到外层循环变量和外层循环下标 */ new Vue({ el: '#app', data:{ arr: [1,2,3,4] } })
复杂渲染
<div id="app">
<div class="floor" v-for="(floor,index) in floors">
<h2>
{{ floor.title }}
</h2>
<ul>
<li v-for="(item,index2) in floor.items">
<h5>{{ item.name }}</h5>
<p>{{item.price}}</p>
</li>
</ul>
</div>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
floors:[
{
title:"手机",
items: [
{
name:"商品1",
price: 10
},
{
name:"商品2",
price: 30
},{
name:"商品3",
price: 40
},{
name:"商品4",
price: 10
}
]
},
{
title:"电视",
items: [
{
name:"商品1",
price: 10
},
{
name:"商品2",
price: 30
},{
name:"商品3",
price: 40
},{
name:"商品4",
price: 10
}
]
},
{
title:"笔记本",
items: [
{
name:"商品1",
price: 10
},
{
name:"商品2",
price: 30
},{
name:"商品3",
price: 40
},{
name:"商品4",
price: 10
}
]
}
]
},
methods: {
removeLi(i){
this.arr.splice(i, 1);
}
}
})
// btn.addEventListener('事件',回调函数,[false/true])
</script>
☆☆☆过程: 当我们 new Vue 创建一个vm(实例时),需要传入一个对象,对象有一个data属性也是对象,vue会自动遍历 data对象。拿到他里面所有属性,使用Object.defineProperty;得到每一个data中属性的getter和setter 每一个 实例创建后 还会创建一个 watcher(观察者), 在setter触发时(data中属性值改变了),通知观察者, 观察者回调函数中,会立即调用(render渲染模板 一般是隐藏),实例的render方法,重新生成 虚拟dom ...
虚拟dom在vue中的 作用: 第一次 vue在渲染真实dom后,都会将基于真实dom,生成虚拟dom,保存在内存中,当改变了数据后,setter通知观察者,重新调用render函数 生成 数据改变 新的虚拟的dom树,和 上一次 保存在内存中的虚拟dom树进行比较(diff算法) ,得到最少代价去操作dom diff在比较中做了什么: dom树中 不同的层级 按照相同层级进行比较 key属性在diff算法 比较时做了什么: 要求key是独一无二 要求:循环中 必须要加 key属性 为了加快diff 比较效率
虚拟dom 概念:用js 对象的 结构来描述一段dom树
<div id="box" class="wrap">
<p class="op">你是p</p>
<span>我是span</span>
文本内容
</div>
{
tagName:"div",
attrs:{
id: 'box',
className:"wrap"
},
children: [
{
tagName:"p",
attrs: {
className:'op'
},
chidren: ['你是p']
},
{
tagName:"span",
attr:null,
children: ['我的span']
},
'文本内容'
]
}
<div :class="a"></div> // class="box" <div :class="b"> // class="box box2" <div :class="[a,'box2']"> // class="box box2" <div :class="{active:表达式}"> // div有没有active类,取决于active属性值是不是真 { data:{ a: 'box', b: [a,'box2'] } }
<div id="app">
<div :style="sty"></div>
<div :style="{width:100+300+500+'px',height:2>3?'100px':'500px',background:'skyblue'}"></div>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:"#app",
data: {
sty:{
width: '200px',
height: '300px',
background: 'blue'
}
}
})
</script>
<div id="app">
<div :style="sty"></div>
<div :style="{width:100+300+500+'px',height:2>3?'100px':'500px',background:'skyblue'}"></div>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:"#app",
data: {
sty:{
width: '200px',
height: '300px',
background: 'blue'
}
}
})
</script>
vue记事本案列
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div id="app">
<div class="wrap" style="max-width:600px;margin:20px auto">
<h2>今日事、今日毕</h2>
<div class="row">
<div class="col-md-10 col-sm-10">
<input type="text" v-model="inputTxt" class="form-control">
</div>
<div class="col-md-2 col-sm-2">
<button @click="addTodo" class="btn btn-primary">增加</button>
</div>
</div>
<div class="content" style="margin-top: 10px">
<ul class="list-group">
<li v-if="!todos.length" class="text-center list-group-item">暂无代办事项</li>
<li
v-for="(todo,index) in todos"
:key="index"
class="list-group-item">
{{ todo.content }}
<button
@click="delTodo(index)"
class="btn btn-danger btn-xs">删除</button>
<button
:disabled="todo.isCompleted" class="btn btn-success btn-xs">{{ todo.isCompleted?'已完成':'点击完成' }}</button>
</li>
</ul>
</div>
</div>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
inputTxt:'',
todos:[
{
content:'明天爬山',
isCompleted: false
},
{
content:'明天爬1111',
isCompleted: true
}
]
},
methods: {
delTodo(index){
// 删除代办事项
if(confirm('您确认删除吗?')){
this.todos.splice(index,1)
}
},
addTodo(){
// 添加代办事项
if(this.inputTxt.trim() === ""){
return
}
this.todos.push({
content: this.inputTxt,
isCompleted: false
})
this.inputTxt = "";
}
}
})
</script>
-
this.$set(对象,属性,值) // 手动强制 调用render 刷新视图 // eg this.$set(this.arr, 1, 100);
-
<div id="app">
<button @click="add">增加一个数据</button>
<div v-if="isShow">
<button @click="changeMsg">改变msg</button>
{{ msg }}
</div>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
isShow: false
},
methods: {
add(){
this.msg = '你好世界';
this.isShow = true;
},
changeMsg(){
this.msg="hello world";
}
}
})
</script>
vue购物车案列
<!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>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div id="app">
<table style="max-width:600px;margin: 50px auto;" class="table table-bordered table-hover">
<thead>
<tr>
<th>商品名称</th>
<th>商品价格</th>
<th>商品数量</th>
<th>小计</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="5" class="text-center">
暂无商品
</td>
</tr>
<tr v-for="(item,index) in items" :key="item.id">
<td>
<input
@change="singleCheck"
type="checkbox" :value="item.id" v-model="checkArr">
{{ item.name }}
</td>
<td>{{ item.price }}</td>
<td>
<button @click="addNum(index)" class="btn btn-xs">+</button>
<span>{{item.num}}</span>
<button @click="reduceNum(index)" class="btn btn-xs">-</button>
</td>
<td>{{ (item.num*item.price).toFixed(2) }}</td>
<td>
<button @click="delItem(index)" class="btn btn-danger btn-xs">删除</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
全选:
<input
@click="allChecked"
:checked="items.length === checkArr.length" type="checkbox">
总价格:{{ total }}
</td>
</tr>
</tfoot>
</table>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:'#app',
data: {
items: [ // 所有商品
{
id:1,
name:"商品1",
price: 15.5,
num: 2
},
{
id:2,
name:"商品2",
price: 18.5,
num: 1
},
{
id:3,
name:"商品3",
price: 20.5,
num: 1
},
{
id:4,
name:"商品4",
price: 19.9,
num: 1
}
],
total:0, //总价格
checkArr: [1,3,4] // 所有选中商品 id
},
methods: {
singleCheck(){
// 点击改变商品选中状态
this.calcTotal();
},
delItem(index){
if(confirm('您确认删除吗?')){
this.items.splice(index, 1);
this.calcTotal();
}
},
addNum(index){
// 增加购买数量
this.items[index].num++;
this.calcTotal();
},
reduceNum(index){
this.items[index].num--;
if(this.items[index].num <= 1){
this.items[index].num = 1;
}
this.calcTotal();
},
calcTotal(){
// 计算总价格
/*
所有选中商品的 价格*数量的总和
*/
let checkedItems = [];
this.items.forEach(item=>{
//console.log(item.id)
if(this.checkArr.includes(item.id)){
checkedItems.push(item);
}
})
this.total = 0;
checkedItems.forEach(item=>{
this.total += item.num*item.price
})
this.total = parseFloat(this.total.toFixed(2));
},
allChecked(e){
console.log(e.target.checked)
let allItemsIdS =[]; //所有商品id数组
this.items.forEach(item=>{
allItemsIdS.push(item.id);
})
if(e.target.checked){
this.checkArr = allItemsIdS;
}else{
this.checkArr = [];
}
this.calcTotal();
}
},
mounted() {
this.calcTotal();
}
})
</script>
</body>
</html>

浙公网安备 33010602011771号