CSS预处理器
css缺陷:
解决方法:css预处理器
VUe特性:
虚拟DOM 计算属性
1. 第一个Vue项目
引入 Vue.js : https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
{{message}}
</div>
<script>
var vm = new Vue({
el: "#app",//绑定标签,el是元素的意思
data: {
//数据都是以键值对的方式存在的
message: "hello Vue!"
}
});
</script>
</body>
</html>
注意:程序里Vue这三个字母一定要一字不差的打,不要改大小写,否则会识别不出来。
效果:
简单实现一下双向绑定:
直接从控制台更改程序的js代码,界面立即改变。
本程序里的vm就是个Vue实例化对对象,它时刻监听,当数据发送变化立即渲染到前端,不需要刷新界面。
Vue不改变Dom元素(使用虚拟Dom),只是更改了里面的值。
即时运行即时编译
Vue核心,实现了Dom监听和数据绑定
2.Vue基本语法
v-bind:用于绑定数据和元素属性
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒查看此处绑定的信息
</span>
</div>
<script>
var vm = new Vue({
el: "#app",//绑定标签,el是元素的意思
data: {
//数据都是以键值对的方式存在的
message: "hello Vue!"
}
});
</script>
</body>
</html>
效果:
v-if
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>if-else</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else-if="type==='C'">C</h1>
<h1 v-else>D</h1>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
type: "A"
}
});
</script>
</body>
</html>
效果:
v-for
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-for</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<li v-for=" item in items">
{{item.message}}
</li>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
items: [
{message: '今天是个好日子'},
{message: '今夜阳光明媚'},
{message: '今夜多云转晴'}
]
}
});
</script>
</body>
</html>
效果:
循环还能打印下标:
<li v-for=" (item,index) in items">
{{item.message}}-----{{index}}
</li>
动态向数组中添加数据:
vm.items.push({message: ‘今夜多云转晴’});
v-on 绑定事件
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-on</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<button v-on:click="sayHi">点我</button>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "针不戳"
},
methods: {
定义的方法必须写在这里,event是传入事件
sayHi: function (event) {
alert(this.message)
}
}
});
</script>
</body>
</html>
效果:
3.Vue双向绑定
数据变,视图跟着变,视图变,数据也跟着变
使用v-model 指令
先试一下 input 和 textarea 标签:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-mode</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
输入文本:<input type="text" v-model="message">{{message}}<br>
输入文本:<textarea cols="30" rows="10" v-model="message"></textarea>{{message}}
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "针不戳"
}
});
</script>
</body>
</html>
效果:
就很牛
再来搞搞单选框:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
选择性别:
<input type="radio" name="sex" value="男" v-model="zqy">男
<input type="radio" name="sex" value="女" v-model="zqy">女
<input type="radio" name="sex" value="男儿身女儿心" v-model="zqy">男儿身女儿心
<p>
你的性别为:{{zqy}}
</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
zqy: ""
}
});
</script>
</body>
</html>
效果:
下拉框:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<select v-model="zqy">
<option value="" disabled>请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>
你的选择:{{zqy}}
</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
zqy: ""
}
});
</script>
</body>
</html>
效果:
Vue组件(就是自定义一个标签)
Vue.component("自定义组件的名",{
props:['要接收的数据'],
template: '模板'
});
先简单实现一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<zqy></zqy>
</div>
<script>
//自定义了一个组件 "zqy" ,template 里面表示这个自定义组件的模板
Vue.component("zqy",{
template: '<li>牛啊</li>'
});
var vm = new Vue({
el: "#app"
});
</script>
</body>
</html>
效果:
–
给自定义绑定上Vue数据
上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<zqy v-for="item in items" v-bind:zhou="item"></zqy>
</div>
<script>
//自定义了一个组件 "zqy" ,template 里面表示这个自定义组件的模板
Vue.component("zqy",{
props:['zhou'],
template: '<li>{{zhou}}</li>'
});
var vm = new Vue({
el: "#app",
data:{
items:["好","牛","针不戳"]
}
});
</script>
</body>
</html>
效果:
–
实现原理:
第一步,在Vue中定义了数据:
var vm = new Vue({
el: "#app",
data:{
items:["好","牛","针不戳"]
}
});
第二步,在自定义组件内使用 v-for 遍历数组中的数据,并将遍历出来的数据与 “zhou” 绑定:
在这里v-for中的 item 是可以随意写的,在这里为了便是度更改一些使用了 item
<zqy v-for="item in items" v-bind:zhou="item"></zqy>
这样也可以:(v-bind后的也是能自定义)
<zqy v-for="niu in items" v-bind:zhou="niu"></zqy>
第三步,组件接收数据并显示:
使用 props:[‘zhou’] 接收上一步绑定数据的 “zhou”
Vue.component("zqy",{
props:['zhou'],
template: '<li>{{zhou}}</li>'
});
4.Axios异步通信
浏览器版本过低会不支持,设置到6或者以上:
因为接口大都是json格式,所以先写一段json数据:
{
"name":"狂神说java",
"url": "http://baidu.com",
"page": 1,
"isNonProfit":true,
"address": {
"street": "含光门",
"city":"陕西西安",
"country": "中国"
},
"links": [
{
"name": "B站",
"url": "https://www.bilibili.com/"
},
{
"name": 4399,
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
导入Axios包 :https://unpkg.com/axios/dist/axios.min.js
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Axios</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<div>{{info.name}}</div>
<div>{{info.address.country}}</div>
<a v-bind:href="info.url">点击</a>
</div>
<script>
var vm = new Vue({
el: "#app",
data() {
return {
//请求的返回参数格式,必须和json格式一样(可以不都写,但是写了的格式必须相同)
info: {
name: null,
address: {
street:null,
city:null,
country:null
},
url:null
}
}
},
mounted() {
//钩子函数 链式编程 ES6特性
axios.get('../data.json').then(response => (this.info=response.data))
}
});
</script>
</body>
</html>
–
钩子函数:就是在加载过程中到了一定时期会自动触发的函数。“钩子”就是在某个阶段给你一个做某些处理的机会。
mounted() {
//钩子函数 链式编程 ES6特性
axios.get('../data.json').then(response => (this.info=response.data))
}
});
上一段代码中的 then() 是表示当上一步获取到资源后摇进行的操作。
5.计算属性
能将计算结果缓存为一个静态的属性,将不变化的结果存入缓存,每次调用时不执行函数,直接返回缓存中的数据。
先上个代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<p>普通函数:{{currentTime1()}}</p>
<p>计算属性:{{currentTime2}}</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: "好"
},
methods: {
currentTime1: function () {
return Date.now();//返回当前时间
}
},
computed: {//计算属性
//这里的方法与 methods 里的方法不能重名,否则只会调用 methods 中的同名方法
currentTime2: function () {
return Date.now();//返回当前时间
}
}
});
</script>
</body>
</html>
–
如果刷新界面,两个值都跟着改变,计算属性刷新界面后就将之前的缓存删除导入新的缓存:
通过控制台调用函数和计算属性:
1.普通函数每次调用都会重新执行函数中的代码,锁以时间戳也会跟着改变:
2.控制台调用计算属性,每次获得的值都相同,是因为计算属性在第一次执行的时候,已经将结构保存到缓存中,每次调用这个计算属性就会直接将缓存中的数据显示出来,减少了资源的占用:
3.当界面不刷新的时候怎么才会改变计算属性缓存的数据呢?
computed: {
currentTime2: function () {
this.message;//加入这行代码
return Date.now();
}
}
让计算属性访问 data() 中的数据,当 data() 中对应的属性发生改变,计算属性缓存就会重新加载,之久会发生改变
6.插槽slot
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。
–
使用插槽实现这个界面(因为一般情况下,这种数据都是从数据库中获取的,所以比较适合使用插槽):
第一步,先定义一个含有的组件,命名为 ‘todo’ :
Vue.component('todo',{
template:
'<div>' +
'<slot></slot>' +
'<ul>' +
'<slot></slot>' +
'</ul>' +
'</div>'
});
为了美观还有另外一种写法(用 ‘ \ ’代替 ’ + '):
Vue.component('todo',{
template:
'<div>\
<slot></slot>\
<ul>\
<slot></slot>\
</ul>\
</div>'
});
第二步,在定义两个组件,用于链接数据,并且便于插入插槽中(咱先把里面的数据写死,一会再动态获取数据):
Vue.component('todo-title', {
template: '<div>用于显示标题</div>'
});
Vue.component('todo-items', {
template: '<li>Java</li>'
});
第三步,将最后定义的两个组件与Vue中的data数据链接(还没连接,这里是准备工作),将这两个自定义组件与插件slot绑定:
Vue.component('todo', {
template:
//使用 name 绑定自定义组件和插槽 slot
'<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title', {
props: ['title'],
template: '<div>{{title}}</div>'
});
Vue.component('todo-items', {
props: ['todoItems'],
template: '<li>{{todoItems}}</li>'
});
var vm = new Vue({
el: "#app",
data:{
title:'学点啥',
todoItems:['Java','Vue','MySql']
}
});
第四步,将div中的自定义标签与solt绑定,并且绑定data中的数据(第一次学,有点不太懂了,为啥下面绑完了上面还要绑):
注意:v-bind 能简写为一个冒号 ‘ : ’
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:Ctitle="title"></todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :Zitems="item"></todo-items>
</todo>
</div>
总体代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>solt插槽</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:Ctitle="title"></todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :Zitems="item"></todo-items>
</todo>
</div>
<script>
Vue.component('todo', {
template:
'<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title', {
props: ['Ctitle'],
template: '<div>{{Ctitle}}</div>'
});
Vue.component('todo-items', {
props: ['Zitems'],
template: '<li>{{Zitems}}</li>'
});
var vm = new Vue({
el: "#app",
data:{
title:'学点啥',
todoItems:['Java','Vue','MySql']
}
});
</script>
</body>
</html>
7.自定义事件分发
以第6部分代码为基础,如何实现点击删除一条数据呢?
–
第一步,先把界面实现一下:
修改了这部分代码
Vue.component('todo-items', {
props: ['Zitems'],
template: '<li>{{Zitems}} <button>删除</button> </li>'
});
效果:
第二步,明白如何删除数组中指定的元素,这里使用到了js中的 splice( ) 函数:
先测试一下这个函数行不行,直接在Vue实例中写:
var vm = new Vue({
el: "#app",
data:{
title:'学点啥',
todoItems:['Java','Vue','MySql']
},
methods:{
removeItems:function (index){
console.log("删除下标为"+index+"的元素"+this.todoItems[index]+" 成功~")
//从下标为index的开始删除,删除一个元素
this.todoItems.splice(index,1);
}
}
});
效果(跳出了些警告,不用管它):
问题来了,如何通过一个自定义组件的按钮来触发这里面的函数事件呢,反正直接调用是不行的(只能调用自己组件内的方法),那样用直接报错,就不截图了
新概念来了:
–
先做好准备工作,数组遍历的时候顺便比那里出下标,并且传递到自定义组件中:
修改的两处代码:
<todo>
<todo-title slot="todo-title" v-bind:Ctitle="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems" :Zitems="item" :index="index"></todo-items>
</todo>
Vue.component('todo-items', {
props: ['Zitems','index'],
template: '<li>{{index}}---{{Zitems}} <button @click="removeItems(index)">删除</button> </li>'
});
开始操作:
自定义事件并绑定Vue中的 removeItems( ) 事件:
<todo>
<todo-title slot="todo-title" v-bind:Ctitle="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:Zitems="item" :index="index" v-on:remove="removeItems(index)"></todo-items>
</todo>
Vue.component('todo-items', {
props: ['Zitems','index'],
template: '<li>{{index}}---{{Zitems}} <button @click="remove">删除</button> </li>',
methods:{
remove:function (index){
this.$emit('remove',index)
}
}
});
总体代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自定义事件分发</title>
<script src='https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js'></script>
</head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" v-bind:Ctitle="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:Zitems="item" :index="index" v-on:remove="removeItems(index)"></todo-items>
</todo>
</div>
<script>
Vue.component('todo', {
template:
'<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title', {
props: ['Ctitle'],
template: '<div>{{Ctitle}}</div>'
});
Vue.component('todo-items', {
props: ['Zitems','index'],
template: '<li>{{index}}---{{Zitems}} <button @click="remove">删除</button> </li>',
methods:{
remove:function (index){
//$emit的两个参数,第一个参数是自定义函数的函数名,第二个参数是传递的参数
this.$emit('remove',index)
}
}
});
var vm = new Vue({
el: "#app",
data:{
title:'学点啥',
todoItems:['Java','Vue','MySql']
},
methods:{
removeItems:function (index){
console.log("删除下标为"+index+"的元素"+this.todoItems[index]+" 成功~")
//从下标为index的开始删除,删除一个元素
this.todoItems.splice(index,1);
}
}
});
</script>
</body>
</html>
效果:
黄色警告看着难受,不过不影响使用,就不管了。
小结:在前端组件中能直接调用Vue中的函数,但是自定义组件不能直接调用,这时候就要使用一个桥梁,自定义函数,先在前端使用自定义函数绑定Vue中的函数,然后再自定义组件中与自定义事件绑定,自定义函数就是这个桥梁:
拓展:JS数组操作:
完