在了解vue以前,咱们先区分框架和类库、渐进式框架等javascript
jQuery、Zepto、underscore... 类库提供的是真实项目中经常使用到的方法,它是一个工具包,基于这个工具包能够快速开发任何的项目html
TAB选项卡插件、BANNER轮播图插件、DIALOG模态框插件、DRAG拖拽插件... iscroll局部滚动插件、jquery中有不少的插件 插件是把项目中某一个具体的功能进行封装vue
bootstrap、swiper、mui、妹子UI... UI组件库通常是多个插件的集合体,不只提供了JS对应的功能,并且把结构、样式等也都实现了,咱们只须要作一名CV工程师就能够快速构建一个产品java
vue、react、uni-app、react native、flutter、angular(ng)、backbone... 通常来讲,框架是类库和组件的综合体,里面提供了大量供咱们操做的方法,也有配套的UI组件库供咱们快速开发;框架是具有独立编程思想的,例如:vue是MVVM思想,让咱们告别传统的DOM操做,按照视图和数据的相互渲染来完成项目开发,可是无论怎么变,都必定会比咱们以前基于原生操做更简单,性能更好...node
市面上经常使用的框架:vue(MVVM) / react(MVC) APP框架:uni-app / react native / flutterreact
vue.js 是一套构建用户界面的渐进式框架。jquery
vue只关注视图层, 采用自底向上增量开发的设计。ios
vue的目标是经过尽量简单的 API 实现响应的数据绑定和组合的视图组件。vue-router
vue 咱们如今学习和使用的是第二代版本vuex
参考资料:
中文文档: cn.vuejs.org/v2/guide/sy… ---> 强烈推荐
基于 $npm i vue
|$yarn add vue
安装
渐进式:类库或者框架都是重量级的,里面包含不少方法,可是实际项目开发中,咱们用不到这么多东西,因此在开发他们的时候,会把功能按照模块进行单独开发,使用者可根据自身状况选择一个模块一个模块的导入使用
这些东西就是VUE全家桶
MVVM是双向数据绑定的:VUE自己实现了数据和视图的相互监听影响 MVC是单向数据绑定,数据更改能够渲染视图,可是视图更改没有更改数据,须要咱们本身在控制层基于change事件实现数据的更改(REACT)
![]()
当初始化vue的实例时,会遍历data中的全部的属性,给每个属性新增get和set方法,
当获取这个属性对应的属性值,会默认执行get方法
设置属性的属性值时,会执行set方法;
vue的指令编译器,对vue的指令进行解析,并初始化视图,并订阅观察者来更新视图;
并将watcher添加到Dep订阅器中,当数据发生改变,observer的set方法会被调用,
会遍历Dep订阅器中全部的订阅者,而后再更新视图;
=> new Vue 每当建立一个实例,就至关于建立一个viewModel监听器:能够监听对应视图和对应数据的相互改变
=> el:element 当前监听器监听的视图(基于querySelector获取):指定的容器不能是HTML和BODY
=> data: 当前监听器监听的数据(这些监听的数据会挂载到vm1实例上,也就是vm1.msg=xxx来操做了)
=> {{msg}} 数据绑定最多见的形式就是使用 {{...}}(双大括号 小胡子语法)的文本插值
<body>
<div id='app'>
{{msg}}
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
/*--- 开发的时候尽量引用未压缩版本,这样有错误会抛出异常 --- */
<script>
let vm = new Vue({
el:'#app',
data:{
msg:'hello world~'
}
});
</script>
</body>
复制代码
new Vue(options)
返回值vm(viewModel)
el:不能挂载到html或者body上 =>querySelector
data
- 数据值对于对象来讲要先声明,不然新增属性无效(能够基于vm.$set处理)
- vm.arr[0]=xxx 改变数组中的某一项视图不会渲染,须要基于内置的方法,例如:push...
- 对象或者数组能够总体替换值实现数据变视图也变 ...
=> 在胡子语法中绑定的数据值是对象类型,会基于JSON.stringify
把其编译为字符串再呈现出来(而不是直接toString处理的)
=> 并非全部的数据更改最后都会通知视图从新渲染
初始数据是一个对象,对象中没有xxx键值对,后期新增的键值对是不会让视图从新渲染的,
解决办法:
1) 最好在初始化数据的时候,就把视图须要的数据提早声明好(能够是空值,可是要有这个属性) =>原理:只有DATA中初始化过的属性才有GET/SET
2) 不要修改某个属性名,而是把对象的值总体替换(指向新的堆内存)
3) 能够基于vm.$set
内置方法修改数据:vm.$set(obj,key,value)
若是数据是一个数组,咱们修改数据基于ARR[N]=xxx或者ARR.length--等操做方式,是没法让视图从新渲染的;
1) 须要基于:push/pop等内置的方法
2) 从新把ARR的值重写(指向新的堆内存)
3) vm.$set
<body>
// {{xxx}} => 小胡子语法
<div id="app">
{{obj}}
<br>
{{arr}}
<br>
{{'name' in obj?'OK':'no'}}
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let obj = {
name: ''
};
let arr = [10];
let vm = new Vue({
el: '#app',
data: {
obj,
arr
}
});
setTimeout(() => {
vm.arr.push(20);
vm.$set(vm.arr, 1, 20);
vm.obj.name = "蓝蓝"; // 需提早设置name属性
vm.$set(vm.obj, 'name', '蓝蓝');
}, 1000);
</script>
</body>
复制代码
VUE指令:directive
1.都是按照v-xxx处理的,它是vue中规定给元素设置的自定义属性
2.当vue加载成功并进行处理的时候,会按照相关的规则解析和宣传视图,遇到对应的指令实现对应的功能
v-model
通常给表单元素设置的,实现表单元素和数据之间的相互绑定
1)先把数据绑定给表单元素 ,通常把数据赋值给表单元素的value
复制代码
2)监听表单元素的内容改变
3)内容改变后,会把对应的数据也改变
4)对应的数据改变,视图中全部用到数据的地方都会从新渲染
视图 <=> 数据
复制代码
在vue框架中给表单元素设置value等属性是没有意义的
v-bind
给元素的内置属性动态绑定数据,例如:给img绑定动态的图片路径地址
能够简写成为 :
,也就是 v-bind:src
等价于 :src
v-html/v-text
:给非表单元素设置内容,v-html支持对于标签的自动识别,v-text会把全部内容分都当作文本
传统的胡子语法,在vue没有加载完成以前,会把{{xxx}}展现在页面中,当vue加载完才会出现真正的内容,这样体验很差
v-once:
绑定的数据是一次性的,后面不论数据怎么改变,视图也都不会从新渲染
v-if
若是对应的值是TRUE,当前元素会在结构中显示,若是是FALSE,当前元素会在结构中移除(它控制的是组件的加载和卸载的操做 =>DOM的增长和删除);还有对应的 v-else-if / v-else 等指令;
v-show
和v-if相似,只不过它是控制元素样式的显示隐藏(display的操做)
1)v-if是控制组件存不存在,对于结果是FALSE,不存在的组件来讲,视图渲染的时候无需渲染这部份内容;而v-show则不行,由于不论是显示仍是隐藏,结构都在,因此视图渲染的时候这部分也要渲染;
2)在过于频繁的切换操做中,v-if明显要比v-show要低一些
v-for
循环动态绑定数据
1) 想循环谁就给谁设置v-for
2) 循环相似for/for in的语法:v-for='(item,index) in arr'
v-on
(简写 @):用来实现事件绑定的指令
语法v-on:click='xxx'
| @click='xxx'
1.事件触发的时候,须要传递参数信息,把方法加小括号,$event是事件对象
v-on:click='sum($event,10,20)'
2.事件修饰符
常规修饰符:@click.prevent/stop = 'xxx'
按键修饰符:@keydown.enter/space/delete/up/right/down/left...='xxx'
键盘码:@keydown.13 = 'xxx'
组合按键:@keydown.alt.67 = 'xxx' //=>ALT+C
v-model
<body>
<div id="app"> 人民币:¥ <input type="text" v-model="priceRMB"> <br> 美圆:$ <span>{{priceRMB/7.1477}}</span> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.min.js"></script> <script> //=>v-model先实现把数据绑定到视图层(给INPUT设置VALUE值),而后监听文本框内容的改变,一旦改变,会把数据也跟着改变;数据一变,视图会从新的渲染; let vm = new Vue({ el: '#app', data: { priceRMB: 0 } }); </script> </body> 复制代码
v-bind
<body>
<div id="app"> <button v-html='msg' @click='handle'></button> <br> <img :src="pic" alt="" v-if='show'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { //=>这里的数据最后都会做为实例的属性挂载到实例上vm.show... msg: '隐藏图片', show: true, pic: '1.png' }, methods: { //=>这里的方法最后也会挂载到实例的私有属性上 handle() { //=>this:vm this.show = !this.show; this.msg = this.show ? '隐藏图片' : '显示图片'; } } }); </script> </body> 复制代码
v-for
<body>
<div id="app">
<table>
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
<tr v-for='(item,index) in arr'>
<td v-html='item.id'></td>
<td v-html='item.name'></td>
<td v-html='item.age'></td>
</tr>
</tbody>
</table>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
arr: [{
id: 1,
name: '张三',
age: 25
}, {
id: 2,
name: '李四',
age: 24
}, {
id: 3,
name: '王五',
age: 26
}]
}
});
</script>
<script>
//JS中循环的几种方式:for循环、while循环、do while循环 | for in循环 | for of循环
let arr = [10, 20, 30, 40],
obj = {
name: '',
year: 10,
1: 100
};
Object.prototype.AA = 12;
/*=>ES6新增for of循环
*1.获取的不是属性名是属性值
*2.不会遍历原型上公有的属性方法(哪怕是自定义的)
*3.只能遍历可被迭代的数据类型值(Symbol.iteratoer):Array、String、Arguments、NodeList、Set、Map等,可是普通对象是不可被迭代的数据,因此不能用for of循环
*/
for (let item of obj) {
console.log(item);
}
for (let key in arr) {
if (!arr.hasOwnProperty(key)) break;
console.log(key, arr[key]);
}
for (let key in obj) {
//=>KEY遍历的属性名
//=>OBJ[KEY]属性值
//=>优先遍历属性名为数字的
//=>会把所属类原型上自定义的属性方法也遍历到
if (!obj.hasOwnProperty(key)) break;
console.log(key);
}
</script>
</body>
复制代码
v-on
<body>
<div id="app"> <a href="http://www.baidu.com/" @click.prevent.stop='func'> 百度</a> <button v-on:click='func'></button> <button v-on:click='sum($event,10,20)'></button> <input type="text" placeholder="请输入搜索内容" v-model='text' @keydown.alt.67='func'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: '' }, methods: { func(ev) { alert('是我了~'); }, sum(ev, n, m) { console.log(arguments); } } }); </script> </body>
复制代码
表单元素的处理
单选或者复选按钮
1.按照 v-model 进行分组,单选框装备的数据是一个值,复选框准备的数据是一个数组
2.每个框都有本身的value,谁被选中,数据值就是被选中元素的value值;相反,值是多少,对应value的元素也会被默认选中;
<body>
<div id="app">
<input type="checkbox" value="OK" v-model='all' @click='handle'>全选/全不选
<br>
<div @change='delegate'>
<input type="checkbox" value="song" v-model='hobby'>唱歌
<input type="checkbox" value="dance" v-model='hobby'>跳舞
<input type="checkbox" value="read" v-model='hobby'>读书
<input type="checkbox" value="javascript" v-model='hobby'>编程
</div>
<br>
<button @click='submit'>提交</button>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
sex: 0,
hobby: ['javascript'],
all: []
},
methods: {
submit() {
console.log(this.sex);
},
handle() {
//=>CLICK事件处理比视图更新后数据的更改要先去作
if (!this.all.includes('OK')) {
this.hobby = ['song', 'dance', 'read', 'javascript'];
} else {
this.hobby = [];
}
},
delegate() {
//=>CHANGE事件处理,要晚于数据更新
this.all = this.hobby.length >= 4 ? ['OK'] : [];
}
}
});
</script>
</body>
复制代码
滤器的语法:按照竖线分隔,把竖线左侧的值传递给右侧的过滤器方法,通过方法的处理,把处理后的结果展现在视图中
过滤器方法只能在胡子语法{{}}和v-bind中使用(过滤器中的方法没有挂载到实例上)
/*如下 methods && filters 中各有方法*/
<body>
<div id="app">
<input type="text" v-model='text'>
<br>
/*<span v-text='text.replace(/\b[a-zA-Z]+\b/g,item=>{
return item.charAt(0).toUpperCase()+item.substring(1);
})'></span>
<span v-text='toUP(text)'></span>*/
<span>{{text|toUP|filterB}}</span>
<img :src="pic|picHandle" alt="">
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
//=>响应式数据:DATA中准备的要在视图中渲染的数据(MODEL)
text: ''
},
methods: {
//=>都会挂载到实例上(不能和DATA中的属性名冲突):这里的制定的方法是普通方法,能够在视图中调取使用,也能够在其它方法中调取使用
toUP(value) {
return value.replace(/\b[a-zA-Z]+\b/g, item => {
return item.charAt(0).toUpperCase() + item.substring(1);
});
}
},
filters: {
//=>设置过滤器:把须要在视图中渲染的数据进行二次或者屡次的处理
toUP(value) {
//=>value:须要过滤的数据 return返回的是过滤后的结果
return value.replace(/\b[a-zA-Z]+\b/g, item => {
return item.charAt(0).toUpperCase() + item.substring(1);
});
},
filterB(value) {
return value.split('').reverse().join('');
},
picHandle(value){
return value.length===0?'http://www.baidu.com/static/1.png':value;
}
}
});
</script>
</body>
复制代码
计算属性:它不是方法是一个属性,因此在视图中调取的时候不能加括号执行,toUP和DATA中的TEXT同样,都会挂载到实例上,它存储的值是对应方法返回的结果(getter函数处理的结果)
计算属性有本身的缓存处理:第一次获取toUP属性值,会关联某个响应式数据(text),当第一次结果获取后,会把这个结果缓存下来;后期视图从新渲染,首先看text值是否发生更改,若是发生更改,会从新计算toUP属性值,若是没有更改,则还会拿上次缓存的结果进行渲染;
<body>
<div id="app"> <input type="text" v-model='text'> <br> <span v-text='toUP'></span> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: '' }, computed: { toUP() { return this.text.replace(/\b[a-zA-Z]+\b/g, item => { return item.charAt(0).toUpperCase() + item.substring(1); }); } }, methods: { /* toUP(value) { return value.replace(/\b[a-zA-Z]+\b/g, item => { return item.charAt(0).toUpperCase() + item.substring(1); }); } */ } }); </script> </body> 复制代码
<body>
<div id="app">
<p>正常结果:{{text}}</p>
<p>反转结果:{{reverseMethod()}}</p>
<p>反转结果:{{reverseComputed}}</p>
<p>{{now2()}}</p>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
text: 'MY NAME IS LANLAN'
},
computed: {
//=>GETTER函数
reverseComputed() {
return this.text.split('').reverse().join('');
},
now1() {
//=>计算属性中必需要关联一个响应式数据,不然GETTER函数只执行一次
// 咱们也能够 =>强制更新视图的从新渲染
return new Date();
}
},
methods: {
reverseMethod() {
return this.text.split('').reverse().join('');
},
now2() {
return new Date();
}
}
});
let n = 0;
let timer = setInterval(() => {
n++;
if (n > 5) {
clearInterval(timer);
return;
}
if (n === 3) {
vm.text = 'WELCOME TO china;
return;
}
//=>强制更新视图的从新渲染
vm.$forceUpdate();
}, 1000);
</script>
</body>
复制代码
<body>
<div id="app"> <p>正常结果:{{text}}</p> <p>反转结果:{{reverseComputed}}</p> <input type="text" v-model='reverseComputed'> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { text: 'MY NAME IS LANLAN' }, computed: { //=>GETTER函数 /* reverseComputed() { return this.text.split('').reverse().join(''); } */ reverseComputed: { get() { //=>GETTER:只要获取这个属性值就会触发GET函数执行 return this.text.split('').reverse().join(''); }, set(value) { //=>SETTER:给属性设置值的时候会触发SET函数,VALUE是给这个属性设置的值 console.log('OK', value); } } } }); let n = 0; let timer = setInterval(() => { n++; if (n > 5) { clearInterval(timer); return; } if (n === 3) { vm.text = 'WELCOME TO CHINA'; return; } //=>强制更新视图的从新渲染 vm.$forceUpdate(); }, 1000); </script> </body>
复制代码
<body>
<div id="app">
<input type="checkbox" name="" id="check" v-model='slected'>
<label for="check" v-text='text'></label>
<br>
<span v-for='item in hobbyList'>
<input type="checkbox" name="" :id="item.id|handle" :value='item.value' v-model='checkList'>
<label :for="item.id|handle" v-text='item.name'></label>
</span>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
/*
* 1.手动点击全选按钮的时候会触发set,根据value控制checkList=>视图从新渲染=> 触发get;
* 2.点击每一个按钮的时候,v-model='checkList'监听改变 => 触发视图从新渲染,都会从新触发get=>判断是否全选
*/
let vm = new Vue({
el: '#app',
data: {
text: '全选/非全选',
hobbyList: [{
id: 1,
name: '唱歌',
value: 'song'
}, {
id: 2,
name: '跳舞',
value: 'dance'
}, {
id: 3,
name: '阅读',
value: 'read'
}, {
id: 4,
name: '睡觉',
value: 'sleep'
}],
//存储选中的兴趣爱好
checkList: [],
},
computed: {
// 存储选中按钮的选中状态
slected: {
// get:获取时触发;
get() {
return this.hobbyList.length === this.checkList.length;
},
// 点击全选按钮的时候会修改slected的值
set(value) {
// value:存储的是选中的状态 true|false
if (value) {
this.hobbyList.forEach(item => {
this.checkList.push(item.value)
});
return;
}
this.checkList = [];
}
}
},
filters: {
handle(value) {
return 'hobby' + value;
}
}
});
</script>
</body>
复制代码
watch监听响应式数据的改变(watch中监听的响应式数据必须在data中初始化) 和 computed中的setter相似
只不过computed是本身单独设置的计算属性(不能和DATA中的冲突),而watch只能监听DATA中有的属性
监听器支持异步操做 computed的getter不支持异步获取数据
<body>
<div id="app">
<input type="checkbox" v-model='slected' @change='handle'>全选/非全选
<br>
<span v-for='item in hobbyList'>
<input type="checkbox" :id="item.id|handleID" :value="item.value" v-model='checkList'>
<label :for="item.id|handleID" v-text='item.name'></label>
</span>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
hobbyList: [{
id: 1,
name: '唱歌',
value: 'song'
}, {
id: 2,
name: '跳舞',
value: 'dance'
}, {
id: 3,
name: '阅读',
value: 'read'
}, {
id: 4,
name: '睡觉',
value: 'sleep'
}],
//存储选中的兴趣爱好
checkList: [],
//存储全选状态
slected: false
},
watch: {
checkList() {
this.slected = this.checkList.length === this.hobbyList.length ? true : false;
}
},
methods: {
handle() {
if (this.slected) {
this.hobbyList.forEach(item => {
this.checkList.push(item.value);
});
return;
}
this.checkList = [];
}
},
filters: {
handleID(value) {
return 'hobby' + value;
}
}
});
</script>
复制代码
对象方式处理动态的样式
* `:class="{样式类名:响应式数据,...}"` 复制代码
* 响应式数据为TRUE则有这个样式类,反之则没有
- 数组控制样式类
*
:class="[响应式数据1,....]"
* 控制响应式数据的值是对应的样式类或者没有值,来控制是否有这个样式 复制代码
/*=== CSS ===*/
<style>
.active {
color: red;
}
.big {
font-size: 40px;
}
</style>
<body>
<div id="app">
<!-- 对象方式处理动态的样式 -->
<p :class="{active:a,big:true}">你好哇~</p>
<button @click='handle'>切换样式</button>
<button @click='a=!a'>切换样式</button>
<!-- 数组控制样式类 -->
<p :class="[active,big]">你好哇~~</p>
<button @click='handle'>切换样式</button>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
// a: false
active: '',
big: 'big'
},
methods: {
handle() {
this.active = this.active === '' ? 'active' : '';
// this.a = !this.a;
}
}
});
</script>
</body>
复制代码
VUE框架开发的时候,咱们应该尽量减小直接去操做DOM
基于REF能够把当前元素放置到this.$refs对象中,从而实现对DOM的直接操做(只有在mounted及以后才能够获取到)
<body>
<div id="app">
<h3 v-html='msg' ref='titleBox'></h3>
<p ref='pBox'></p>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
msg: '你好世界'
},
mounted() {
console.log(this.$refs); //=>{titleBox:H3,pBox:P}
}
});
console.log(vm.$refs.titleBox) // <h3>你好世界</h3>
</script>
</body>
复制代码
beforeCreate 建立vue实例以前
created 建立实例成功(通常在这里实现数据的异步请求)
beforeMount 渲染DOM以前(加载组件第一次渲染)
mounted 渲染DOM完成(加载组件第一次渲染)
beforeUpdate 从新渲染以前(数据更新等操做控制DOM从新渲染)
updated 重现渲染完成
beforeDestroy 销毁以前
destroyed 销毁完成 => 销毁以后,再去修改响应式数据值,视图也不会在从新的渲染了
/*---CSS---*/
<style>
*{
margin: 0;
padding: 0;
}
.tabBox {
box-sizing: border-box;
margin: 50px auto;
width: 500px;
}
.tabBox .tab {
display: flex;
position: relative;
top: 1px;
}
.tabBox .tab li {
list-style: none;
margin-right: 10px;
padding: 0 20px;
line-height: 35px;
border: 1px solid #AAA;
background: #EEE;
cursor: pointer;
}
.tabBox .tab li.active {
background: #FFF;
border-bottom-color: #FFF;
}
.tabBox .content {
display: none;
box-sizing: border-box;
padding: 10px;
height: 100px;
border: 1px solid #AAA;
}
.tabBox .content.active {
display: block;
}
</style>
/*--- JS ---*/
<body>
<div id="app">
<div class="tabBox">
<ul class="tab">
<li v-for='(item,index) in TAB_DATA' v-html='item.name' :class='{
active:index===curIdex}' @click='curIdex=index'></li>
</ul>
<div v-for='(item,index) in TAB_DATA' v-html='item.children' :class='{
content:true,active:index===curIdex}'></div>
</div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let TAB_DATA = [{
id: 1,
name: '音乐',
children: '音乐的内容'
},
{
id: 2,
name: '动漫',
children: '二次元的世界'
}, {
id: 3,
name: '读书',
children: '知识的芬芳'
}, {
id: 4,
name: '视频',
children: '视频的内容'
}, {
id: 5,
name: '新闻',
children: '最新报道'
}]
let em = new Vue({
el: '#app',
data: {
TAB_DATA,
curIdex: 0 // 默认显示选项卡的索引
}
})
</script>
</body>
复制代码
<body>
<div id="app">
<div class="tabBox">
<ul class="tab" @click='handle($event)'>
<li v-for='(item,index) in TAB_DATA' v-html='item.name' :class="{active:index===curIndex}"
:index='index'>
<!-- @click='curIndex=index' -->
</li>
</ul>
<div v-for='(item,index) in TAB_DATA' v-html='item.children'
:class="{content:true,active:index===curIndex}"></div>
</div>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let TAB_DATA = [{
id: 1,
name: '音乐',
children: '音乐的内容'
}, {
id: 2,
name: '影视',
children: '影视的内容'
}, {
id: 3,
name: '动漫',
children: '动漫的内容'
}, {
id: 4,
name: '纪录片',
children: '纪录片的内容'
}];
let vm = new Vue({
el: '#app',
data: {
//选项卡数据
TAB_DATA,
//展现选项卡的索引
curIndex: 0
},
methods: {
handle(ev) {
let target = ev.target,
tarTag = target.tagName;
if (tarTag === 'LI') {
this.curIndex = parseInt(target.getAttribute('index'));
}
}
}
});
</script>
</body>
复制代码
<style>
.tabBox {
box-sizing: border-box;
margin: 20px auto;
width: 600px;
}
.tabBox .tab {
display: flex;
position: relative;
top: 1px;
}
.tabBox .tab li {
margin-right: 10px;
padding: 0 20px;
line-height: 35px;
border: 1px solid #AAA;
background: #EEE;
cursor: pointer;
}
.tabBox .tab li.active {
background: #FFF;
border-bottom-color: #FFF;
}
.tabBox .content {
box-sizing: border-box;
padding: 10px;
height: 300px;
border: 1px solid #AAA;
}
</style>
</head>
<body>
<div id="app">
<div class="tabBox">
<ul class="tab">
<li v-for='(item,index) in TAB_DATA' v-html='item.name' :class="{active:index===curIndex}"
@click='handle($event,index,item.id)'>
</li>
</ul>
<div class="content" v-html='content'></div>
</div>
</div>
<!-- IMPORT JS -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
<script>
let TAB_DATA = [{
id: 1,
name: '音乐'
}, {
id: 2,
name: '影视'
}, {
id: 3,
name: '动漫'
}, {
id: 4,
name: '纪录片'
}];
let vm = new Vue({
el: '#app',
data: {
//选项卡数据
TAB_DATA,
//展现选项卡的索引
curIndex: 0,
//内容区域的数据
content: ''
},
created() {
//=>生命周期函数(VUE实例建立成功)
this.queryDATA(TAB_DATA[this.curIndex]['id']);
},
methods: {
queryDATA(curID) {
axios.get('./data.json').then(response => {
return response.data;
}).then(result => {
let itemDATA = result.find(item => parseInt(item.id) === parseInt(curID));
if (itemDATA) {
this.content = itemDATA.content;
return;
}
return Promise.reject();
}).catch(reason => {
this.content = '查无此信息';
});
},
handle(ev, index, id) {
if (this.curIndex === index) return;
this.curIndex = index;
this.queryDATA(id);
}
}
});
</script>
</body>
/*---data.json---*/
[{
"id": 1,
"content": "音乐的内容"
}, {
"id": 2,
"content": "影视的内容"
}, {
"id": 3,
"content": "动漫的内容"
}, {
"id": 4,
"content": "纪录片的内容"
}]
复制代码
<body>
<div class="wrap" id="wrap">
<div class="box">
<ul class="list">
<li v-for='(item,index) in DATA'>
<i @click='handle($event,"minus",index)'></i>
<em v-html='item.count'></em>
<i @click='handle($event,"plus",index)'></i>
<span>
单价:<strong v-html='item.price+"元"'></strong>
小计:<strong v-html='computedTotal(item.price,item.count)'></strong>
</span>
</li>
</ul>
<div class="info">
<span>商品公合计:<em v-html='total'></em>件</span>
<span>共花费了:<em v-html='totalPrice'></em>元</span>
<span>其中最贵的商品单价是:<em v-html='maxPrice'></em>元</span>
</div>
</div>
</div>
<!-- IMPORT JS -->
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
//数据
let DATA = [{
id: 1,
count: 0,
price: 12.5
},
{
id: 2,
count: 0,
price: 8.5
},
{
id: 3,
count: 0,
price: 4.5
},
{
id: 4,
count: 0,
price: 10.5
},
{
id: 3,
count: 0,
price: 20.0
}];
let vm = new Vue({
el: '#wrap',
data: {
DATA
},
methods: {
computedTotal(price, count) {
return price * count + '元'
},
handle(ev, type, activeIndex) {
this.DATA = this.DATA.map((item, index) => {
if (activeIndex === index) {
if (type === 'minus') {
item.count--;
item.count <= 0 ? item.count = 0 : null;
} else if (type === 'plus') {
item.count++;
item.count > 10 ? (item.count = 10,alert('不能太贪心哦~')) : null;
}
}
return item;
})
}
},
computed: {
// 总计
total() {
return this.DATA.reduce((accumulator, item, index) => {
return accumulator + item.count;
}, 0)
},
// 总价格
totalPrice() {
return this.DATA.reduce((accumulator, item, index) => {
return accumulator + item.count * item.price;
}, 0)
},
// 最贵
maxPrice() {
//找到count不为0的数据,返回最大价钱
let arr = this.DATA.filter(item => {
return item.count >= 1;
}).map(item => {
return item.price;
});
// 初始count都为0,因此arr为空
return arr.length === 0 ? 0 : Math.max(...arr);
}
}
})
</script>
</body>
复制代码