Es6的补充
<body>
<button class="btns">第一个</button>
<button class="btns">第二个</button>
<button class="btns">第三个</button>
<button class="btns">第四个</button>
<script>
// ES5 之前,都没有块级作用域的概念, 以至于只能使用function 来解决作用域问题
// 1. 变量作用域 => 全局
{
var name ="why";
console.log(name);
}
console.log(name);
// 2. 没有块级作用域引起的问题: if 的块级
var func;
if(true) {
var name = 'why',
func = function() {
console.log(name);
}
func() // 此处执行可打印 why
}
name="kobe";
func(); // 此处不打印 kobe
// 以上例子, name 是if语句内定义, 没有块级作用域导致在if语句外也能修改name 的值
// 3. 没有块级作用域引起的问题: for 的块级
// var btns = document.getElementsByClassName("btns");
// for(var i=0; i<btns.length; i++) {
// btns[i].onclick = function() {
// console.log(i);
// }
// }
// 4. 使用闭包解决 没有块级作用域的问题
var btns = document.getElementsByClassName("btns");
for(var i=0; i<btns.length; i++) {
(function(num){
btns[i].onclick = function() {
console.log(i);
}
})(i);
}
/* ES6 */
if(true) {
const info_name = 'const';
console.log(info_name);
}
// 1. 注意一: 一旦给const 修饰的标识符被赋值后, 不可修改
// 2. 在使用cosnt 定义符, 必须进行赋值
const info_index = 1; // 不可 const info_index;
// 3, 常量的含义是指向的对象不可修改, 但可修改对象内部的属性
const obj = {
name: 'why',
age: 18,
height: 188
}
obj.name = "kobe"; // 可这样操作, 且obj.name 将会被kobe 替换
// 而不可修改 obj 这个对象 , 如 const obj = [];不可将对象改成数组
// 1. ES5 写法 字面量写法
/*
const info_obj = {
info_name: 'why',
info_age : 18,
info_height : 188
}
*/
// 2. ES6写法 增强写法
const info_name = 'why';
const info_age = 18;
const info_height = 188
const info_obj = {
info_name,
info_age,
info_height
}
</script>
vue 初体验
<!--
1. Vue 初体验: 创建一个hellow文件
1. 创建html 文件, 使用内联模式引入 vue.js文件
2. 创建一个ID 为 app 的div元素
1. 在<script> 标签内 创建一个常量 app , 将创建的vue实例赋值给常量
1. el => element 元素
2. data 在此处 与模块的data(){return {}} 不同, 组件中的data必须是个函数
3. vue实例的数据是响应式的 =>? 当在页面开发者工具consle处 修改
app.data.message 的值后, 页面 message 的值也会跟着修改
4. 在html标签内 插入值 =》 mustache 语法 {{}}
5. mustache 语法 内 不仅可以插入值, 也可以使用表达式
-->
<div id="app">
{{message}}
{{message + sex}}
</div>
<script>
// const 常量 let 变量
const app = new Vue({
el: "#app",
data: {
message: "hellow",
sex: '难'
}
})
</script>
<!--
2. 使用循环 v-for
1. 创建 vue实例, 绑定元素 circulation => 循环
2. v-for 的值 中, 多个单词用逗号隔开, 并使用括号v-for="(item, index) in move"
3. 一般的 使用了 循环语法, 后带 :key="index"
-->
<div id="circulation">
<ul>
<li v-for="(item, index) in move" :key="index">{{item}}</li>
</ul>
</div>
<script>
const circulation = new Vue({
el: "#circulation",
data: {
move: ['奥特曼', '哪吒','娜扎','娃哈哈']
}
})
</script>
<!--
3. 点击按钮 修改 count 的值
1. 创建computed元素
2. 班定 count 数据
3. 添加methods 方法, 使用 v-on:click 方法 语法糖:@
-->
<div id="computed">
<div>
<p>{{count}}</p>
<button @click="increase">+</button><button v-on:class="decrease">-</button>
</div>
</div>
<script>
const computed = new Vue({
el: "#computed",
data: {
count: 1,
currentIndex: 0
},
methods: {
// increase 增加 decrease 减少
// 下面的方法为 ES6写法 increase() {} === increase: function() {}
increase() {
this.count++
},
decrease: function() {
this.count--
}
}
})
</script>
<!--
4. MVVM => model view view-model 数据, 视图, 视图模型
5.
1. methods 方法
2. function 函数
3. Vue的生命周期
4. 挂载
5. 钩子
6. 回调函数
-->
02- 插值操作
<div id="app">
<!--
1. v-for:="item in students"
-->
<div>v-for 循环: <span v-for="item in students">{{item + '-'}}</span></div>
<!--
2. v-once : 数据在往后的操作中都不会被修改
1. 如 : 在浏览器开发者模式 修改 app.once="hhh", 页面中的{{once}}显示的内容不会发生改变
-->
<div>v-once : <span v-once>{{once}}</span></div>
<!--
3. v-html :
将数据url 以html的标签值形式显示, 隐藏标签
-->
<div>正常显示: <span >{{url}}</span></div>
<div>v-html: <span v-html="url"></span></div>
<!--
4. v-text : 显示文本
与{{}} 语法相同, 但不够灵活 => 一下 标签内的文本将不会显示, 而{{}}语法则正常拼接
-->
<div v-text="message">,你好啊</div>
<div >{{message}},你好啊</div>
<!--
5. v-pre 保留 预先输出格式
-->
<div>{{message}}</div>
<div v-pre>{{message}}</div>
<!--
6. v-cloak 斗篷
在vue 解析之前, div中有一个属性v-cloak
在vue 解析之后, div中没有一个属性v-cloak
1. 斗篷的作用:
1. 当浏览器加载页面 , vue 解析未结束前, 执行 v-cloak 属性
2. 当浏览器加载 vue解析后, v-cloack属性将删除
// 假装以下样式在 <head>处
<style>
[v-cloak] {
display: none;
}
</style>
-->
<div >{{message}}</div>
<!--
7. 使用 v-bind 与 v-for 结合实现, 点击某一个值, 该值颜色变红
1. v-for 语句拥有index属性值
1. 动态绑定class, 当设置的currentIndex 值 全等于index 时,active为真
2. 交互方法: 修改currentIndex 的值 = index
-->
<div class="box">
<ul>
<li v-for="(item, index) in students" @click="btnclick(index)" :key="index" :class="{active: currentIndex === index}">{{item}}</li>
</ul>
</div>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hellow',
once: '一次',
students: ['小明','小红', '小兰'],
url: '<a href="www.baidu.com">百度一下</a>',
isActive: true,
currentIndex: 0
},
methods: {
btnclick(index) {
return this.currentIndex = index
}
}
})
</script>
03- 动态绑定属性
="app">
<!--
1. v-bind 绑定属性 => 语法糖 :
1. 绑定属性 :src :value :class :title :href ...
2. 作用: 不写死数据, 在后台服务器请求数据, 动态修改属性值
-->
<a v-bind:href="url">百度一下</a>
<!--
2 .对象语法: :class="{active:isActive}
对象内可使用表达式或使用键值对{active:false, line:true}
-->
<p :class="{active:isActive}">动态修改文字颜色</p>
<p :class="{active:false, line:true}">添加键值对</p>
<button @click="btnClick">切换</button>
<!--3. 数组语法: 一般不这么使用-->
<h1 :class="[info_a, info_b]">获取类名</h1>
<!--
4. 使用方法 : getClass() , 添加了括号代表立即执行
-->
<h1 :class="getClass()">修改类名</h1>
<!--
5. 使用动态绑定 <style>
1. 对象语法
1. :style="{fontSize: '50px'}"
2. :style="{fontSize: finalSize + 'px'}" => 此处finalSize 是data内的一个数据
3. :style="{'font-size': finalSize + 'px}'"
2. 数组语法
1. :style="[baseStyle, baseStyle1]"
-->
</div>
script>
const app = new Vue({
el: '#app',
data: {
url: 'www.baidu.com',
isActive: true,
info_a: 'aaa',
info_b: 'bbbb',
finalSize: 100,
baseStyle: {background: 'red'},
baseStyle1: {color: '#f00'}
},
methods: {
btnClick() {
this.isActive = !this.isActive
},
getClass() {
// 将值返回
return [this.info_a, this.info_b]
}
}
})
</script>
04- 计算属性
<div id="app">
<!--
1. methods 方法 => 每次调用都会刷新页面
2. computed 计算属性 ,
1. 有缓存, 每次调用时,当数据没有变化时, 将最后一次修改的结果返回
2. 执行computed属性, 无需使用括号, 直接以数据的形式传入 mustan语法
3. 当computed 修改了数据后, 缓存将会清空
-->
<p>总价格: {{totalPrice}}</p>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{id: 1, name: 'html', price: 10},
{id: 2, name: 'java', price: 20},
{id: 3, name: 'css', price: 30},
{id: 4, name: 'python', price: 40}
]
},
computed: {
totalPrice() {
let result = 0
// for (let i in this.books) {
// for (let i of this.books) {
for (let i=0; i<this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
</script>
<div id="computed">
{{fullName}}
</div>
<script>
const info_com = new Vue({
el: '#computed',
data: {
first_name: 'kobe',
last_name: 'jenny'
},
computed: {
// 计算属性是一个对象, 对象内有set和get 两个函数方法,
// 每次调用都会执行set , get 而set方法一般很少使用, 则演变成了
//直接将get set 隐藏 , fullName : function() {} => fullName(){}
fullName: {
set: function(info_value) {
//console.log('0000', info); 每次行计算属性都会执行set方法
// 当开发者模式 修改 info_com.fullName= 'hha hahha' 时, 页面的fullName值将会改变
const names = info_value.split(' ')
this.first_name = names[0]
this.last_name = names[1]
},
get: function() {
return this.first_name + " " + this.last_name
}
}
}
})
</script>
05-事件监听
<div id='app'>
<!--
1. 当方法没有添加括号时, 触发后会返回一个event 值
-->
<button @click="btnClick">按钮1</button>
<!--
1.当添加了括号() 却没有传参, 则会输出 undefine
-->
<button @click="btnClick1()">按钮2</button>
<!--
1. 当函数由多个形参, 而调用函数传入实参的个数不够时, 未传入的形参将会输出undefine,
2. 若要获取event, 则 $event 需要跟在形参的最后
3. 当形参传入没有使用 引号时, 默认调用 data中的数据
-->
<button @click="btnClick2('index',$event)">按钮3</button>
<button @click="btnClick2(index,$event)">按钮4</button>
</div>
<script src='../../vue.js'></script>
<script>
const app = new Vue ({
el: '#app',
data : {
message: 'hah',
index: 5
},
methods: {
btnClick() {
console.log(event)
},
btnClick1(info_index) {
console.log(info_index);
},
btnClick2(info_index, event) {
console.log(info_index, event);
}
}
});
</script>
06-v-on 修饰符
div id='app'>
<div>
<p>{{message}}</p>
<!--
1. @click.stop 事件冒泡:
1. 当父按钮不使用修饰符.stop时, 点击按钮将会触发父元素的parentBtn() 执行
2. .stop 阻止事件冒泡
-->
<div @click="parentBtn">
<button @click.stop="childBtn">父按钮</button>
</div>
<!--
2. @click.prevent 的使用
2. 当不使用 .prevent 修饰符时, 点击按钮将会提交并跳转页面
1. 使用了修饰符后, 将会提交数据 并阻止页面跳转
-->
<div>
<input type="submit" value="提交" @click="childBtn">
</div>
<!--
3. @click.enter 键盘监听
4. @click.once 事件只允许触发一次
-->
</div>
</div>
<script>
const app = new Vue ({
el: '#app',
data : {
message: 'hah'
},
methods: {
parentBtn() {
console.log('parent')
},
childBtn() {
console.log('children')
}
}
});
</script>
07- 条件语句
<div id='app'>
<span v-if="isActive">
<p>用户名 : <input type="text" id="info_text" placeholder="用户"></p>
</span>
<span v-else>
<p>邮箱: <input type="text" id="info_email" placeholder="邮箱"></p>
</span>
<button @click="btnClick">切换</button>
</div>
<script>
const app = new Vue ({
el: '#app',
data : {
message: 'hah' ,
isActive: true
},
methods: {
btnClick() {
this.isActive = !this.isActive
}
}
});
</script>
循环语句
v-for :
1. item => 元素
2. index = > 索引
3. value => 值
4. key 属性 : 高效的更新 虚拟DOM
diff 算法 = 》 different 不同
Array: 数组的方法
1. arr.pop() 删除最后一个值
2. arr.push(value) 在最后一个值添加
3. arr.shift(value) 删除第一个值
4. arr.unshift() 在最前面添加值
5. arr.concat(arr) 拼接数组
6. arr.join('符号') 在数组的值与值之间使用 符号拼接
7. arr.splic()
8. arr.sort()
9. arr.reverse() 倒叙
<div id='app'>
</div>
<script src='../../vue.js'></script>
<script>
// 形参 ...num 代表剩余参数, 可在数组中使用 , === arguments
function computed(...num) {
let sum = 0;
return sum +=num;
}
console.log(computed(10,20,30,10,40,20))
const app = new Vue ({
el: '#app',
data : {
message: 'hah'
}
});
</script>
09- 图书馆购物车
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: #f6f6f6;
}
#app {
position: absolute;
left: 0;
right: 0;
top: 200px;
}
.table {
width: 700px;
border: 1px solid #ccc;
text-align: center;
}
.table td {
border: 1px solid #ccc;
padding: 5px 10px;
font-size: 14px;
}
.table thead tr td {
font-weight: bold;
font-size: 14px;
}
</style>
<div id='app'>
<!-- 当 books 这个数组的长度大于0 则条件成立显示 购物栏, 否则将执行 v-else 语句 -->
<div v-if="books.length">
<table class="table">
<thead>
<tr>
<td class="index"></td>
<td class="books_name">名称</td>
<td class="books_time">出版日期</td>
<td class="books_price">价格</td>
<td class="books_count">数量</td>
<td class="book_delete">移除</td>
</tr>
</thead>
<tbody>
<!--
1. v-for 循环遍历, 多个值 使用逗号隔开,并在括号内
-->
<tr v-for="(item, index) in books">
<td>{{item.index}}</td>
<td>{{item.name}}</td>
<td>{{item.time}}</td>
<!--
1. fullToFix 是一个过滤器语句
相等于 {{"¥ " + item.price.toFixed(2)}}
2. 过滤器有形参 price, 使用时无需传入实参
-->
<td>{{item.price | fullToFix}}</td>
<td>
<!--
1. 使用index 来确定当前所点击的按钮属于第几行
2. :disable 语句执行的条件时当 书本的个数等于0时, 按钮不可点击
-->
<button @click="decreament(index)" :disabled="item.count === 0">-</button>{{item.count}}<button @click="increament(index)">+</button>
</td>
<td><button @click="btnClick(index)">移除</button></td>
</tr>
</tbody>
</table>
<div class="totalprice">
<p>总价格: {{totalPrice | fullToFix}}</p>
</div>
</div>
<div v-else>
<p>您的购物车为空</p>
</div>
</div>
ipt>
const app = new Vue ({
el: '#app',
data : {
books: [
{
index: 1,
name: 'java',
time: '2020-1',
price: 10,
count: 1
},
{
index: 1,
name: 'javascript',
time: '2020-1',
price: 20,
count: 1
},
{
index: 1,
name: 'c++',
time: '2020-1',
price: 30,
count: 1
},
{
index: 1,
name: 'html',
time: '2020-1',
price: 40,
count: 1
}
]
},
computed: {
totalPrice() {
let sum = 0;
for( let i in this.books) {
sum+= this.books[i].price * this.books[i].count
}
return sum
}
},
methods: {
increament(index) {
/*
1. 操作的是books 这个数组内的count 值, 最终值要返回给这个数组中的某行的count
2. 若 要多此一举
@click="increament(item.count)"
increament(num) {
num++;
this.books.count = num;
}
*/
this.books[index].count++
},
decreament(index) {
this.books[index].count--
},
btnClick(index) {
// 删除数组的某一行, 使用splice()
this.books.splice(index, 1)
}
},
filters: {
fullToFix(price) {
return '¥ ' + price.toFixed(2)
}
}
});
</script>
10-数组
<script>
// 条件一: 在一个数组中, 将小于100的值取出
var arr = [5,30,100,55,90,101,102,300,1055,105,1111,1422,1];
var arr1 = []
for(var i=0; i<arr.length;i++) {
if(arr[i] <= 100) {
arr1.push(arr[i])
}
}
console.log(arr1);
// 条件二: 将取出的值全部 *2
var arr2 = [];
for(var j=0; j<arr1.length;j++) {
arr2.push(arr1[j] *2)
}
console.log(arr2);
// 条件三: 将取出的值*2后汇总
var sum=0;
// for (var b=0; b<arr2.length;b++) {
for(var b of arr2){
sum+= b
}
console.log(sum);
/*
以原生的方法将以上三个条件输出, 语句太过于麻烦, 而是用封装好的高阶函数,则更加简洁
1. 使用链式调用 同时执行三个条件语法
2.
flite() 起到过滤的效果, 将执行条件返回
map() 起到加工的作用。 将返回的值 进行*2 加工
reduce() 功能最强大
*/
let newarr = [];
let total = arr.filter(function(i) {
return i <= 100
}).map(function(i){
return i*2
}).reduce(function(prevalue,i){
return prevalue + i
},0)
// console.log(arr)
console.log(total)
let newarr2 = [];
let totalNum = arr.filter(i => i<=100).map(i => i*2).reduce((prevalue, i) => prevalue + i)
console.log(totalNum)
</script>
11- 组件化思想
组件:
1. 将一个模版封装成模块, 在多个地方使用。 => 建立一次, 多次使用
2. 便于维护, 对于后期的修改较友好
1. 全局组件:
1. 创建模版
1. 在Vue 实例之间 使用 Vue.extend(模版)
1. extend() 值 可以使用 `template: html元素` 在extend 内创建模版
2. extend() 值 可以使用 ``template: htmlID 在HTML中创建模版, 使用id值绑定
1. HTML中使用 <template id="tel">...元素内容</template>
2. extend(`template: "#tel"`)
1. HTML 中使用<script type="text/x-template">
2. 注册组件
1. Vue.component('HTML中使用的标签名', 注册时赋值的常量)
3. 使用组件 挂载到 vue 实例上
1. 因注册的是全局组件, 则可在各个实例中 使用 所注册的标签名调用
2. 若在Vue实例外使用, 则是个无效的标签
4. 组件注册的语法糖语法:
1. 不使用 Vue.extend() 方法, 直接将 模版放置 components属性内,
components: {
template: `<div>...</div>`
}
2. 局部组件:
1. 创建模版
1. 模版的创建方法 与 全局组件一样
2. 创建一个 .vue 文件, 并将接口导出
1. export {组件名} => 调用时必须使用这个组件名
2. export default {组件名} => 调用时可使用自主创建的组件名
2. 注册组件
1. 方法一: 注册的方式和全局组件一致
2。方法二:
1. 调用导出的接口 使用 import 组件名 from 文件路径 (若是在某个子组件中调用, 则需要在该组件的script 标签内 引用接口)
2. 在Vue 实例中 使用 components 属性 添加
3. 使用组件 (只允许在注册的Vue实例中使用)
3. 父组件与子组件
1. 父组件中插入子组件:
1. 在父组件的 模版内使用 子组件的元素名
2. 并在父组件的conponents 属性中注册子组件
3. 子组件的创建要在父组件之前, javascript 是循规蹈矩, 由上至下运行,
当子组件在父组件之后创建,父组件注册的组件将无法获取到子组件的信息,发生错误
4. 组件属性:
1. data => 组件中的data属性必须是个函数, 函数的值是独立的 data(){}
2. props: 父传子 (properties 属性)
1. 父组件 内 创建数据 => 在data:{move:['海王','海贼王 ',' 电影']} 中创建数据
2. 子组件创建props 属性,设置要使用的值, 在父组件模版中 传入值给子组件
1. 使用数组:
1. 子组件属性 props: ['cmove', 'cmessage'] => 创建要获取数据的名称
2. 在父组件的模版中,动态传递数据
1. <cpn :cmove="move" :cmessage="message"></cpn> (cpn 是子组件的元素名)
2. 在子组件的模版内就是使用数据
1. <template> <p>{{cmessage}} {{cmove}}</p></template>
2. 使用对象:
1. 子组件属性 props: {
cmessage: {type: String, default: aaa},
cmove: {type: Array, required: true}
=> required 必传属性,否则报错
** 当获取传递值的类型为对象或数组时,默认值必须是个函数, 否则会报错
** default (){
return []
}
}
2. 在父组件的模版中,动态传递数据
1. <cpn :cmove="move" :cmessage="message"></cpn> (cpn 是子组件的元素名)
2. 在子组件的模版内就是使用数据
1. <template> <p>{{cmessage}} {{cmove}}</p></template>
3. 当props 使用驼峰标识时, props: ['strStr']
在模版中的使用必须将 驼峰形式以 '-' 拼接的方式输出 => html 解析dom无法识别驼峰
如: <cpn :cstr-str="str"> 而使用mus语法则无需转换 <p>{{strStr}}</p>
3. $emit() 子传父
1. 子组件创建数据 data(){ books: [....]}
2. 子组件模版创建按钮 , <button @click="btnClick(item)" v-for="item in books">{{item}}
3. 子组件methods属性创建方法 发射数据给父组件
1. methods: { btnClick(item){this.$emit('childbtn', item)}}
2. ↑ 'childbtn' 是自定义方法名, item 是数据本身event
4. 父组件模版
1. 父组件methods 属性创建btnClick的方法
2. 在子组件 标签<cpn @childbtn="btnClick"> 👈 @childbtn 是子组件发射来的方法
<div id='app'>
<cpn :cmove="move" :cmessage="message" @childbtn="btnClick"></cpn>
</div>
<div id='banner'>
<cpn/>
</div>
<script src='../../vue.js'></script>
<script>
//创建子组件, 并在父组件中使用
const cpn_child = Vue.extend({
template: '<div>我是子组件</div>',
// methods: {
// btnClick(item){
// // 按钮点击, 子组件发射一个自定义名为 'childBtn'的方法, 并将item传送回去给父组件
// this.$emit('childbtn', item);
// }
// }
})
// 父组件
const cpm = Vue.extend({
template: `
<div>
<p>插入模版</p>
<p>{{cmove}}</p>
<p>{{cmessage}}</p>
<div>
<button @click="btnClick(item)" v-for="item in books">{{item.name}}</button>
</div>
<cpn_child/>
</div>
`,
components: {
cpn_child
},
data(){
return {
books: [
{
id:1,
name: '按钮1'
}, {
id:2,
name: '按钮2'
},
{
id:3,
name: '按钮3'
},
{
id:4,
name: '按钮4'
}
]
}
},
// 子组件, 使用props 创建获取父组件数据的名称
// props: ['cmove', 'cmessage']
props: {
cmove: {
type: Array,
default() {
return [] // 当属性类型为数组或对象时,必须使用工厂函数, 否则会报错
}
},
cmessage: {
type: String,
default: 'aaa',
// required: true // 必须传值, 否则报错
}
},
methods: {
btnClick(item){
// 按钮点击, 子组件发射一个自定义名为 'childBtn'的方法, 并将item传送回去给父组件
this.$emit('childbtn', item);
}
}
})
// 全局组件 cpn
Vue.component('cpn', cpm)
// 创建 Vue 实例 app
const app = new Vue ({
el: '#app',
data : {
message: 'hah' ,
move: ['海王','海贼王 ',' 电影']
},
methods: {
btnClick(item){
console.log(item)
}
}
});
// 创建实例 banner
const banner = new Vue({
el: '#banner'
})
</script>