声明
本文没有细讲,是为了帮助工作需要的朋友们快速入门Vue写的,或者是复习用的文章,所以不要说:啊!这里也不说因为啥,就这么写
别杠,杠就是你对,出门左转谢谢,求你给我写一篇细节点的好吗,我必给你点赞
此文会一直更到实战项目完事,附带代码,有错误欢迎指出,有问题留言,期间我会不断补充,细节一下文章内容的,大家一起加油吧
总览
Vue起步
Hello World
在官网下载vue.js(百度Vue进入官网)
我们先用原生来写一段代码
<body>
<div id="app"></div>
<script>
var dom = document.getElementById('app')
dom.innerHTML = 'hello world'
</script>
</body>
现在我们要用vue来写了,我们要引入vue.js,然后创建vue实例
Vue.js在官网可以下载,我也会直接给大家
<body>
<div id="app">{{ content }}</div>
<script>
var app = new Vue({
el: '#app',
data: {
content: 'hello world'
}
})
</script>
</body>
el配置项:实例负责管理的区域
我们如果要延迟两秒显示内容的话需要用setTimeout
<body>
<div id="app">{{ content }}</div>
<script>
var app = new Vue({
el: '#app',
data: {
content: 'hello world'
}
})
setTimeout(function () {
app.$data.content = 'bye world'
}, 2000)
</script>
</body>
这里$data理解为data的别名
我们用原生和Vue追重要的区别是,我们不需要DOM操作了
使用Vue.js实现TodoList(例子)
<body>
<div id="app">
<input type="text">
<button>提交</button>
<ul>
<li>第一课的内容</li>
<li>第二课的内容</li>
</ul>
</div>
</body>
现在我有个需求,输入框输入内容,提交后呈现在li
我们现在,要利用vue.js不再让我们的数据是死数据
具体代码如下
<body>
<div id="app">
<input type="text">
<button>提交</button>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
list: ['第一课的内容', '第二课的内容']
}
})
</script>
</body>
效果和原生是一样的
v-for指令:类似于for,就是用来遍历渲染的
v-on:绑定事件
v-model:数据的双向绑定
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
list: ['第一课的内容', '第二课的内容'],
inputValue: ''
},
methods: {
handleBtnClick: function () {
}
},
})
</script>
</body>
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
},
})
</script>
</body>
MVVM模式
<body>
<div>
<input type="text">
<button id="btn">提交</button>
<ul></ul>
</div>
<script>
function Page() { }
$.extend(Page.prototype, {
init: function () {
this.bindEvents()
},
bindEvents: function () {
var btn = $('#btn')
btn.on('click', $.proxy(this.handleBtnClick,
this))//proxy是jquery的一个方法,可以改变this指向
},
handleBtnClick: function () {
alert('123')
}
})
var page = new Page()
page.init()
</script>
</body>
这是一段基础的代码
<body>
<div>
<input id="input" type="text">
<button id="btn">提交</button>
<ul id="ul"></ul>
</div>
<script>
function Page() { }
$.extend(Page.prototype, {
init: function () {
this.bindEvents()
},
bindEvents: function () {
var btn = $('#btn')
btn.on('click', $.proxy(this.handleBtnClick,
this))
},
handleBtnClick: function () {
var inputValue = $("#input").val()
var ulElem = $("#ul")
ulElem.append('<li>' + inputValue + '</li>')
$("#input").val('')
}
})
var page = new Page()
page.init()
</script>
</body>
这是我们的效果代码
可以达到跟vue一样的效果
M:模型,在这个代码里不涉及Ajax,所以不涉及M层
V:视图
P:控制器
MVVM呢
注意,我们需要关注的是view和model层
VM层不需要我们去操作,它是Vue自动操作的
- M层:就是我们写的数据
- V层:就是视图
- VM层:就是我们数据变,视图就跟着变,这个不需要我们操作
前端组件化
每个组件就是每个页面上的一个区域,类似于原生里面,我们不也是用各个div盒子来进行分区吗
我们在Vue里,不同的区域我们会有对应的组件
使用组件化思想修改TodoList
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{item}}</li> -->
<todo-item v-bind:content="item" v-for="item in list"></todo-item>
</ul>
</div>
<script>
//Vue.component用来注册全局组件
Vue.component("TodoItem", {
props: ['content'],
template: "<li>{{content}}</li>"
})
var app = new Vue({
el: '#app',
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
},
})
</script>
</body>
</html>
以上的是定义了一个全局组件,现在我们想定义一个局部组件呢
最主要的区别就是,我们需要去注册组件,用components去注册
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{item}}</li> -->
<todo-item v-bind:content="item" v-for="item in list"></todo-item>
</ul>
</div>
<script>
//Vue.component用来注册全局组件
// Vue.component("TodoItem", {
// props: ['content'],
// template: "<li>{{content}}</li>"
// })
// 注册局部组件
var TodoItem = {
props: ['content'],
template: "<li>{{content}}</li>"
}
var app = new Vue({
el: '#app',
components: {
TodoItem: TodoItem
},
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
}
},
})
</script>
</body>
</html>
简单的组件间传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button v-on:click="handleBtnClick">提交</button>
<ul>
<!-- <li v-for="item in list">{{item}}</li> -->
<todo-item v-bind:content="item"
v-bind:index="index"
v-for="(item,index) in list"
@delete="handleItemDelete">
</todo-item>
</ul>
</div>
<script>
//Vue.component用来注册全局组件
// Vue.component("TodoItem", {
// props: ['content'],
// template: "<li>{{content}}</li>"
// })
// 注册局部组件
var TodoItem = {
props: ['content', 'index'],
template: "<li @click='handleItemClick'>{{content}}</li>",
methods: {
handleItemClick: function () {
this.$emit("delete", this.index)
}
}
}
var app = new Vue({
el: '#app',
components: {
TodoItem: TodoItem
},
data: {
list: [],
inputValue: ''
},
methods: {
handleBtnClick: function () {
this.list.push(this.inputValue)
this.inputValue = ''
},
handleItemDelete: function (index) {
this.list.splice(index, 1)
}
},
})
</script>
</body>
</html>
Vue基础
Vue实例
Vue 的每个组件实际上都是一个Vue的实例,我们官方用vm
Vue2生命周期
生命周期函数就是Vue实例在某一个时间点会自动执行的函数,通过不同的时间点,可以做不同的时间,比较常用的是created和mounted,可以用来发axios和操作DOM
计算属性,方法与侦听器
<body>
<div id="app">
{{first + " " + last}}
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
first: "Jin",
last: "Lin"
}
})
</script>
</body>
我想让页面上显示Jin Lin,我在插值中是这个写法,可以发现,他成语句了,也就是有逻辑了,但是我们不想在模版的插值中去写逻辑,怎么办
我们引出一个概念:计算属性
<body>
<div id="app">
{{full}}
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
first: "Jin",
last: "Lin"
},
computed: {
full: function () {
console.log('计算了');
return this.first + " " + this.last
}
}
})
</script>
</body>
计算属性和别的最重要的区别就是:它还是属性,它和data里的属性最大的区别就是,它是通过计算得来的
计算属性有一个缓存的机制:就是计算属性依赖的值不发生改变,计算属性就不会发生计算
除了计算属性,我们还可以通过方法来达到相同的效果
<body>
<div id="app">
{{full()}}
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
first: "Jin",
last: "Lin"
},
methods: {
full: function () {
return this.first + " " + this.last
}
},
})
</script>
</body>
只不过我们需要用()调用一下
但是这种方法,是没有计算属性有效的,为什么这么说呢
除了以上的两种,还有一种,叫做侦听
<body>
<div id="app">
{{full}}
{{age}}
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
first: "Jin",
last: "Lin",
full: "Jin Lin",
age: "18"
},
watch: {
first: function () {
console.log('计算了一次');
this.full = this.first + "" + this.last
},
last: function () {
console.log('计算了一次');
this.full = this.first + "" + this.last
}
}
})
</script>
</body
watch也有缓存
那么,watch和computed都具有缓存的机制,推荐使用哪个呢
computed呗,因为简单呗
watch和computed区别:
watch可以开启异步任务,computed不可以开启异步,因为它依靠返回值
computed可以完成的功能,watch都可以完成
计算属性的getter和setter
<body>
<div id="app">
{{full}}
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
first: "Jin",
last: "Lin",
},
computed: {
full: {
get: function () {
return this.first + " " + this.last
},
set: function (value) {
var arr = value.split(" ")
this.first = arr[0]
this.last = arr[1]
}
}
}
})
</script>
</body>
Vue的样式绑定
<body>
<div id="app">
<div @click="hand" :class="{activated:isActivated}">
hello world
</div>
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
isActivated: false
},
methods: {
hand: function () {
this.isActivated = true
}
},
})
</script>
</body>
通过这个,我们就可以实现,点击变颜色了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
<style>
.activated {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div @click="hand" :class="{activated}">
hello world
</div>
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
activated: ""
},
methods: {
hand: function () {
this.activated = "activated"
}
},
})
</script>
</body>
</html>
我们想再点击变黑,互相切换呢
hand: function () {
this.activated = this.activated === "activated" ? "" : "activated"
}
可以用if else,但是三元表达式不是更简便,看着更牛b嘛,嘿嘿
那么,如果我们直接绑定style呢,两种写法:对象形式,数组形式
对象:
<body>
<div id="app">
<div :style="styleObj">
hello world
</div>
</div>
<script>
//创建了一个Vue实例
var vm = new Vue({
el: '#app',
data: {
styleObj: {
color: "red"
}
},
methods: {
},
})
</script>
</body>
变色的
<body>
<div id="app">
<div :style="styleObj" @click="hand">
hello world
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
styleObj: {
color: "red"
}
},
methods: {
hand: function () {
this.styleObj.color = this.styleObj.color === "red" ? "black" : "red"
}
},
})
</script>
</body>
数组模式
<body>
<div id="app">
<div :style="[styleObj,{fontSize:'20px'}]" @click="hand">
hello world
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
styleObj: {
color: "red"
}
},
methods: {
hand: function () {
this.styleObj.color = this.styleObj.color === "red" ? "black" : "red"
}
},
})
</script>
</body>
字符串写法:适用于样式的类名不确定,需要动态指令
数组写法:要绑定的样式个数不确定,名字也不确定
对象写法:要绑定的样式个数不确定,名字也不确定,但要动态决定用不用
Vue中的条件渲染
<body>
<div id="app">
<div v-if="show">{{message}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: false,
message: "Jin ❤ Lin"
}
})
</script>
</body>
这是v-if,同时还有一个指令v-show
<body>
<div id="app">
<div v-if="show">{{message}}</div>
<div v-show="show">{{message}}</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: false,
message: "Jin ❤ Lin"
}
})
</script>
</body>
注意这里的区别,v-if是直接没有,而v-show是用了display:none,也就是说,这两者在根本上就不同
显然,我们v-show的性能更高一些,因为它不用频繁地销毁和生产DOM
但是,v-if能和v-else配合使用,当然也可以和v-else-if使用,需要注意的是,中间不能被打断
还有一点需要注意的:v-show不能和template配合使用
Vue列表渲染
<body>
<div id="app">
<div v-for="item of list">
{{item}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
list: [
"Jin",
"Lin"
]
}
})
</script>
</body>
item of list中的of可以改成in
<body>
<div id="app">
<div v-for="(item,index) of list">
{{item}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
list: [
"Jin",
"Lin"
]
}
})
</script>
</body>
index是索引下标
为了提高性能,我们会给循环加一个key值(体现在虚拟DOM上)
这里不推荐用index,正常开发后端都会有一个id,或者是什么别的东西
<body>
<div id="app">
<div v-for="(item,index) of list" :key="item.id">
{{item}} ---- {{index}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
list: [
{
id: '001',
name: 'Jin'
},
{
id: '002',
name: 'Lin'
}
]
}
})
</script>
</body>
现在页面是这个效果
我们需要进行一下改进
我们还可以遍历对象
<body>
<div id="app">
<div v-for="item of userInfo">
{{item}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
userInfo: {
name: "shaka",
age: 18,
gender: "男"
}
}
})
</script>
</body>
我们可以加一个key
<body>
<div id="app">
<div v-for="(item,key) of userInfo">
{{item}}----{{key}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
userInfo: {
name: "shaka",
age: 18,
gender: "男"
}
}
})
</script>
</body>
我们可以发现这个key就是键名,那么item就是键值
当然,我们还可以加index
Vue中的set方法
这是对象的set方法
我们要是操作数组对象的话
我们可以用push、pop、shift等数组的api,这里也可以用set
首先,如果我们直接改的话
<body>
<div id="app">
<div v-for="(item,index) of userInfo">
{{item}}
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
userInfo: [1, 2, 3, 4]
}
})
</script>
</body>
Vue中的事件绑定
<body>
<div id="app">
<button @click="hand">Button</button>
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
hand: function (e) {
console.log(e);
}
},
})
</script>
</body>
这是我们正常的写法
那么我们应该怎么办呢
这种写法有什么好处呢
它可以让我们传递一些额外的参数
这就是绑定事件的两种写法
看下面的带代码
<body>
<div id="app">
<form action="/abc" @click="hand">
<input type="submit">
</form>
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
hand: function (e) {
console.log(e);
}
},
})
</script>
</body>
那么,我们想阻止表单提交的默认行为,怎么去做
这么写未免麻烦,简写形式呢
这个prevent叫做事件修饰符,同样的修饰符还有好几个
<body>
<div id="app">
<input @keydown="hand">
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
hand: function (e) {
console.log(e.target.value);
}
},
})
</script>
</body>
我们想输入回车的时候再输出到控制台,这个时候就需要按键修饰符了
还有系统修饰符需要注意,比如ctrl,它代表你必须一边按住ctrl一边输入才行
还有监测鼠标右键:@click.right 就可以了
<body>
<div id="app">
<div @click.right="hand">click</div>
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
hand: function (e) {
console.log("right");
}
},
})
</script>
</body>
Vue中的表单绑定
核心就是v-model指令,之前介绍双向绑定的时候已经给大家介绍过了,这里是想说,不止可以应用在input框中,还可以应用在别的地方
textarea,checkbox都可以应用
<body>
<div id="app">
<select v-model="value">
<option disabled>--请选择--</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
{{value}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
value: ""
}
})
</script>
</body>
需要注意的是,我们给option加value呢
这样页面会优先显示value的值,如果没有value才会显示text的内容
当然,v-model也有修饰符,比如lazy(失去焦点发生反应),number
就是input框有一个问题,就是我们不管输入字符串还是数字,它都会返给我们一个字符串
<body>
<div id="app">
<input type="text" v-model="value">
{{value}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
value: ""
},
watch: {
value: function () {
console.log(typeof this.value);
}
}
})
</script>
</body>
Vue组件
Vue组件的细节点
<body>
<div id="app">
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
<script>
Vue.component('row', {
template: '<tr><td>this is row</td></tr>'
})
var vm = new Vue({
el: '#app'
})
</script>
</body>
但是会出bug,违背了我们h5的规范
那么我们就会用is来解决这个问题
<body>
<div id="app">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component('row', {
template: '<tr><td>this is row</td></tr>'
})
var vm = new Vue({
el: '#app'
})
</script>
用is属性,不会出bug
既能保证tr里是我们的组件,又能保证它符合h5的编码规范,不会出bug
同理,ul,li也是这个道理
我现在想对代码进行改进
这样可以吗
答案是不可以的,这是为什么
这里要说的是,我们虽然在vm(根组件)里面的data可以写成对象形式,但是在非根组件(也就是子组件)中是不可以的,我们要求必须是个函数
这样写就不会发生问题了
这里就要说,为什么要是个函数了
ref:用来操作DOM
<body>
<div id="app">
<div ref="hello" @click="hand">hello world</div>
</div>
<script>
var vm = new Vue({
el: '#app',
methods: {
hand: function () {
console.log(this.$refs.hello);
}
},
})
</script>
</body>
父子组件的数据传递
首先,我们先注册局部组件
<body>
<div id="app">
<counter></counter>
<counter></counter>
</div>
<script>
//局部组件
var counter = {
template: '<div>0</div>'
}
var vm = new Vue({
el: '#app',
components: {
counter: counter
}
})
</script>
</body>
父组件通过属性的形式向子组件传递数据
<body>
<div id="app">
<counter :count="0"></counter>
<counter :count="1"></counter>
</div>
<script>
//局部组件
var counter = {
props: ['count'],
template: '<div>{{count}}</div>'
}
var vm = new Vue({
el: '#app',
components: {
counter: counter
}
})
</script>
</body>
<body>
<div id="app">
<counter :count="0"></counter>
<counter :count="1"></counter>
</div>
<script>
//局部组件
var counter = {
props: ['count'],
template: '<div @click="hand">{{count}}</div>',
methods: {
hand: function () {
this.count++
}
},
}
var vm = new Vue({
el: '#app',
components: {
counter: counter
}
})
</script>
</body>
这样可以实现,但是这样是不被允许的
这是一个在Vue里面被称作单项数据流的东西,就是,我们只能用父组件传递过来的值,而不能去修改它
所以我们采用这种方式,组件中的this,永远指向自身。即便是父组件传递过来的数据,vue底层也帮你都转到自组件的属性上去了。
那我们,子组件向父组件传值呢:自定义事件
<body>
<div id="app">
<counter :count="3" @inc="handleIncrease"></counter>
<counter :count="2" @inc="handleIncrease"></counter>
<div>{{total}}</div>
</div>
<script>
//局部组件
var counter = {
props: ['count'],
data() {
return {
number: this.count
}
},
template: '<div @click="hand">{{number}}</div>',
methods: {
hand: function () {
this.number = this.number + 2
this.$emit('inc', 2)//可以传递参数
}
},
}
var vm = new Vue({
el: '#app',
data: {
total: 5
},
components: {
counter: counter
},
methods: {
handleIncrease: function (step) {//step就是接受inc的参数
// alert(step)
this.total += step
}
}
})
</script>
</body>
组件参数校验与非props特性
<body>
<div id="app">
<child content="hello world"></child>
</div>
<script>
Vue.component('child', {
props: ['content'],
template: '<div>{{content}}</div>'
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
这是一段正常的父传值给子的代码,我们现在有一个需求,子在接受父的数据的时候,我们想对其进行约束,我们应该怎么去做呢
比如,我们只接受字符串
那我们的需求是,字符串或者数字呢
那么什么是非props特性,就是子组件没人接收数据
给组件绑定原生事件
<body>
<div id="app">
<child @click="hand"></child>
</div>
<script>
Vue.component('child', {
template: '<div>Child</div>'
})
var vm = new Vue({
el: '#app',
methods: {
hand: function () {
alert('Jin❤Lin')
}
},
})
</script>
</body>
我们发现它是无法生效的
这样才属于我们绑定了原生的事件,可以触发
那如果我想要触发自定义的事件呢
那如果我们不想这么写,我们可以用一个native修饰符
<body>
<div id="app">
<child @click.native="hand"></child>
</div>
<script>
Vue.component('child', {
template: '<div>Child</div>',
})
var vm = new Vue({
el: '#app',
methods: {
hand: function () {
alert('Jin❤Lin')
}
},
})
</script>
</body>
也可以达到效果
非父子组件间的传值
我们知道组件的拆分,积类似于原生的div
我们知道了父子组件之间的传递,但是如果我们不是父子之间的传递呢,比如兄弟之间的传值,隔辈之间的传值呢
我们的确可以通过父子传值的方式,一直反复下去,可以达到效果,但是这样太费劲了
那么怎么做到简单的方式呢?
vuex和总线的机制(发布订阅模式、观察者模式)
vuex在后面单说,这里先介绍总线
<body>
<div id="app">
<child content="Jin"></child>
<child content="Lin"></child>
</div>
<script>
Vue.prototype.bus = new Vue()
Vue.component('child', {
props: {
content: String
},
template: '<div @click="hand">{{content}}</div>',
methods: {
hand: function () {
this.bus.$emit('change', this.content)
}
},
mounted: function () {
var this_ = this
this.bus.$on('change', function (msg) {
this_.content = msg
})
}
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
但是我们之前说过了,我们Vue有单向数据流,不能直接修改根组件传过来的值
所以要进行改进
这样就没问题了
在Vue中使用插槽
<body>
<div id="app">
<child></child>
</div>
<script>
Vue.component('child', {
template: '<div><p>hello</p></div>',
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
这是一段正常的代码,相信大家到这里,是没什么问题了
页面显示如下
现在,我们对代码进行更改
我们发现页面出现了一些问题,我们发现父组件传过来的p标签被转义了,那么我们不想让它转义怎么办
我们进行如下的改进就可以了
所以,显然这么写是有问题的
同时,如果用这种方法传的值过多的话,代码就不好看了
这样,我们就需要一个新概念了:插槽(这里是默认插槽)
<body>
<div id="app">
<child>
<p>Lin</p>
</child>
</div>
<script>
Vue.component('child', {
props: ['content'],
template: `<div>
<p>Jin</p>
<slot></slot>
</div>`,
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
也就是说,通过插槽,我们可以更方便地向自组件传递DOM元素
同时,slot还可以设置默认值
这是它的页面效果
那么,我现在不想要这个效果呢,想一一对应着来呢
这就需要具名插槽了
<body>
<div id="app">
<child>
<div class="header" slot="header">header</div>
<div class="footer" slot="footer">footer</div>
</child>
</div>
<script>
Vue.component('child', {
template: `<div>
<slot name="header"></slot>
<slot name="footer"></slot>
</div>`,
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
这样就OK了
这样的好处是,如果我们插入多个DOM结构
具名插槽也可以有默认值,这里不演示了
Vue中的作用域插槽
<body>
<div id="app">
<child>
</child>
</div>
<script>
Vue.component('child', {
data() {
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<li v-for="item of list">
{{item}}
</li>
</ul>
</div>`,
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
当一些时候,DOM结构不确定的时候,我们的DOM结构想从外部传递进来的时候,就需要作用域插槽了
<body>
<div id="app">
<child>
<template slot-scope="props">
<li>{{props.item}}</li>
</template>
</child>
</div>
<script>
Vue.component('child', {
data: function () {
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot>
v-for="item of list"
:item=item
</slot>
</ul>
</div>`,
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
这里写成:item = item。其中第一个item自定义名字,第二个是for循环中的item。这里是插槽中有数据需要向外暴露出去,由外部决定的渲染样式,必须通过属性绑定的形式。也可以近似的理解为父子组件的传值,因为template的相当于是去填充插槽的内容,这和子组件去填充父组件也是异曲同工之妙。props属性绑定的形式传值,都是近似一种父子关系。
动态组件与v-once指令
<body>
<div id="app">
<child-one></child-one>
<child-two></child-two>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
})
</script>
</body>
这是我的页面效果
现在我要做一个功能
当我点击这个按钮的时候,一会child-one显示,一会child-two显示
大家可能首先会想到条件渲染(v-if),代码如下
<body>
<div id="app">
<child-one v-if="type === 'child-one'"></child-one>
<child-two v-if="type === 'child-two'"></child-two>
<button @click="hand">Change</button>
</div>
<script>
Vue.component('child-one', {
template: '<div>child-one</div>'
})
Vue.component('child-two', {
template: '<div>child-two</div>'
})
var vm = new Vue({
el: '#app',
data: {
type: 'child-one'
},
methods: {
hand: function () {
this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
}
},
})
</script>
</body>
是可以做到的,没有问题
现在我们还可以通过动态组件达到这种效果
我们发现,效果是一样的
就是动态组件会通过is属性里面的内容,加载不同的组件
v-once表示模板只渲染一次
vue中的动画特效
Vue中CSS动画原理
<body>
<div id="app">
<div v-if="show">Jin ❤ Lin</div>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
}
},
})
</script>
</body>
现在,我有这么一段代码,我现在想给它加一个动画效果
那我们就要在div外层包一个transition标签
但是我们加完后,发现效果并没有出现
我们加了这个代码之后就会有效果了,这是因为什么
注意这里的fade是我们自己起的名字,默认是v-enter
原理图
它的原理就是给我们div动态添加了一个class
这都是我们显示时候的效果,那么隐藏时候的效果呢
这样就OK啦
其实是同样的道理
当然,这是可以简写,看着舒服一些的
在Vue中使用Animate.css库
我们先在Vue中使用keyframs创建一个动画效果
那我们可以不用默认的名字,自己起名字吗
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
<style>
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.active {
transform-origin: left center;
animation: bounce-in 1s;
}
.leave {
transform-origin: left center;
animation: bounce-in 1s reverse;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade" enter-active-class="active" leave-active-class="leave">
<div v-if="show">Jin ❤ Lin</div>
</transition>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
}
},
})
</script>
</body>
</html>
现在我们要用animate.css来做动画的效果(详情看官网文档)
具体的animate.css看官网的api文档就行
在Vue中同时使用过渡和动画
我们想让页面的内容第一次出现的时候也有动画效果
这样就可以了
现在我有另一个需求,我要求不仅要有css3的动画效果,还有一个过渡的动画效果呢
先加上这两个字段,然后我们继续去写style样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./animate.min.css">
<script src="./vue.min.js"></script>
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade" appear appear-active-class="animate__animated animate__swing"
enter-active-class=" animate__animated animate__shakeX fade-enter-active"
leave-active-class="animate__animated animate__swing fade-leave-active">
<div v-if="show">Jin ❤ Lin</div>
</transition>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
}
},
})
</script>
</body>
</html>
那如果重复了,我们以那个为准呢,是以keyframe,还是以transition为准
以transition为准
Vue中的Js动画与Velocity.js的结合
我们在此之前都是通过CSS实现一些动画效果,现在我们要通过JS来实现一些动画效果
Vue之中,提供给了我们很多关于动画的钩子
这个el指的就是动画包裹的div标签
当@before-enter这个事件触发之后,就会进入真正的动画时间,也就会进入到另一个事件@enter
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade" @before-enter="handBefore" @enter="handEnter">
<div v-if="show">Jin ❤ Lin</div>
</transition>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
},
handBefore: function (el) {
el.style.color = 'red'
},
handEnter: function (el, done) {
setTimeout(() => {
el.style.color = 'yellow'
}, 2000);
}
},
})
</script>
</body>
</html>
就是告诉Vue一声,诶,这个动画我执行完了
当done这个函数执行完,我们又会进入到一个事件@after-enter
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade" @before-enter="handBefore" @enter="handEnter" @after-enter="handAfter">
<div v-if="show">Jin ❤ Lin</div>
</transition>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
},
handBefore: function (el) {
el.style.color = 'red'
},
handEnter: function (el, done) {
setTimeout(() => {
el.style.color = 'yellow'
}, 2000);
setTimeout(() => {
done()
}, 4000);
},
handAfter: function (el) {
el.style.color = '#000'
}
},
})
</script>
</body>
</html>
那么我除了入场动画,还有对应的出场动画,就是把对应的enter改成leave就可以了,这里就不过多叙述了
加入Velocity.js怎么去写呢
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./vue.min.js"></script>
<script src="http://files.cnblogs.com/files/xiaohuochai/velocity.min.js"></script>
</head>
<body>
<div id="app">
<transition name="fade" @before-enter="handBefore" @enter="handEnter" @after-enter="handAfter">
<div v-show="show">Jin ❤ Lin</div>
</transition>
<button @click="hand">切换</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show: true
},
methods: {
hand: function () {
this.show = !this.show
},
handBefore: function (el) {
el.style.opacity = 0
},
handEnter: function (el, done) {
Velocity(el, { opacity: 1 }, { duration: 1000 })
},
handAfter: function (el) {
}
},
})
</script>
</body>
</html>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/79708.html