对象.属性 = 值
(app.message = ‘hello’)来改变数据,体验vue的响应式CDN引入
<!-- 开发环境版本,代码没有压缩,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
下载和引用
开发环境 https://vuejs.org/js/vue.js
生产环境 https://vuejs.org/js/vue.min.js
npm安装
npm install vue
数据展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">{{ message }}</div>
<script>
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello vue.js'
}
}
})
</script>
</body>
</html>
{{}}语法:叫Mustache(玛斯塔)语法,可以进行数据计算,字符串的拼接。
优点:可以完全的达到页面与数据的分离
列表展示(for循环,item是每项的值,index是每个项的索引)
<div id="app">
<ul v-for = "item in message">
<li>{{ item }}</li>
</ul>
</div>
<script>
const app = new Vue({
el: '#app',
data() {
return {
message: ['少年的你','最好的我们','寻梦环游记','匆匆那年']
}
}
})
</script>
vue案例—计数器
<!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">
<!-- 方法1 -->
<!-- <button v-on:click="counter++">+</button>
<span>{{ counter }}</span>
<button v-on:click="counter--">-</button> -->
<!-- 方法2 -->
<input type="button" v-on:click="add" value="+" />
<span>{{ counter }}</span>
<input type="button" v-on:click="sub" value="-">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
counter: 0
}
},
methods: {
add:function() {
console.log('add');
this.counter++
},
sub:function() {
console.log('sub');
this.counter--
}
}
})
</script>
</body>
</html>
MVVM
Model View Model View
搜索网站
维基百科:https://www.wikipedia.org/
绑定view和model实现数据的双向绑定,你变我也变
解释
事件
时,可以监听到,并在对应情况下改变对应的数据生命周期:事务从诞生到消亡的过程。
vue生命周期:创建前/后,载入前/后,更新前/后,销毁前/后。【重:面试会考】
生命周期函数,是vue自定义的公共函数,不需要创建,直接使用就。
什么是生命周期函数?
比如:
beforeMount: function() {
}
// 或者
beforeMount() {
}
错误的形式:
mounted:() => {
}
在实例初始化之后,数据观测和暴露了一些有用的实例属性与方法。
实例初始化——new Vue()
数据观测——在vue的响应式系统中加入data对象中所有数据,这边涉及到vue的双向绑定,可以看官方文档上的这篇深度响应式原理 深度响应式原理
暴露属性和方法——就是vue实例自带的一些属性和方法,我们可以看一个官网的例子,例子中带$的属性和方法就是vue实例自带的,可以和用户定义的区分开来
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
复制代码
// 有el属性的情况下
new Vue({
el: '#app',
beforeCreate: function() {
console.log('调用了beforeCreate')
},
created: function() {
console.log('调用了created')
},
beforeMount: function() {
console.log('调用了beforeMount')
},
mounted: function() {
console.log('调用了mounted')
}
})
// 输出结果
// 调用了beforeCreate
// 调用了created
// 调用了beforeMount
// 调用了mounted
复制代码
// 在没有el属性的情况下,没有vm.$mount
new Vue({
beforeCreate: function() {
console.log('调用了beforeCreate')
},
created: function() {
console.log('调用了created')
},
beforeMount: function() {
console.log('调用了beforeMount')
},
mounted: function() {
console.log('调用了mounted')
}
})
// 输出结果
// 调用了beforeCreate
// 调用了created
复制代码
// 在没有el属性的情况下,但是有vm.$mount方法
var vm = new Vue({
beforeCreate: function() {
console.log('调用了beforeCreate')
},
created: function() {
console.log('调用了created')
},
beforeMount: function() {
console.log('调用了beforeMount')
},
mounted: function() {
console.log('调用了mounted')
}
})
vm.$mount('#app')
// 输出结果
// 调用了beforeCreate
// 调用了created
// 调用了beforeMount
// 调用了mounted
主要分三种情况:
我们来看以下几个例子:
new Vue({
el: '#app',
template: 'hello world'
})
//页面上渲染出了hello world
复制代码
hello world
new Vue({
el: '#app'
})
// 页面上渲染出了hello world
复制代码
//两者都存在的时候
hello world2
new Vue({
el: '#app',
template: 'hello world1'
})
// 页面上渲染出了hello world1
从上述的例子可以看出内部的优先外部的。
1、为什么el属性的判断在template之前? 因为el是一个选择器,比如上述例子中我们用到的最多的是id选择器app,vue实例需要用这个el去template中寻找对应的。
2、实际上,vue实例中还有一种render选项,我们可以从文档上看一下他的用法:
new Vue({
el: '#app',
render() {
return (...)
}
})
3、上述三者的渲染优先级:render函数 > template属性 > 外部html
4、vue编译过程——把tempalte编译成render函数的过程。
{{message}}
new Vue({
el: '#app',
data: {
message: 1
},
beforeMount: function() {
console.log('调用了beforeMount');
console.log(this.message)
console.log(this.$el)
},
mounted: function() {
console.log('调用了mounted');
console.log(this.message)
console.log(this.$el)
}
})
// 输出的结果:
// 调用了beforeMount
// 1
//
//
// 调用了mounted
// 1
//
// 1
//
创建vue实例的$el,然后用它替代el属性。
这个过程中,我们会发现,当一个数据发生改变时,你的视图也将随之改变,整个更新的过程是:数据改变——导致虚拟DOM的改变——调用这两个生命钩子去改变视图
// 没绑定的情况
var vm = new Vue({
el: '#app',
template: '',
beforeUpdate: function() {
console.log('调用了beforeUpdate')
},
updated: function() {
console.log('调用了uodated')
},
data: {
a: 1
}
})
vm.a = 2
//这种情况在控制台中是什么都不会输出的。
复制代码
var vm = new Vue({
el: '#app',
template: '{{a}}',
beforeUpdate: function() {
console.log('调用了beforeUpdate')
},
updated: function() {
console.log('调用了uodated')
},
data: {
a: 1
}
})
vm.a = 2
// 输出结果:
// 调用了beforeUpdate
// 调用了uodated
复制代码
在beferoDestory生命钩子调用之前,所有实例都可以用,但是当调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
let vm = new Vue({
el: '#app',
data: {
message: 1
},
template: '{{message}}
',
beforeCreate() {
console.log('调用了beforeCreate')
console.log(this.message)
console.log(this.$el)
},
created() {
console.log('调用了created')
console.log(this.message)
console.log(this.$el)
},
beforeMount() {
console.log('调用了beforeMount')
console.log(this.message)
console.log(this.$el)
},
mounted() {
console.log('调用了mounted')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate() {
console.log('调用了beforeUpdate')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('调用了updated')
console.log(this.message)
console.log(this.$el)
},
beforeDestory() {
console.log('调用了beforeDestory')
console.log(this.message)
console.log(this.$el)
},
destoryed() {
console.log('调用了Destoryed')
console.log(this.message)
console.log(this.$el)
}
})
vm.message = 2
复制代码
// 调用了beforeCreate
// undefined
// undefined
// 调用了created
// 1
// undefined
// 调用了beforeMount
// 1
//
// 调用了mounted
// 1
// 1
// 调用了beforeUpdate
// 2
// 2
// 调用了updated
// 2
// 2
代码规范:缩进,一般来说是缩进4个空格,但实际上缩进2个空格会更加的规范。
Mustach语法,也就是双大括号({{}})语法
mustach:胡子,胡须
<div id="app">
<h2>{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
message: 'hello meustach'
}
}
})
</script>
Mustach语法,可以进行数值的计算,数据的绑定,字符串的拼接
只显示第一次绑定的值,不会跟着用户的操作而改变
元素和组件只渲染一次,不会跟着数据的改变而改变
<div id="app">
<!-- 显示 点我 超链接 点击之后就跳转到https://pic.images.ac.cn/image/5e87056c7bec6网页 -->
<h2 v-html = "url"></h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
url: `点我`
}
}
})
</script>
绑定文本值
<div id="app">
<!-- 显示 hello v-text,good -->
<h2>{{ message }},good</h2>
<!-- 显示 hello v-text -->
<h2 v-text = "message">good</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello v-text'
}
}
})
</script>
不灵活,只能绑定确定的值,不能进行数据拼接,添加拼接值后,拼接值会被v-text的值覆盖
和
标签作用一样,写什么就展示什么用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
<div id="app">
<!-- 显示 hello v-text,good -->
<h2>{{ message }},good</h2>
<!-- 显示 {{ message }},good -->
<h2 v-pre>{{ message }},good</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello v-text'
}
}
})
</script>
在某些情况下,我们浏览器可能会直接显示出未编译的Mustach标签
clock:斗篷
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* v-lock存在的时候不显示内容 */
[v-lock] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-lock>
<!-- 显示 hello v-text,good -->
<h2>{{ message }},good</h2>
<!-- 显示 {{ message }},good -->
<h2 v-pre>{{ message }},good</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
// 在vue解析之前,div中有一个属性v-clock
// vue解析完成后,div中没有v-lock属性
setTimeout(function () {
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello v-text'
}
}
});
},1000);
</script>
</body>
</html>
页面加载的时候起一个类似缓冲的作用
作用:动态绑定属性
缩写: :
预期:any(with argument) | Object(without argument)
参数:attrOrProp(optional)
<div id="app">
<!-- 通过图片地址,动态绑定元素属性,显示图片 -->
<!-- 图片不会显示 -->
<img src="imgUrl">
<!-- 图片会显示 -->
<!-- v-bind的原型 -->
<img v-bind:src="imgUrl" >
<!-- v-bind的简写形式 -->
<img :src="imgUrl" >
<!-- 通过 v-html 标签绑定形式,动态显示图片 -->
<div v-html="img"></div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data() {
return {
// 图片地址
imgUrl: 'http://imgs.aixifan.com/content/2016_07_10/1468158502.gif',
img: ''
}
}
})
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 可以通过app.isactive来改变属性的值(布尔值),展示不同的状态 -->
<!-- <h2 :class="{key1:value1, key2:value2}">{{name}}</h2> -->
<!-- <h2 :class="{类名1:true, 类名2:boolean}">{{name}}</h2> -->
<!-- 元素绑定的class和动态绑定的class在浏览器中加载会合并 -->
<h2 class="title" :class="{active:isactive, line:isline}">{{name}}</h2>
<!-- 简化写法:将绑定的class属性写成一个方法,然后绑定封装后的方法,让页面看起来更加的简洁 -->
<h2 class="title" :class="getClass()">{{name}}</h2>
<button type="button" v-on:click="check">按钮</button>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data() {
return {
name: '小陈',
isactive: true,
isline: true
}
},
methods: {
// 通过按钮点击事件来切换绑定数据的显示样式
check: function(){
this.isactive = !this.isactive;
},
getClass: function() {
return {active:this.isactive, line:this.isline}
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 通过数组语法绑定多个class名 -->
<!-- 绑定的class属性有单引号时,当字符串解析 -->
<!-- 在页面显示成 <h2 class="active line"></h2> -->
<h2 :class="['active', 'line']">{{ name }}</h2>
<!-- 绑定的class属性没有单引号时,当变量解析 -->
<!-- 在页面显示成 <h2 class="aaa bbb"></h2> -->
<h2 :class="[active, line]">{{ name }}</h2>
<!-- 在页面显示成 <h2 class="aaa bbb"></h2> -->
<h2 :class="getClass()">{{ name }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data() {
return {
name: '小陈',
active: 'aaa',
line: 'bbb'
}
},
methods: {
getClass: function(){
// 在使用方法绑定时,绑定数组中的属性值一定要加上this
// 不加 this 就会显示active line is not defind
// return [active, line]
return [this.active, this.line]
}
}
})
</script>
</body>
</html>
点击列表中的哪一项,哪一项的值就变成红色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
ul li {
/* 鼠标移上去,添加小手样式 */
cursor: pointer;
}
/* 元素绑定的class样式 */
.active {
color: red;
}
</style>
</head>
<body>
<!-- 2 创建作用域 -->
<div id="app">
<ul>
<!--通过切换索引值改变class-->
<!-- 遍历显示在那个标签里面v-for循环就写在那个标签里面 -->
<li v-for='(item,index) in movie' @click="change(index)" :class='{ active:index === i }'>{{ item }}</li>
</ul>
</div>
<!-- 1 引包 -->
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
// 3 实例化vue
var app = new Vue({
// 4 添加挂载点 el
el: '#app',
data() {
return {
// 页面加载的时候给第一个li标签添加样式
// 元素的索引从0开始
i: 0,
// 页面显示的数组数据
movie: ['寻梦环游记', '肖申克的救赎', '摩登家庭', '老友记']
}
},
methods: {
// 元素标签点击事件
change: function(index) {
// console.log(index);
// 将添加class属性的索引变成用户点击的索引
this.i = index;
}
}
})
</script>
</body>
</html>
<h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
style后面跟的是一个对象类型
对象的key是css属性名称
对象的value是具体赋的值,值可以来自data中的属性
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- <h2 :style="{key: value}"></h2> -->
<!-- key是css的属性名 value是属性值 -->
<!-- 这样编译会报错,编译的时候浏览器把50px当成一个变量编译的,但是变量不能以数组开头 -->
<!-- <h2 :style="{font-size: 50px}">{{ message }}</h2> -->
<!-- 解决方法: 将 50px 变成 '50px' -->
<h2 :style="{'font-size': '50px'}">{{ message }}</h2>
<h2 :style="{fontSize: '50px'}">{{ message }}</h2>
<!-- 直接引用变量finalSize -->
<!-- 引用的变量的值有单位,直接引用变量 -->
<h2 :style="{fontSize: finalSize, color: finalColor }">{{ message }}</h2>
<!-- 通过函数封装来改变样式 -->
<h2 :style="getStyle()">{{ message }}</h2>
<!-- 引用变量的值没有单位,在变量后面通过字符串的拼接来添加单位 -->
<h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'HerayChen',
finalSize: '60px',
end: 60,
finalColor: 'red'
}
},
methods: {
getStyle: function() {
return {fontSize: this.finalSize, color: this.finalColor }
}
}
})
</script>
</body>
</html>
<h2 v-bind:style="[fontColor,backgroundColor]">{{ message }}</h2>
style后面跟的是一个数组类型
多个值,分隔即可
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<h2 :style="[fontColor]">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'HerayChen',
fontColor: {color: 'red'}
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 通过mustach语法实现拼接 -->
<h2>{{ cname + ' ' + ename }}</h2>
<h2>{{ cname }} {{ ename }}</h2>
<!-- 通过函数方法实现拼接 -->
<h2>{{ getFullName() }}</h2>
<!-- 通过计算属性实现拼接 -->
<!-- 注意:计算属性,在写的时候是通过方法组合而成的,但是在使用的时候是当成属性使用的,直接通过属性名调用即可,不需要加双小括号 -->
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
ename: 'HerayChen',
cname: '肖晨'
}
},
// computed 计算属性
computed: {
// fullName在这里是一个属性,不是一个函数
fullName: function() {
return this.cname + ' ' + this.ename;
}
},
methods: {
getFullName() {
return this.cname + ' ' + this.ename;
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<h2>所有书的总价格为:{{ books[0].price + books[1].price + books[2].price + books[3].price }}</h2>
<h2>所有书的总价格为:{{ totalPrice }}</h2>
<h2>所有书的总价格为:{{ tprice }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
books: [{
id: 202001,
name: '月亮与六便士',
price: 50
}, {
id: 202002,
name: '独家的记忆',
price: 35
}, {
id: 202003,
name: '我在未来等你',
price: 25
}, {
id: 202004,
name: '爱',
price: 250
}]
}
},
computed: {
totalPrice: function() {
let result = 0;
for(let i = 0; i < this.books.length; i++){
result += this.books[i].price;
}
return result;
},
tprice: function() {
let result = 0;
// es6中的for循环
for (let i in this.books) {
result += this.books[i].price;
}
return result;
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
cname: '肖晨',
ename: 'HerayChen'
}
},
computed: {
// fullName: function() {
// return this.cname + ' ' + this.ename;
// },
// 计算属性一般没有set方法,只读属性
fullName: {
set: function(newName) {
// 只有值更改后才会调用set方法
// 要使用set方法,set方法一定是有参数的
// 通过空格截取修改后的值
const names = newName.split(' ');
// 前面的部分是cname
this.cname = names[0];
// 后面的部分是ename
this.ename = name[1];
},
get: function() {
return this.cname + ' ' + this.ename;
}
}
}
})
</script>
</body>
</html>
计算属性(computed)比methods性能更高,methods加载一次调用一次(每次都会重新计算一次),计算属性只调用一次(只计算一次)。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 直接拼接 -->
<!-- 一般不使用这种方法,语法过于繁琐 -->
<h2>{{ cname + ' ' + ename }}</h2>
<!-- 通过函数拼接 -->
<!-- 调用多次多次,页面加载一次调用一次 -->
<h2>{{ getFullName() }}</h2>
<!-- 通过计算属性拼接 -->
<!-- 调用多次 不管调用多少次,fullName只调用一次 -->
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
cname: '肖晨',
ename: 'HerayChen'
}
},
computed: {
fullName: function() {
return this.cname + ' ' + this.ename;
}
},
methods: {
getFullName: function() {
return this.cname + ' ' + this.ename;
}
}
})
</script>
</body>
</html>
var/let:变量,const:常量
let
const
将某个变量变成常量
常量是固定值,不可以再次赋值
const可以保证数据的安全性
在es6开发中优先使用const,只有需要改变某一个标识符的时候才使用let
注意:
1 常量不可以再次修改
const name = 'herayChen';
name = 'xiaochen0'; // 错误
2 常量声明之后必须赋值
const name; //错误
3 常量的含义是指向的对象不能修改,但是可以改变对象内部的属性
const obj = {
name: 'xiaochen',
age: 20
}
obj.age = 18; //正确
在const obj = {}中,{}就是obj的字面量。
属性的增强写法
// 属性的增强写法
const name = 'xiaochen';
const age = 20;
const sex = '女';
// ES5中
const obj = {
name: name,
age: age,
sex: sex
}
// ES6中
const obj = {
name,
age,
sex
}
函数的增强写法
// 函数的增强写法
// ES5
const obj = {
add: function() {
},
reducte: function() {
}
}
// ES6
const obj = {
add() {
},
reducte() {
}
}
最近更新:typescript(microsoft),flow(facebook),angular(goole)【框架本身就使用的是typescript】
<div id="app">
<h2>{{ counter }}</h2>
<!--
v-bind的语法糖:
<h2 v-bind:title="">{{ counter }}</h2>
<h2 :title="">{{ counter }}</h2>
-->
<!-- 直接操作数据 -->
<button type="button" @click="counter++">+</button>
<button type="button" @click="counter--">-</button>
<!-- 绑定函数,调用 -->
<button type="button" v-on:click="increment">+</button>
<!-- v-on中的语法糖:@click -->
<button type="button" @click="decrement">-</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
}
}
})
</script>
情况一:
如果该方法不需要额外参数,那么方法后面的()可以省略,但是如果方法本身中有一个参数,那么则会默认event参数传递进去。
情况二:
如果需要同时传递某一个参数,同时需要event时,剋通过$event传入事件。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 1.事件调用的方法没有参数 -->
<!-- @click="btnClick" 或者 @click="btnClick()" -->
<button @click="btn1Click">按钮1</button>
<!-- 2.有一个参数 -->
<!-- 在事件定义时,写函数时省略了小括号,但是方法本身是需要一个参数的 -->
<!-- 打印输出123 -->
<button @click="btn2Click(num)">按钮2</button>
<!-- 没有传递参数函数的形参是undefined -->
<button @click="btn2Click()">按钮2.1</button>
<!-- 打印输出MouseEvent对象 -->
<!-- 在进行事件操作的时候浏览器会自动生成一个event对象 -->
<!-- v-on绑定函数需要传递新参,但是没有传递形参及小括号,就输出event对象 -->
<button @click="btn2Click">按钮2.2</button>
<!-- 3.有一个及多个参数 -->
<!-- 在方法定义时,我们需要event对象,还需要其他参数 -->
<!-- event is not defined -->
<!-- 在这里浏览器解析的时候是把event当成一个变量来解析的 -->
<button @click="btn3Click(num, event)">按钮3</button>
<!-- 在调用方法的时候如何手动获取event对象 ,通过 $event -->
<button @click="btn3Click(num, $event)">按钮3.1</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
num: 123
}
},
methods: {
btn1Click() {
console.log("btnClick");
},
btn2Click(abc) {
console.log(abc);
},
btn3Click(abc, event) {
console.log(abc, event);
}
}
})
</script>
</body>
</html>
<!-- 1 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 2 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 3 阻止默认行为,没有表达式 -->
<button @click.stop></button>
<!-- 4 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 5 键修饰符,键别名 -->
<button @click.enter="onEnter"></button>
<!-- 6 键修饰符,键代码 -->
<button @click.13="onEnter"></button>
<!-- 7 点击只会触发一次 -->
<button @click.once="doThis"></button>
示例:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 1 .stop阻止事件冒泡的使用 -->
<div @click="divClick">
<!-- 通过 stop阻止事件向上冒泡 -->
<button @click.stop="btnClick">按钮</button>
</div>
<!-- 2 .prevent修饰符的使用 -->
<form action="baidu.com">
<!-- 通过prevent阻止表单的默认提交 -->
<input type="submit" value="提交" @click.prevent="submitClick"/>
</form>
<!-- 3 监听键盘的键帽 -->
<input type="text" @keyup.enter="keyUp" />
<!-- 4 once修饰符的使用 -->
<button type="button" @click.once="btn2Click">提交</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
divClick() {
console.log('divClick');
},
btnClick() {
console.log('btnClick');
},
submitClick() {
// 自定义提交
console.log('submitClick');
},
keyUp() {
// 监听键帽,按下回车键后才打印
console.log('keyUp');
},
btn2Click() {
// 只提交一次
console.log('btn2Click');
}
}
})
</script>
</body>
</html>
<div id="app">
<!-- 为false不显示,true显示 -->
<h2 v-if="isShow">good morning HerayChen</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
isShow: true
}
}
})
</script>
<div id="app">
<!-- v-if中的条件为true时,显示v-if里面的内容 -->
<!-- v-if中的条件为false时,显示v-else里面的内容 -->
<h2 v-if="isShow">{{ message }}</h2>
<h2 v-else>{{ now }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'good morning HerayChen',
now: 'good afternoon HerayChen',
isShow: false
}
}
})
</script>
层层判断
<div id="app">
<!-- 1 直接在标签上使用 -->
<h2 v-if="score >= 90">优秀</h2>
<h2 v-else-if="score >= 80">良好</h2>
<h2 v-else-if="score >= 60">及格</h2>
<h2 v-else>继续加油呀!</h2>
<!-- 2 通过计算属性来使用 -->
<h1> {{ result }}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
score: 90
}
},
computed: {
result() {
let showMessage = '';
if (this.score >= 90) {
showMessage = '优秀'
} else if (this.score >= 80) {
showMessage = '良好'
} else if (this.score >= 60) {
showMessage = '及格'
} else{
showMessage = '继续加油呀~'
}
return showMessage;
}
}
})
</script>
选择不同的方式登录
在此过程中遇到的小问题:
问题解答:
解决方案:
<div id="app">
<span v-if="isUser">
<label for="userName">手机账号</label>
<!-- 给input标签添加key属性,防止在页面中输入了账号然后想切换登录方式,输入的数据没有清除 -->
<!-- 这种现象的原因是:vue的虚拟DOM , 元素内部的复用问题-->
<!-- 给input添加key属性,将key作为一个标识,决定能不能在其他地方进行使用 -->
<!-- 当不需要在其他地方使用时,key的值一定唯一 -->
<input type="text" id="userName" placeholder="手机账号" key="userName"/>
</span>
<span v-else>
<label for="email">邮箱</label>
<input type="text" id="email" placeholder="邮箱" key="email"/>
</span>
<button @click="isUser = !isUser">切换类型</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
isUser: true
}
}
})
</script>
<div id="app">
<!-- v-if条件为false是,包含v-if指令的元素,根本就不会存在DOM中 -->
<!-- 创建 删除... -->
<h2 v-if="isShow">{{ message }}</h2>
<!-- v-show是通过使用display:none来实现的 -->
<!-- display:block display:none -->
<h2 v-show="isShow">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: '知识改变命运,学习成就未来',
isShow: true
}
}
})
</script>
v-if和v-show对比:
<div id="app">
<!-- 在遍历过程中没有使用索引值 -->
<ul>
<li v-for="item in movies">{{ item }}</li>
</ul>
<!-- 在遍历过程中获取索引值 -->
<ul>
<li v-for="(item, index) in movies">{{ index+1 }}.{{ item }}</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
movies: ['寻梦环游记', '肖申克的救赎', '爱的冒险', '冰雪奇缘']
}
}
})
</script>
<div id="app">
<ul>
<!-- 在遍历对象中 item是对象中的每个属性的值 value -->
<li v-for="item in movies">{{ item }}</li>
</ul>
<ul>
<!-- key 属性名 -->
<!-- item 属性值 -->
<li v-for="(item,key) in movies">{{ key }}-{{ item }}</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
movies:{
id: 1,
name: '动物世界',
actor: '李易峰',
time: '2018-05-04'
}
}
}
})
</script>
1 push()
2 pop()
3 shift()
4 unshift()
5 splice()
6 sort()
7 reverse()
8 Vue中的set方法
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in letter" :key="item">{{ item }}</li>
</ul>
<button type="button" @click="btnClick">按钮</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
letter: ['A', 'B', 'C', 'D', 'E'],
nums: [1, 3, 4, 77, 33, 6]
}
},
methods: {
btnClick() {
// 1 push()
// 在数组后添加一个元素
// Math.random().toString(36).substr(2) 随机生成字母和数字的组合
this.letter.push(Math.random().toString(36).substr(2));
// 一次添加多个元素
this.letter.push('aaa', 'bbb', 'ccc');
// 2 pop()
// 删除数组的最后一个元素
this.letter.pop();
// 3 shift()
// 删除数组的第一个元素
this.letter.shift();
// 4 unshift()
// 在数组最前面添加一个元素
this.letter.unshift(Math.random().toString(36).substr(2));
// 5 splice()
// splice方法可以删除元素/插入元素/替换元素
// 删除
this.letter.splice(1, 2);
// splice(1, 2);//从第一个元素开始,向后删除2个元素 显示ADE
// 如果没有传第二个参数就删除从起始位置后的所有元素
// 替换
// 显示AFGHI
// 从第一个元素开始,向后替换四个元素
this.letter.splice(1, 4, 'F', 'G', 'H', 'I');
// 插入
// 显示ABCDFGHIE
// 在数组的第四个元素后添加'F', 'G', 'H', 'I'
this.letter.splice(4, 0, 'F', 'G', 'H', 'I');
// 6 sort()
// 数组的排序
// 打印输出 [1, 3, 33, 4, 6, 77]
console.log(this.nums.sort());
// 7 reverse()
// 翻转数组
// 显示EDCBA
this.letter.reverse();
// 8 Vue中的set方法
// set(要修改的对象, 索引值, 修改后的值)
// 显示 bbb B C D E
Vue.set(this.letter, 0, 'bbbb')
// 注意:通过索引值,更改数组中的元素,这个不是响应式的
// this.letter[0] = 'bbb';
// 使用可变参数(...)的函数
// function add(...num) {
// // 打印输出[1, 2, 3, 4, 4, 5, 5]
// console.log(num);
// }
// add(1, 2, 3, 4, 4, 5, 5);
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 8px 16px;
border: 1px solid #E9E9E9;
text-align: center;
}
th {
background-color: #7F7F7F;
color: #5c6b77;
font-weight: 600;
}
</style>
</head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th>编号</th>
<th>书籍名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in books">
<!-- 一次显示所有,不宜于做其他操作 -->
<!-- <td v-for="value in item">{{ value }}</td> -->
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.data }}</td>
<!-- 1 使用toFixed直接保留小数 -->
<!-- <td>{{ '¥' + item.price.toFixed(2) }}</td> -->
<!-- 2 通过函数的封装调用保留小数 -->
<!-- <td>{{ getFinalPrice(item.price) }}</td> -->
<!-- 3 过滤器 -->
<td>{{ item.price | getFinalPrice }}</td>
<td>
<button type="button" @click="increment(index)">+</button>
{{ item.count }}
<button type="button" @click="decrement(index)" :disabled="item.count <= 1">-</button>
</td>
<td>
<button type="button" @click="removeHandel(index)">移出</button>
</td>
</tr>
</tbody>
</table>
<h2>总价格:{{ totalPrice | getFinalPrice }}</h2>
</div>
<div v-else>
<h2>购物车为空</h2>
</div>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
</script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
books: [{
id: 1,
name: '《算法导论》',
data: '2006-9',
price: 85.00,
count: 1
}, {
id: 2,
name: '《计算机概论》',
data: '2018-9',
price: 35.00,
count: 1
}, {
id: 3,
name: '《网络技术与基础》',
data: '2006-9',
price: 84.00,
count: 1
}, {
id: 4,
name: '《编程珠玑》',
data: '2008-9',
price: 39.00,
count: 1
}, {
id: 5,
name: '《代码大全》',
data: '2006-9',
price: 85.00,
count: 1
}]
}
},
computed: {
totalPrice() {
// 1 普通的for循环
// let total = 0;
// for (let i = 0; i < this.books.length; i++) {
// total += this.books[i].price * this.books[i].count;
// }
// return total;
// 2 es6中的for let in循环
// let total = 0;
// for (let i in this.books) {
// // console.log(i); i是数组的索引
// total += this.books[i].price * this.books[i].count;
// }
// return total;
// 3 es6中拿到数组中每一项的索引值
// let total = 0;
// for (let item of this.books) {
// // item 是数组中每一项的值
// // console.log(s);
// total += item.price * item.count;
// }
// return total;
// 高阶函数reduce
return this.books.reduce(function(preVaule, book) {
return preVaule + book.price * book.count;
}, 0);
}
},
methods: {
// 保留小数 函数
// getFinalPrice(price) {
// return '¥' + price.toFixed(2)
// }
// 加法函数
increment(index) {
// console.log('increment',index);
this.books[index].count++
},
// 减法函数
decrement(index) {
// console.log('decrement',index);
this.books[index].count--
},
removeHandel(index) {
this.books.splice(index, 1)
}
},
// 过滤器
filters: {
getFinalPrice(price) {
return '¥' + price.toFixed(2)
}
}
})
</script>
</body>
</html>
普通js实现:
const num = [10, 20, 30, 40, 50, 200];
// 创建一个空数组
let newNum = [];
// 1 通过for循环将所有小于100的数据,添加到新数组中
for (let s of num) {
if (s < 100) {
newNum.push(s)
}
}
// 创建一个空数组
let new2Num = [];
// 2 通过for循环遍历1中得到的小于100的数据,将1中的数组的每一项都乘以2
for (let n of newNum) {
new2Num.push(n * 2);
}
console.log(new2Num);
// 3 遍历2中得到的数组,将数组中每项值相加
let total = 0;
for (let n of new2Num) {
console.log(total += n);
}
通过高阶函数实现:
const num = [10, 20, 30, 40, 50, 200];
// 高阶函数
// 1 过滤
// filter函数 必须返回一个布尔值
// 当函数返回true时,函数内部会自动将这次回调的n加入到新的数组中
// 当函数返回false时,函数内部会过滤掉不符合条件的n
let newNum = num.filter(function(n) {
// console.log(n); //filter函数会回调6次
return n < 100;
});
console.log(newNum); //打印输出[10, 20, 30, 40, 50]
// 2 map
let new2Num = newNum.map(function(n) {
return n * 2;
});
console.log(new2Num); //打印输出[20, 40, 60, 80, 100]
// 3 reduce
// 作用: 对数组中所有的值进行汇总
// preVaule 上一次遍历返回的值
// 第一次:preVaule: 0 n: 20
// 第二次: preVaule: 第一次返回的值 n: 40
let total = new2Num.reduce(function(preVaule, n) {
return preVaule + n;
}, 0);
console.log(total); // 打印输出300
简化高阶函数:
const num = [10, 20, 30, 40, 50, 200];
let total = num.filter(function(n) {
return n < 100;
}).map(function() {
return n * 2;
}).reduce(function(preVaule, n) {
return preVaule + n;
}, 0);
console.log(total);
高阶函数和es6简化:
let total = num.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
console.log(total);
表单控件在实际开发中是非常常见的,特别是对于用户信息的提交,需要大量的表单
Vue中使用v-model指令来实现表单元素和数据的双向绑定
<div id="app">
<input type="text" v-model="message" />
<h2>{{ message }}</h2>
<!-- v-model的实现原理 --><!-- v-on:input监听用户输入的事件 -->
<!-- 1 v-bind绑定value属性 -->
<!-- 2 v-on指令给当前元素绑定input事件 -->
<input type="text" :value="name" @input="valueChange"/>
<input type="text" :value="name" @input="name = $event.target.value"/>
<h2>{{ name }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'hello xiaochen',
name: 'Heray'
}
},
methods: {
valueChange(event) {
this.name = event.target.value;
}
}
})
</script>
<div id="app">
<label for="male">
<!-- 单选按钮只能选择一个 添加name属性 或者 v-model属性-->
<input type="radio" id="male" name="sex" value="男" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex">女
</label>
<h2>你选择的性别是:{{ sex }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
// 给sex添加值,让页面加载的时候默认选中男
sex: '男'
}
}
})
</script>
<div id="app">
<!-- 1 checkbox单选框 -->
<label for="agreement">
<input type="checkbox" id="agreement" v-model="isAgreement" />同意协议
</label>
<h2>你的选择是: {{ isAgreement }}</h2>
<!-- 只有统一协议才能下一步,isAgreement为false时下一步按钮是禁用的状态 -->
<button type="button" :disabled="!isAgreement">下一步</button>
<hr />
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="滑冰" v-model="hobbies">滑冰
<input type="checkbox" value="街舞" v-model="hobbies">街舞
<input type="checkbox" value="唱歌" v-model="hobbies">唱歌
<input type="checkbox" value="滑板" v-model="hobbies">滑板
<h2>你的爱好是:{{ hobbies }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
// 单选框对应的是一个布尔值
isAgreement: false,
// 多选框对应的是一个数组
hobbies: []
}
}
})
</script>
<div id="app">
<!-- 1 选择一个 -->
<select name="selected" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="梨子">梨子</option>
<option value="樱桃">樱桃</option>
<option value="草莓">草莓</option>
<option value="车厘子">车厘子</option>
</select>
<h2>你喜欢的水果是:{{ fruit }}</h2>
<hr />
<!-- 2 选择多个 -->
<select name="selected" v-model="fruits" multiple="multiple">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="梨子">梨子</option>
<option value="樱桃">樱桃</option>
<option value="草莓">草莓</option>
<option value="车厘子">车厘子</option>
</select>
<h2>你喜欢的水果是:{{ fruits }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
fruit:'草莓',
fruits:[]
}
}
})
</script>
<div id="app">
<label v-for="(item, index) in hobbies" :for="index">
<input type="checkbox" :value="item" :id="index" v-model="hobbies">{{ item }}
</label>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
hobbies: ['街舞', 'rapper', '滑板', '拉丁']
}
}
})
</script>
lazy修饰符:
number修饰符:
trim修饰符:
<div id="app">
<!-- 1 lazy修饰符 -->
<!-- 在失去焦点和回车后更新绑定的数据 -->
姓名:<input type="text" v-model.lazy="name"/>
<h2>{{ name }}</h2>
<!-- 2 number修饰符 -->
<!-- 不管怎么输入,都只显示number类型的数据 -->
<!-- <input type="number" v-model="age"/>输入的是数字,但是显示出来的数据是string类型的 -->
年龄:<input type="text" v-model.number="age"/>
<h2>{{ age }}-{{ typeof age }}</h2>
<!-- 3 trim修饰符 -->
<!-- 去除输入内容的前后空格 -->
爱好:<input type="text" v-model.trim="hobby"/>
<h2>{{ hobby }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
name: 'xiaochen',
age: 18,
hobby: ''
}
}
})
</script>
一个完成的页面分成很多个组件,每个组件都用于实现页面的一个功能块,每个组件又能进行细分
组件化思想的应用:
组件的使用分成三个步骤:
<div id="app">
<!-- 3 使用组件 -->
<my-info></my-info>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 创建组件构造器对象
const cnp = Vue.extend({
// 自定义组件的模板
template: `
标题
内容
尾部
`
})
<!-- // 2 注册组件 -->
//Vue.component('注册组件的标签名',组件构造器名)
Vue.component('my-info',cnp)
new Vue({
el: '#app',
data() {
return {
}
}
})
</script>
<div id="app">
<!-- 3 使用全局组件 -->
<my-info></my-info>
<!-- 使用局部组件 -->
<cpns></cpns>
</div>
<div id="app2">
<!-- 使用全局组件 -->
<my-info></my-info>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 创建组件构造器对象
const cnp = Vue.extend({
template: `
标题
内容
尾部
`
})
<!-- // 2 注册组件(全局组件,意味着可以在多个Vue的实力下面使用) -->
Vue.component('my-info',cnp)
new Vue({
el: '#app',
data() {
return {
}
},
<!-- 自定义局部组件,局部组件只能在挂载点范围之内使用 -->
components: {
<!-- cpns使用组件的标签名 -->
cpns: cnp
}
})
new Vue({
el:'#app2'
})
</script>
<div id="app">
<!-- <dad></dad> -->
<brother></brother>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 第一个组件构造器
const dad = Vue.extend({
template:
`
头部
身体
脚部
`
})
<!-- // 第二个组件构造器 -->
const brother = Vue.extend({
template:
`
head
body
foot
`,
components: {
<!-- 在brother组件里面使用dad组件里面的内容 -->
<!-- 然后使用brother组件,就可以显示brother组件和dad组件的内容 -->
<!-- 要想使用组件必须注册组件 -->
<!-- 组件名:组件模板 -->
dad: dad
}
})
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- dad: dad, -->
brother: brother
}
})
</script>
<div id="app">
<!-- 全局组件 -->
<daD></daD>
<!-- 局部组件 -->
<cpn2></cpn2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 注册全局组件
const dad = Vue.component('dad', {
template:
`
我是dad模板中全局组件的内容
`
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 注册局部组件 -->
'cpn2': {
template:
`
我是dad模板中局部组件的内容
`
}
}
});
</script>
模板的分离写法:
<div id="app">
<!-- 全局组件 -->
<daD></daD>
<!-- 局部组件 -->
<cpn2></cpn2>
</div>
<!-- 1 通过script标签提取模板 -->
<!-- 注意类型必须是:text/x-template -->
<script type="text/x-template" id="dad">
<div>
<h2>我是dad模板中全局组件的内容</h2>
</div>
</script>
<!-- 2 通过template标签 -->
<template id="cpn2">
<div>
<h2>我是dad模板中局部组件的内容</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 注册全局组件
const dad = Vue.component('dad', {
// 通过id引用模板
template: `#dad`
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 注册局部组件 -->
'cpn2': {
template:`#cpn2`
}
}
});
</script>
组件数据的存放:
<div id="app">
<!-- 全局组件 -->
<daD></daD>
<!-- 局部组件 -->
<cpn2></cpn2>
</div>
<!-- 1 通过script标签提取模板 -->
<!-- 注意类型必须是:text/x-template -->
<script type="text/x-template" id="dad">
<div>
<h2>{{ message }}</h2>
</div>
</script>
<!-- 2 通过template标签 -->
<template id="cpn2">
<div>
<h2>{{ message }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 注册全局组件
const dad = Vue.component('dad', {
// 通过id引用模板
template: `#dad`,
data() {
return {
message: '我是dad模板中全局组件的内容'
}
}
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 注册局部组件 -->
'cpn2': {
template: `#cpn2`,
data() {
return {
message: '我是dad模板中局部组件的内容'
}
}
}
}
});
</script>
函数每次都会返回一个新的新的对象,产生不同的数据。
对象每次都作用在一个属性上,一个改变所有的都改变({}可能会相互影响)。
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<!-- 组件模板 -->
<template id="cpn">
<div>
<h2>当前计数:{{ num }}</h2>
<button type="button" @click="increment">+</button>
<button type="button" @click="decrement">-</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 注册组件
Vue.component('cpn', {
template: `#cpn`,
// data是一个函数,函数每次都会返回一个新的对象
// 这样同时使用一个组件,点击一个组件,就不会改变其他组件的值
// 如果data {} 返回的是一个对象,每次作用的都是一个同养的对象,一个改变其他的都改变
// 使用{},会产生连锁反应
data() {
return {
num: 0
}
},
methods: {
increment() {
this.num++
},
decrement() {
this.num--
}
}
})
const app = new Vue({
el: '#app',
data() {
return {
}
}
})
</script>
通信:相互交流,数据传递。在大组件(父组件)获取所有的后台数据,然后在传递给小组件(子组件),渲染到页面。
如何进行父子组件的通信?
properties
属性的缩写)向子组件中传递数据<div id="app">
<!-- 在父组件里面使用子组件 -->
<!-- 在页面中显示[ "速度与激情", "肖申克的救赎", "友情之上", "摩登少年" ] 和 hello -->
<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
<!-- 在传值后,如果没有用v-bind,则会把绑定字段,当成字符串解析 -->
<!-- 在页面中显示movies message -->
<cpn cmovies="movies" cmessage="message"></cpn>
</div>
<template id="cpn">
<div>
<p>{{ cmovies }}</p>
<!-- 循环遍历父组件中传递过来的数据 -->
<ul>
<li v-for="item in cmovies">{{ item }}</li>
</ul>
<h2>{{ cmessage }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 自定义组件
const cpn = {
template: `#cpn`,
// 父传子props
// 1 数组
props: ['cmovies','cmessage'],
// 2 对象
prpos: {
// 1 类型的限制
// cmovies: Array,
// cmessage: String
// 2 提供一些默认值,以及必传值
cmessage: {
type: String,
// 没有传值提供的默认值
default: 'aa',
// 传值时cmessage是必须传的值
required: true
},
cmovies: {
type: Array,
// 类型是对象或者数组时,默认值必须是一个函数
default() {
return []
}
}
}
}
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello',
movies:['速度与激情', '肖申克的救赎', '友情之上', '摩登少年']
}
},
components: {
cpn
}
})
</script>
验证支持的数据类型:
Vue.component('my-component',{
props: {
//基础的类型检查(null,匹配任何数)
propA: Number,
//多个可能的类型
propB: [String, Number],
//必填的字符
propC: {
type: String,
required: true
},
//带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
default() {
// 返回一个默认值
return { message:'hello' }
}
},
// 自定义验证函数
propF: {
validator(value){
//这个值必须匹配下列字符中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
自定义数据类型:
function Person(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
}
Vue.component('blog-post', {
props: {
// 自定义数据类型
author: Person
}
})
在子组件中,props中的数据使用了驼峰命名,在父组件中使用必须去掉驼峰(遇到大写字母在前面加-分隔,然后将大写字母变成小写字母)
<div id="app">
<!-- 子组件是在父组件中有使用的 -->
<!-- 在子组件上绑定(v-bind)父组件传递过来的数据 -->
<!-- v-bind不支持驼峰命名 -->
<!-- <cpn :cinfo = "info"></cpn> -->
<!-- props中绑定的数据是cInfo,使用了驼峰必须 -->
<!-- 使用是必须将 cInfo 写成 c-info-->
<!-- 遇到大写字母在前面加-,然后将其变成小写使用 -->
<cpn :c-info = "info"></cpn>
</div>
<template id="cpn">
<!-- 子组件的模板中有很多个标签,必须有一个跟标签将其包裹 -->
<div>
<!-- 使用父组件中传递过来的数据 -->
<!-- <h2>{{ cinfo }}</h2> -->
<!-- props中使用了驼峰 -->
<!-- 在页面中显示 { "name": "萧辰", "age": 18, "hobbie": [ "街舞", "吉他", "滑板" ] } -->
<h2>{{ cInfo }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 子组件
const cpn = {
template: `#cpn`,
props: {
// cinfo: {
cInfo: {
type:Object,
default() {
return {
}
}
}
}
};
// 父组件
const app = new Vue({
el: '#app',
data() {
return {
info: {
name: '萧辰',
age: 18,
hobbie: ['街舞', '吉他', '滑板']
}
}
},
components: {
cpn
}
})
</script>
自定义事件的流程:
<!-- 父组件模板 -->
<div id="app">
<!-- 监听v-bind子组件发射出的时间 -->
<!-- 子组件监听子组件传递过来的事件时绑定的事件不能使用驼峰命名 -->
<!-- cpnClick(item) 写成 cpnClick这样也是可以的,从子组件传递过来的方法,会默认将参数也传递过来,就像event一样-->
<cpn @itemclick="cpnClick(item)"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<button v-for="item in cartegories" @click="btnClick(item)">{{ item.name }}</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 子组件
const cpn = {
template: '#cpn',
data() {
return {
cartegories:[
{
id: 'a',
name: '热门推荐'
},
{
id: 'b',
name: '手机数码'
},{
id: 'c',
name: '家用家电'
},{
id: 'd',
name: '手机办公'
},{
id: 'e',
name: '精选服饰'
}
]
}
},
methods: {
btnClick(item) {
// 查看用户点击的信息
// console.log(item);
// 将用户点击的信息传到父组件中
// 向父组件中发射自定义事件事件,及传递的参数
this.$emit('itemclick', item)
}
}
}
// 父组件
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn
},
methods: {
// 父组件事件
cpnClick(item) {
console.log(item);
}
}
})
</script>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<h2>props1:{{ number1 }}</h2>
<h2>data:{{ cnumber1 }}</h2>
<!-- <input type="text" v-model="cnumber1"/> -->
<input type="text" :value="cnumber1" @input="num1Input" />
<h2>props2:{{ number2 }}</h2>
<h2>data:{{ cnumber2 }}</h2>
<!-- <input type="text" v-model="cnumber2"/> -->
<input type="text" :value="cnumber2" @input="num2Input" />
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
num1: 1,
num2: 0
}
},
methods: {
num1change(value) {
this.num1 = parseInt(value);
},
num2change(value) {
this.num2 = parseInt(value);
}
},
components: {
cpn: {
template: `#cpn`,
props: {
number1: Number,
number2: Number
},
data() {
return {
cnumber1: this.number1,
cnumber2: this.number2
}
},
methods: {
num1Input(event) {
// 1 将input中的value赋值到cnumber1
this.cnumber1 = event.target.value;
// 2 为了让父组件可以修改值,发出一个事件
this.$emit('num1change', this.cnumber1);
// 3 同时修改cnumber2的值
this.cnumber2 = this.cnumber1 * 100;
this.$emit('num2change', this.cnumber2)
},
num2Input(event) {
this.cnumber2 = event.target.value;
this.$emit('num2change', this.cnumber2);
// 3 同时修改cnumber2的值
this.cnumber1 = this.cnumber2 / 100;
this.$emit('num1change', this.cnumber1)
}
}
}
}
})
</script>
</body>
</html>
$children 得到的是一个 数组
this.$children[].访问对象
$refs 得到的是一个 对象
this.$refs.添加ref的数值.访问对象
实例
<div id="app">
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button type="button" @click="btnClick">点我</button>
</div>
<template id="cpn">
<div>
我是子组件
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
btnClick() {
// 1 通过$children去拿子组件中的值
// // 拿到的子组件是一个数组类型的
// // console.log(this.$children);
// // 通过$children调用子组件的showMessage方法
// // this.$children[0].showMessage();
// // this.$children[0].name;
// for (let c of this.$children) {
// // 打印输出showMessage
// c.showMessage();
// // 打印输出xiaochen
// console.log(c.name);
// }
// 2 通过$refs去拿子组件中的值
// this.$refs默认是一个空对象
console.log(this.$refs);
// 要使用$refs取值,需要在标签上面添加ref属性,然后通过this.$refs.ref属性值拿值
// 打印输出 showMessage
this.$refs.aaa.showMessage();
// 打印输出 xiaochen
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: 'xiaochen'
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
$parent
this.$parent.访问父组件的属性
$root
// 访问根组件,Vue实例
this.$root
实例:
<div id="app">
<cpn>
</cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn组件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: '我是cpn组件的name'
}
},
components: {
ccpn: {
template: `#ccpn`,
methods: {
btnClick() {
// 1 访问父组件$parent
// 打印出来是一个VueComponent对象
console.log(this.$parent);
// 打印输出 我是cpn组件的name
console.log(this.$parent.name);
// 2 访问根组件$root
// 打印Vue 实例
console.log(this.$root);
}
}
}
}
}
}
})
</script>
为什么使用组件的插槽:
使用slot插槽,占据位置,在使用的时候传入对应的值,然后传入的值自己会填补插槽占据的位置。
插槽的基本使用:
<div id="app">
<cpn></cpn>
<hr />
<cpn>
<button type="button">点我</button>
</cpn>
<hr />
<cpn><b>我是传入值</b></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件</h2>
<slot></slot>
<h5>content</h5>
<!-- 给插槽添加一个默认值,调用的时候没有加别的参数,就使用默认值,有参数,就是用传递的值 -->
<slot><button>我是插槽传递的默认值</button></slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`
}
}
})
</script>
抽取共性,保留不同。
给插槽设置name值,然后使用的使用根据solt等于的name值进行替换。
<div id="app">
<cpn>
<!-- 替换name为center插槽 -->
<h1 slot="center">标题</h1>
</cpn>
</div>
<template id="cpn">
<div>
<slot name="left">
<h2>我是左边插槽</h2>
</slot>
<slot name="center">
<h2>我是中间插槽</h2>
</slot>
<slot name="right">
<h2>我是右边插槽</h2>
</slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`
}
}
})
</script>
父模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在自己作用域内编译。
<div id="app">
<!-- 这个是根据实例里面的isShow来决定的 -->
<!-- 命令使用时不关心组件的位置,只关心作用域 -->
<!-- 显示 app的data中的isShow是true -->
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<!-- 不显示 -->
<!-- cpn组件中的isShow是false -->
<button v-show="isShow"></button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
isShow: true
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
isShow: false
}
}
}
}
})
</script>
作用域插槽的目的就是:
父组件替换插槽的标签,但是内容由子组件来提供。
实例:
子组件中包括一组数据,比如:pLanguages[‘Javascript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
需要在多个界面进行展示:
内容在子组件,希望父组件告诉我们如何展示?
<div id="app">
<!-- 子组件默认展示 -->
<cpn></cpn>
<!-- 拿到子组件中的数据,然后在父组件中展示成不同的样式 -->
<!-- 目的:获取子组件中的pLanguages -->
<cpn>
<template slot-scope="slot">
<!-- 通过slot引用插槽对象 -->
<!-- 通过slot.data 拿到的就是 子组件中传递的:data="pLanguages" -->
<span v-for="item in slot.data">{{item}} -</span>
<div>{{ slot.data.join(' - ')}}</div>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 这里data可以为任何值 -->
<slot :data="pLanguages">
<ul>
<!-- 子组件展示 -->
<li v-for="item in pLanguages">{{ item }}</li>
</ul>
</slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
isShow: true
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
pLanguages: ['Javascript', 'Python', 'Swift', 'Go', 'C++']
}
}
}
}
})
</script>
js原始功能:
常见的模块化规范:
CommonJS,AMD,CMD,也有ES6中的Modules
CommonJS只是一个规范,CommonJS的实现是node.js。
模块化的两个核心:导出(export)和导入(require)
CommonJS的导出:
moule.export = {
name: 'xiaochen',
doit(a, b) {
return a + b;
}
}
CommonJS的导入:
//CommonJS模块
let { name,doit } = require('moduleA');
//等同于
let m = require('moduleA');
let name = m.name;
...
export指令用于导出变量:
export let name = 'xiaochen'
export let age = 18
export let dream = 'free'
也可以:
let name = 'xiaochen'
let age = 18
let dream = 'free'
export {
name, age, dream
}
导出函数和类:
export function sum(a, b) {
return a + b;
}
export class Person {
run() {
console.log('想上学的第一天');
}
}
import {sum, Person} from './a.js'
// 实例化类
const p = new Person();
// 调用类里面的函数
p.run();
export default:
某些情况下,一个模块包含某个功能,我们并不希望给这个功能命名,而且让导入这自己来命名
export default
const time = '二零二零年四月七日'
// 1
export { time }
// 2
export const time = '二零二零年四月七日'
//要使用上面的数据
import {time} from 'a.js'
// 在一个js中文件中,只能有一个default导出
export default time
import t from 'a.js'
export指令导出了模块对外提供的接口后,我们就可以通过import命令来加载这个对应的模块了
首先我们需要在HTML代码中引入两个js文件,并且类型需要设置module
<script src = "info.js" type = "module"></script>
<script src = "main.js" type = "module"></script>
import指令用于导入模块内容,比如mian.js的代码
import {name, age, sex} from './info.js'
console.log(name, age, sex);
统一全部导入
import * as info from './info.js'
console.log(info.name);
官网:webpack.js.org
从本质上将,webpack是一个现代的JavaScript应用的静态模块打包工具。
查看node版本:
node -v
全局安装webpack(这里我们先制定版本号3.6.0,因为vue cli2依赖该版本):
查看电脑中有没有安装过webpack
webpack --version 或者 webpack -v
没有 安装
全局安装webpack:
npm install webpack@3.6.0 -g
本地安装webpack:
--save-dev
是开发时依赖【devDependencies】,项目打包后不需要继续使用
npm install webpack@3.6.0 --save-dev
文档解释:
dist文件 | distribution(发布) |
---|---|
文件 | 解释 |
src文件 | 主要文件,一般项目的文件都写在src这个文件夹里面 |
打包:
// webpack 打包文件main.js的路径 打包成dist下面的bundle.js文件
// webpack在打包的时候会自动处理依赖文件
// 所以只需要打包入口文件就好了
webpack ./src/main.js ./dist/bundle.js
配置webpack让项目在运行的时候,直接webpack
就可以运行项目,不需要webpack ./src/main.js ./dist/bundle.js
这样运行
步骤:
在项目文件中创建webpack.config.js
文件
给webpack.config.js添加配置
// path 依赖了node中的path包,所以要安装node中的所有依赖项
// npm init --yes 安装所有依赖包
// 就会去全局找path
cost path = require('path');
module.exports = {
// 入口
entry: './src/main/.js',
// 出口
output: {
// 路径 path 是绝对路径
// 动态获取路径
path: path.resolve(__dirname, 'dist'),
// 文件名 bundle 打包
filename: 'bundle.js'
}
}
pacjage.json中自定义启动
为了在命令行工具中能够 通过 npm run build 运行项目,在package.json文件的script脚本中添加依赖项
让我们在执行npm run build
命令的时候来package.json文件中找到webpack
当在命令行工具中执行npm run build的时候相当于执行webpack命令,运行的时候num run build会先去查找本地的webpack,这样防止因webpack版本的问题而引发错误
"build": "webpack"
通过npm run build
打包后的文件是全局的
loader是webpack中一个非常核心的概念
webpack用来做什么呢?
loader使用过程:
步骤一:通过npm安装需要使用的loader
css-loader
npm install --save-dev css-loader
style-loader
npm install --save-dev style-loader
步骤二:在webpack.config.js中的modules关键字下进行配置
在module中css-loader只负责将css文件进行加载,style-loader将样式添加到DOM中
使用多个loader时,是从右向左
module: {
rules: [
{
test: /\.css$/
use: ['style-loader', 'css-loader']
}
]
}
步骤三:配置,也就是再次打包,npm run build
要想使用less文件更改样式要安装less-loader
:
npm install --save-dev less-loader less
在webpack.config.js文件中配置less:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
}]
}
};
下载url-loader
:
npm install --save-dev url-loader
配置url-loader:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// 当加载的图片,小于limit时,会将图片编译成base64字符串形式
// 当加载的图片,大于limit时,会使用file-loader模块进行加载,通过webpack打包后会编译成base64字符串的形式
limit: 8192 // 8192 8kb
// 打包后webpack自动帮我们生成一个非常长的名字,但真是开发中,我们可能对打包图片的名字有一定的要求,比图将所有的图片放在一个文件夹中,跟图片原来的名称,同时也要防止重复
// [name]:图片原来的名字 [hash:8]:哈希值保留8位 [ext]:图片的扩展名
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
}
安装file-loader:
npm install --save-dev file-loader
安装后,文档中使用的图片是打包后dist文件夹中的图片,
在webpack.config.js文件配置图片使用的路径:
在output中加入publicPath
output: {
publicPath: 'dist/'
}
ES6的语法直接转成ES5,需要使用babel。
在webpack中直接使用babel对应的loader就可以了。
安装:
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件:
env:environment环境的缩写。
module: {
rules: [
{
test: /\.js$/,
// exclude:排除
// include:包含
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
}
在项目中使用vue.js进行开发,那么必须对其有依赖,所以我们先要进行安装:
--save dev
是开发时依赖,因为我们后续是在实际项目中使用vue的,所以并不是开发时依赖,使用--save
npm install vue --save
// 简写
npm install vue -S
使用vue进行开发
// 导入vue
import Vue from 'vue'
//使用
new Vue({
el: '#app',
...
})
vue在发布的时候,发布了两个版本
runtime-only
runtime-complier
要解决这个问题,只需要在webpack.config.js中配置
resolve: {
// 文件引入时省略后缀名配置
extensions: ['.js', '.css', '.vue'],
// alias 别名
alias: {
// 如果导入vue后,去vue文件中去找vue.esm.js文件,这个文件中包含了complier
'vue$':'vue/dist/vue.esm.js'
}
}
template在解析的时候会替换el,再去修改html中的代码
但是如果将所有替换的代码都写在template里面,看着就很感觉很复杂,我们可以将template中的信息提取成一个组件
// ------------------------------2.app.js文件------------------------------------
// App对象中的代码可以封装到一个app.js文件里面
export default {
template:
`
....
`,
data() {
return {
}
}
... // 将所有的内容抽取到一个组件里面使用
}
// -----------------------------3.创建App.vue文件--------------------------------
//让模板于组件分离
<template>
<div>
....
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
}
}
...
}
</script>
<style>
//样式
</style>
// ------------------------------1.main.js文件------------------------------------
//const App = {
// template:
// `
//
// ....
//
// `,
// data() {
// return {
// }
// }
// ... // 将所有的内容抽取到一个组件里面使用
//}
// 引入App组件内容
//import App from './vue/app'
import App from './vue/App.vue'
new Vue({
el: '#app',
template: ' ',
components: {
App // 在组件里面注册App
}
})
但是在编译过程中不能识别App.vue文件,所以我们需要对vue文件进行一个封装,就要使用vue-loader
和vue-template-complier
安装:
vue-loader让vue文件进行一个加载,vue-template-complier 对vue文件进行编译
npm install vue-loader vue-template-complier --save-dev
配置:
{
test: /\.vue$/,
use: ['vue-loader']
}
因为vue-loader版本的原因,可能会报错,说vue-loader was used without the corresponding plugin
,在package.json文件中将vue-loader
的版本改成^13.0.0
(13到14版本之间),然后在命令行工具中执行npm install
重新安装一下
BannerPlugin,属于webpack自带的插件。
修改webpack.config.js的文件:
const path = require('path');
//导入webpack
const webpack = require('webpack');
modeule.exports = {
...
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有')
]
}
重新打包:
npm run build/webpack
目前,我们的index.html页面存放在项目的根目录下
HtmlWebpackPlugin插件可以:
安装HtmlWebpackPlugin插件
npm install html-webpack-plugin --save-dev
使用插件,修改webpack.config.js文件中plugins部分的内容
这里的template表示根据什么模板来生成index.html
另外我们需要删除之前在output中添加的publicPath属性
否则插入的script标签中的src可能会有问题
const path = require('path');
//导入webpack
const webpack = require('webpack');
// 导入HtmlWebpackPlugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
modeule.exports = {
...
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有'),
// 这样使用之后,就会在文件中的dist文件夹下面生成index.html文件
new HtmlWebpackPlugin({
// 让template根据index.html文件来生成index.html
template: 'index.html'
})
]
}
在项目发布之前,我们必须要对js等文件进行压缩处理
对js文件进行压缩,使用的是第三方插件unlifyjs-webpack-plugin
,并且版本号指定1.1.1
,和cli2
保持一致
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
修改webpack.config.js文件,使用插件:
const path = require('path');
//导入webpack
const webpack = require('webpack');
// 导入unlifyjs-webpack-plugin插件
// 在开发阶段不建议使用uglifyJsPlugin插件,代码在修改后不宜调试
const uglifyJsPlugin = require('unlifyjs-webpack-plugin');
module.exports = {
...
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有'),
new uglifyJsPlugin()
]
}
查看打包后的bunlde.js文件,最后已经被压缩过了
webpack提供了一个可选的本地服务器,这个本地服务器基于node.js搭建,内部使用express框架,可实现浏览器自动刷新显示修改后的结果。
不过它是一个单独的模块,在webpack中使用之前需要先安装
npm install --save-dev webpack-dev-server@2.9.1
devserver也是作为webpack中的一个选项,选项本身可以设置以下属性:
webpack.config.js文件配置修改:
devServer: {
contentBase: './dist',
inline: true
}
我们还可以配置package.json中的script:
–open参数标识直接打开浏览器
"build": "webpack"
"dev": "webpack-dev-server --open"
配置完成后运行:
在命令窗口通过npm run dev
运行
将开发时依赖和发布时依赖分离。
在主文件夹下创建build文件夹,在build文件夹下面创建base.config.js
(公共),prod.config.js
(开发时依赖包)和dev.config.js
(运行时依赖)
安装webpack-merge
,将分离的文件进行合并
npm install webpack-merge --save-dev
使用
base.config.js中:
const path = require('path');
//导入webpack
const webpack = require('webpack');
modeule.exports = {
// 入口
entry: './src/main/.js',
// 出口
output: {
// 路径 path 是绝对路径
// 动态获取路径
path: path.resolve(__dirname, 'dist'),
// 文件名 bundle 打包
filename: 'bundle.js'
},
module: {
rules: [{
test: /\.css$/
use: ['style-loader', 'css-loader']
}]
},
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有')
new HtmlWebpackPlugin({
// 让template根据index.html文件来生成index.html
template: 'index.html'
})
]
}
prod.config.js中:
const uglifyJsPlugin = require('unlifyjs-webpack-plugin');
// 导入webpack-merge
const webpackMerage = require('webpack-merge');
//拿到baseConfig
const baseConfig = require('./base.config');
//将config文件合并导出
module.exports = webpackMerage(baseConfig, {
...
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有'),
new uglifyJsPlugin()
]
})
dev.config.js中:
// 导入webpack-merge
const webpackMerage = require('webpack-merge');
//拿到baseConfig
const baseConfig = require('./base.config');
module.exports = webpackMerage(baseConfig,{
devServer: {
contentBase: './dist',
inline: true
}
})
最后在使用时候,将package.json文件中的build改为:
更改一下config的指向:
"build": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"
然后使用:
run run dev
但是这样打包后的文件在build文件下面生成的dist文件夹里面,为了解决这个问题,就将base.config.js文件中output下的path改为:
path: path.resolve(__dirname, '../dist')
脚手架应用于webpack,webpack基于node。
安装Vue脚手架,-g(global:全局的)
npm install -g @vue/cli
注意:上面安装的是Vue CLI3的版本,如果需要想按照Vue CLI2的方式初始化项目是不可以的。
安装Vue CLI2:
npm install -g @vue/cli-init
安装完成后,查看是否安装成功:
vue --version
Vue CLI2初始化项目:
Vue CLI3初始化项目
vue create my-project
chrome中的 v8引擎(使用c++实现,v8是开源的),将js代码直接编译成二进制代码,在浏览器中执行
js -》 浏览器
js -》字节码 -》浏览器
视频材料链接: https://pan.baidu.com/s/1dxV3TSKpHoFhZo-oM3stFg
提取码: epuk