安装
npm install vue
语法
声明式渲染
<div id='app'>
{{ message }}{{name}}
<span v-bind:title = 'message2' style="display: block;">
鼠标悬停几秒查看此处动态绑定的提示信息
</span>
</div>
var app = new Vue({
el: '#app',
data: {
message:'hello message',
name:' 有点意思',
message2:'页面加载于'+new Date().toLocaleString()
}
})
条件与循环
- 条件
<div id="app-3"> <p v-if="seen">现在你看到我了</p> </div>
var app = new Vue({
el: '#app',
data:{
seen : true
}
})
- 循环
<div id='app'>
<ol>
<li v-for='todo in todos'>
{{ todo.text }}
</li>
</ol>
</div>
var app = new Vue({
el: '#app',
data:{
todos:[
{ text:'学习JavaScript' },
{ text:'学习Vue' },
{ text:'整个牛项目' }
]
}
})
//最后可以用app.todos.push({text:'内容'})
处理用户输入
<div id="app">
<p>{{message}}</p>
<button v-on:click='reverseMessage'>
反转消息
</button>
</div>
var app = new Vue({
el: '#app',
data:{
message:'hello Vue.js'
},
methods:{
reverseMessage:function(){
this.message = this.message.split('').reverse().join('')
//split将其全部转成数组然后用reverse方法将数据的顺序反转最后用join方法转成字符串连接起来
}
}
})
v-model命令将表单与上面message内容的双向绑定
<div id="app">
<p>{{message}}</p>
<input type="text" v-model="message">
</div>
var app = new Vue({
el: '#app',
data:{
message:'hello Vue'
},
})
生命周期钩子
不能在选项上或者property上使用箭头函数因为箭头函数没有this
-
beforeCreate
创建之前 没有初始化数据 同时没有真实dom
基本不用 -
created 创建结束 有数据 没有
dom
可以修改数据 在这里修改数据不会触发运行中的更新的生命周期
-
beforemount
将组件渲染,并且构造 DOM 元素然后塞入页面的过程称为组件的挂载。 -
mounted 挂载成功后 有数据可以修改数据 可以修改
dom
-
beforeUpdata
挂载之后数据更新的时候触发,挂载之前数据更新不会触发数据是更新之后的
dom
是更新之前的 -
updated 数据与
dom
都更新完了触发数据是更新之后的
dom
也是更新之后的注意做数据修改的操作 可能引起死循环
-
before Destroy 有数据 有this 都没有用 有
dom
-
destroyed 有数据 有this 没用 没有
dom
生命周期
beforeCreate
-
创建 创建虚拟
dom
created
beforeMount
-
挂载 虚拟
dom
变成真实dom
出现在页面上mounted
beforeUpdate
-
更新 更新数据->更新
dom
元素updated
beforeDestory
-
销毁 组件pass away
destoryed
4 (4个阶段) 8(每个阶段2个钩子函数) 2(缓存钩子) 1(捕获错误的钩子函数)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a5oefp4M-1656248957715)(D:\ps personal works\lifecycle.png)]
常用
created 网络请求
mounted 网络请求 初始化dom
before destroy/destroyed 组件销毁前擦屁股解决遗憾
数据与方法
当一个 Vue
实例被创建时,它将 data
对象中的所有的 property 加入到 Vue
的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
只有当实例被创建就已经存在于data
中的property才是响应的。
除了数据的property,Vue
实例还暴露了一些实例的property与方法前缀有$
https://cn.vuejs.org/v2/api/#%E5%AE%9E%E4%BE%8B-property
模版语法
文本
<div id="app">
<span>Message: {{ msg }}</span>
</div>
var vm = new Vue({
el:'#app'
data:{
msg:'hello'
}
})
HTML
<div id="app">
{{msg}}
<p>using mustaches:{{rawHtml}}</p>
<p >Using v-html directive: <span v-html="rawHtml"></span></p>
</div>
var vm = new Vue({
el:'#app',
data:{
msg:'hello',
rawHtml:'<span style="color:red">this is my</span>',
}
})
当我们最后出现的效果是span里面套了一个span标签,即这个v-html指令是在指定的标签里面再套一个我们的Dom元素
Attribute
Mustache语法不能用在HTML的属性上,我们可以用v-bind指令来绑定
<span v-bind:id="dynamicId">324342</span>
dynamicId:'yiwh'
使用JavaScript表达式
{{ number + 1 }}//这里的number可以用变量
{{ ok ? 'YES' : 'NO' }}//这里的ok也可以是变量但也可以是一个比较表达式值为true或者FALSE
{{ message.split('').reverse().join('') }}//message可以是一个属性
<div v-bind:id="'list-' + id"></div>
只能访问全局变量的一个白名单
if (process.env.NODE_ENV !== 'production') {
const allowedGlobals = makeMap(
'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
'require' // for Webpack/Browserify
)
每个绑定都只能包含单个表达式
指令
指令 (Directives) 是带有 v-
前缀的特殊 attribute。
<p v-if="seen">现在你看到我了</p>
v-if
指令将根据表达式 seen
的值的真假来插入/移除 <p>
元素。
参数
<a v-bind:href="url">...</a>
这里是将url
与hrel
属性相绑定
<a v-on:click="doSomething">...</a>
这里的参数为监听的事件名,用do_Something来作为这个函数
动态参数
可以用方括号括起来的 JavaScript 表达式作为一个指令的参数
<a v-bind:[attributeName]="url"> ... </a>
<!-- 缩写 -->
<a :[attributeName]="url"></a>
<a v-on:[eventName]="doSomething"> ... </a>
<!-- 缩写 -->
<a @[eventName]="dosomething">...</a>
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML attribute 名里是无效的。
浏览器会把 attribute 名全部强制转为小写:
<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
<div id="app">
<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
someattr:'href',
value:'https://www.baidu.com/'
}
})
</script>
修饰符
缩写
v-bind
缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
V-on缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
实例
<div id="app">
<p v-if="seen">现在你看到我了</p>
<a v-bind:href="url">...</a>
<div @click="click1">
<div @click.stop="click2">
<!-- 这个stop可以只触发当前这个不向上传递 -->
click me
</div>
</div>
</div>
var vm = new Vue({
el : "#app",
data : {
seen : false,
url : "https://cn.vuejs.org/v2/guide/syntax.html#%E6%8C%87%E4%BB%A4"
},
methods:{
click1 : function () {
console.log('click1......');
},
click2 : function () {
console.log('click2......');
}
}
});
计算属性和侦听器
计算属性
对于任何复杂逻辑,你都应当使用计算属性。
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello',
//reversedMessage:'真巧'//默认是先来data里面找,data里面没有找到就直接去computed里面找
},
computed: {
//计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
vm.reversedMessage
的值始终取决于 vm.message
的值。
计算属性的 getter 函数是没有副作用 (side effect) 的
计算属性缓存vs方法
计算属性是通过响应系统通过绑定message的值,如果message的值改变则响应系统就会改变页面的值,如果值不改变,则不重新渲染页面.展示的仍然是页面之前缓存的数据,计算属性是基于它们的响应式依赖进行缓存的.
方法则是每次都会执行一次,每次都会重新渲染页面.
明显两种写法中计算属性的效率要高的多.
计算属性是基于它们的响应式依赖进行缓存的—这句话怎样理解呢?
下面的计算属性将不再更新,因为 Date.now()
不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
也就是说计算属性只有依赖于vue
实例中具有响应能力的属性时才能达到这种效果,这其实展示的是响应系统的一种可传递性,以及其可传递性的限制.
计算属性VS侦听方法
https://www.jianshu.com/p/b70f1668d08f
-
computed是监听多个数据改变一个数据,一般用于计算一些比较复杂的场景,比如购物车计算价格,就是多对一
watch是监听一个数据从而改变多个数据,通过观察一个数据的变化去改变其他数据,比如搜索框提示列表,就是一对多 -
computed用于计算,watch用于观察
-
computed一定要有return
-
computed具有缓存性,当依赖的数据没有发生变化,就会从缓存中取出数据,所以computed的性能比watch要好一点
-
计算属性不能在data中声明
-
watch中可以进行异步或者开销较大的操作
侦听方法名字为watch它可以让我们侦听一个对象内的属性让我们使其它属性随着这个属性变化
但computed属性与这个有些相似我们需要自己辨别什么时候使用这两个属性
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>{{ add }}</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello',
add:1+2,
},
// computed: {
// //计算属性的 getter
// reversedMessage: function () {
// // `this` 指向 vm 实例
// return Date.now();
// }
// }
watch:{
message(){
this.message = '你好'
},
}
})
watch属性里面放的是函数,函数数对应相关的属性,当对应的属性改变时就会执行这个方法。
immediate和handler
这样使用watch时有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。
<div id="root">
<p>FullName: {{fullName}}</p>
<p>FirstName: <input type="text" v-model="firstName"> </p>
</div>
<script>
new Vue({
el: '#root',
data: {
firstName: 'Dawei',
lastName: 'Lou',
fullName: ''
},
watch: {
firstName: {
handler(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
},
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法,如果设置了false,那么效果和上边例子一样
immediate: true
}
}
})
</script>
deep属性(深度监听,常用于对象内的属性变化)
<div id="root">
<p>obj.a: {{obj.a}}</p>
<p>obj.a: <input type="text" v-model="obj.a"></p>
</div>
如果要监听object里面的属性a的值,这时就需要deep属性
watch: {
obj: {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
deep: true
}
}
上面的方法对性能影响大,修改object里面任何一个属性都会触发这个监听器里的handler我们可以这样处理
let vm = new Vue({
el: '#root',
data: {
obj: {
a: 123
}
},
watch: {
'obj.a': {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
deep:true
}
},
// methed: function () {
// this.$mounted(function () {
// this.obj = {
// a: '456',
// }
// })
// }
})
计算属性的setter
计算属性默认只有getter,不过你也可以提供一个setter
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
//现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。
}
}
}
// ...
总结:与Java里面的get与set类似(几乎一样)
侦听器
使用 watch
选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的
总结:watch适用于复杂操作
Class与Style绑定
绑定HTML Class
<div id="root" :class="{active: isActive,'text-danger':hasError}">
fdsafdsa
</div>
上面的语法表示active
这个class的存在与否取决于propertyisActive
其它一样
let vm = new Vue({
el: '#root',
data: {
isActive:true,
hasError:true
},
// methed: function () {
// this.$mounted(function () {
// this.obj = {
// a: '456',
// }
// })
// }
})
渲染效果
<div id="root" class="active text-danger">
fdsafdsa
</div>
返回对象的计算属性
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
数组语法
我们可以把一个数组传给v-bind:class
,用来应用一个class列表
<div id="root" :class="[active,text_danger]">
fdsafdsa
</div>
data: {
active:'active',
text_danger:'text-danger'
},
渲染为:
<div class="active text-danger"></div>
可以在数组中使用三目运算符
<div id="root" :class="[isActive ? active : '',text_danger]">
fdsafdsa
</div>
用在组件上
先欠着
绑定内联样式
对象语法
直接绑定到一个样式对象并且与之前的绑定class可以同时存在
<div id="root" :class="{active: isActive,'text-danger':hasError}" :style="styleObject">
fdsafdsa
</div>
let vm = new Vue({
el: '#root',
data: {
isActive: true,
hasError: true,
styleObject: {
color: 'red',
fontSize: '13px'
}
}
// methed: function () {
// this.$mounted(function () {
// this.obj = {
// a: '456',
// }
// })
// }
})
数组语法
<div id="root" :class="{active: isActive,'text-danger':hasError}"
:style="[styleObject,overridingStyles]">
fdsafdsa
</div>
自动添加前缀
个人理解就是可以用Vue
绑定一些不标准的或者是浏览器实验性的css
样式不用担心出现问题
多重值
可以为这个style绑定的property提供一个包含多个值的数组,并且从最后一个开始渲染,如果最后一个可以应用就只应用最后一个,如果不可以就往前找可以应用的
<div id="root" :style="{ display: ['block', '-ms-flexbox', '-ms-flexbox'] }">
fdsafdsa
</div>
条件渲染
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
v-if
只可以切换一个元素,如果要切换多个元素用<template>
包裹你要进行一个变换的元素最终结果不会带上<template>
元素
<template v-if="awesome">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-else``v-else-if
懂的都懂就是初级语法
用key管理可利用的元素
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>name</label>
<input placeholder="Enter your email address">
</template>
在上面的代码中切换loginType
不会清除用户已经输入的内容。<input>
不会被替换掉–仅仅是替换了它的placeholder
。
但这样也不问题符合实际需求,所以Vue
为你提供了一种方式来表达这两个元素是完全独立的,只需要添加一个唯一值的key
attribute即可,<label>
元素仍然会被高效地复用,因为它们没有添加 key
attribute。
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>name</label>
<input placeholder="Enter your email address" key="email-input">
</template>
v-show
v-show的元素始终会被渲染在DOM中,它只是简单地切换元素的css property display
注意,
v-show
不支持<template>
元素,也不支持v-else
。
v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的监听器和子组件适当地被销毁和重建。
v-if如果条件为假就什么也不做,当条件为真才开始渲染条件块。
如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
不推荐同时使用
v-if
和v-for
列表渲染
v-for
指令基于一个数组来渲染一个列表
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
v-for
还支持第二个参数即当前项的索引。
<ul id="example-1">
<li v-for="(item, index) in items">
{{ index }} - {{ item.message }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
也可以直接写成item of items
在v-for
里使用对象
same你也可以用v-for
来遍历一个对象的property
<ul id="example-1">
<li v-for="value in object">
{{ value }}
</li>
</ul>
var example1 = new Vue({
el: '#example-1',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
你也提供第二个的参数property名称
<li v-for="(value, name) of object">
{{ name }}: {{ value }}
</li>
title: How to do lists in Vue
author: Jane Doe
publishedAt: 2016-04-10
还可以用第三个参数作为索引:
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
注意两点
- 主键名不可以改变——index,name,value
- 遍历对象时,会按
object.key()
的结果遍历,不能保证结果在不同的Javascript
引擎下都一致
维护状态
官网上bb了一大堆没有怎么听懂,大概意思就是用v-for
的时候加个:key=item.xxx
并且这个key必须是一个唯一的值
不要用对象和数组之类的非基本类型属性作为
v-for
的key
数组更新
变更方法
Vue
对数组的一些更新的方法进行一个侦听,所以它们也会触发更新,其中包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
替换数组
变量方法,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如filter() concat()和slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变量方法时,可以用新数组替换旧数组。
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项
Vue
不能检测数组和对象的变量
显示过滤/排序后的结果
我们可以创建一个计算属性,来返回过滤或排序后的数组
<li v-for="n in evenNumbers">{{ n }}</li>
data: {
numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
evenNumbers: function () {
return this.numbers.filter(function (number) {
return number % 2 === 0
})
}
}
在计算属性中不适用的情况下
<ul v-for="set in sets">
<li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
在v-for里使用值范围
v-for
也可以接受整数。在这种情况下,会把模版重复对应次数
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
将会对这个span标签重复渲染在div内部
在<template>
使用v-for
类似于v-if,我们可以用v-for
的<template>
来渲染一段包含多个元素的内容
自定义指令
全局自定义指令
Vue.directive('指令的名字',{
interted(el){
el 自定义指令绑定的元素
}
})
v-自定义指令的名字
for-example
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
局部自定义指令
在哪注册在哪用
组件与实例都可以注册局部自定义指令
new Vue({
directive:{
自定义指令的名字:{
interted(el){
}
}
}
})
example
new vue({
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
})
组件
- 创建组件
- 注册组件
- 使用组件
局部组件 全局组件的区分就是注册位置不同
全局组件
Vue.component('组件名',{组件的配置项})
然后可以在vue
的实例中使用
example
// 全局组件注册
Vue.component('xixi',{template:'<h1>呵呵</h1>'})
let vm = new Vue({
el:'#app',
data:{
name:'有趣'
}
})
全局组件的嵌套关系
全局组件的嵌套
全局组件没有固定的嵌套关系,嵌套关系由书写方式决定
Vue.component('fa',{template:'#fa'})
Vue.component('son',{template:'#son'})
let vm1 = new Vue({
el:'#app'
})
<div id="app">
<son>
</son>
</div>
<template id="fa">
<div>
这里是父组件
</div>
</template>
<template id="son">
<div>
这里是子组件<fa></fa>
</div>
</template>
局部组件
new Vue({
...
components:{
配置项
},
hehe:{
template:'#xixi'
components:{
....
}
}
})
example
// 局部组件
// 注册
let component = Vue.extend({template:"<h1>这里是局部组件</h1>"})
let vmc = new Vue({
el:'#eye',
data:{
name:'实例二'
},
// 使用
components:{
'haha':component,
}
})
局部组件的嵌套关系
局部组件的嵌套关系在注册的过程中已经确定了
使用过程中 必须要找这种嵌套关系来使用
<div id="app">
<fa>
</fa>
</div>
<template id="fa">
<div>
<son></son>
这里是父组件
</div>
</template>
<template id="son">
<div>
这里是子组件
</div>
</template>
let vm1 = new Vue({
el: '#app',
components: {
fa: {
template: '#fa',
components: {
son:{
template: '#son'
}
}
}
}
})
组件的通信
概括
在组件和实例中自己的数据只有自己可以控制
-
父子通信 props
父组件控制子组件 父组件控制自己的数据变化 将变化后的数据通过props自定义属性传递给子组件
-
子父通信 $emit
子组件控制父组件的数据 父组件控制自己的数据变化,将控制函数通过emit自定义事件传递子组件 供子组件使用
-
兄弟通信
-
状态提升
- 父子与子父结合使用
-
事件总线
-
eventbus
-
创建一个空实例 作为桥梁
-
$on在空实例上注册事件
-
vm.$on( event, callback )
- 参数:
{string | Array<string>} event
(数组只在 2.2.0+ 中支持){Function} callback
- 参数:
-
-
在能获取到空实例的 就可以通过$emit()方法进行触发事件
-
-
-
全局状态管理
-
父子通信
<div id="app">
<fa>
</fa>
</div>
<template id="fa">
<div>
<button>父组件的按钮</button>
<hr>
<son :hehe = 'name' xixi='网易'></son>
</div>
</template>
<template id="son">
<div>
<div class="son" v-show = 'show' >
这里是子组件
</div>
{{hehe}}{{xixi}}
</div>
</template>
Vue.component('fa',{
template:'#fa',
data(){
return {
name:'哈哈'
}
}
})
Vue.component('son',{
template:'#son',
props:['hehe','xixi'],
data(){
return {
show:true
}
}
})
let vm1 = new Vue({
el: '#app',
})
不管是组件还是实例自己的属性只能自己用
props[‘自定义属性名字’] 将父亲的数据传给儿子
- 在组件标签上使用自定义属性
- 在组件内部通过props接收自定义属性
- 接收完后,可以在组件内直接使用
当父组件有一个属性时,我们可以在子组件:wawa = ‘属性名
获得这个属性
子父通信
自定义事件
emit 可以触发绑定在组件身上自定义事件
- 在组件标签绑定一个自定义事件
<son @custom=‘add’>
- 在组件内部 通过emit 触发这个自定事件
在子组件里触发父组件的方法
子父通信通过this.$emit(String eventname,[args])
参数:
{string} eventName
[...args]
触发当前实例上的自定义事件。附加参数都会传给监听器回调
兄弟通信
组件的配置项
当组件的配置项较为简单的时候我们当然可以直接写
Vue.component('xixi',{template:'<hr>'})
但其较为复杂的时候
我们需要用template模版
template模版里面只能放一个根元素并且它不会被渲染
<template id="sha">
<div>
<p v-for='item in 10'>{{item}}</p>
</div>
</template>
<div id="app">
<xixi>
</xixi>
</div>
Vue.component('xixi',{
template:'#sha'
})
let vm = new Vue({
el:'#app',
})
data
<div id="app">
{{name}}
<hehe>
</hehe>
</div>
<template id="tp1">
<div>
<h1>
这里是模版
</h1> {{name}}
</div>
</template>
vm1 = new Vue({
el: '#app',
data: {
name: '这里是实例'
},
components: {
hehe: {
template: '#tp1',
data() {
return {name:'傻'}
}
},
}
})
组件正常情况下无法直接使用实例的数据 只能使用自己的数据
实例里的data是一个对象
组件里的data是一个函数返回一个对象 返回的对象就是我们的数据
组件内也有components 也可以注册组件 形成的组件的嵌套
组件不能在子类中使用
组件配置项与实例配置项的区别
方法 | 实例 | 组件 |
---|---|---|
绑定元素 | el | template |
数据 | data对象 | data函数 |
自定义指令 | directive | directive |
方法 | methods | methods |
other | same | same |
vue-cli
安装
npm install -g @vue/cli
vue -V
出现版本号注意可能你的版本号和我一样比较低大概在2.98左右需要重新安装加一条–force- 新建一个文件
- 进行文件目录 执行
vue create name
- 进入项目目录 执行
npm run serve
cli项目的基本目录
src
源码目录
- main.js 入口文件
xxx.vue
单文件组件
READEME 项目文档
public 公有资源
package.json
项目依赖
node_moudle
依赖包
过滤器
Vue.filter
( id, definition] )
- 参数:
{string} id
{Function} [definition]
函数的第一个参数data就是要过渡的数据
-
全局过渡器
Vue.filter(过渡器名,处理函数)
Vue.filter('hehe',(data,params='.')=>{ // 对数据做处理 let y = (new Date(data)).getFullYear(); let m = (new Date(data)).getMonth()+1; let d = (new Date(data)).getDate(); return `${y}${params}${m}${params}${d}` })
-
局部过渡器 组件或者实例里的配置项
filter:{过渡器名,处理函数}
filters: { 'hehe': (data, params = '.') => { let y = (new Date(data)).getFullYear(); let m = (new Date(data)).getMonth() + 1; let d = (new Date(data)).getDate(); return `${y}${params}${m}${params}${d}` } }
监听watch
watch也是配置项的一种主要功能是监听数据的改变
有两个参数一个是更新前的值,一个是更新后的值
watch监听触发的时候dom
还没有更新所以数据是更改之后的 但是dom
是更改之前的
监听的两种写法
num:(newValue,oldValue)=>{
console.log('num你变了',newValue,oldValue);
},
name(newValue,oldValue){
console.log('name你也变了',newValue,oldValue);
}
以上分别监听了name与num
属性
$refs
vue
里面获得dom
的方法
通过 this.$refs 获取绑定的dom
元素 this 为实例对象或者为组件对象
如果同时有两个相同的ref后面的会代替前面的
vm.$refs
-
类型:
Object
-
只读
-
详细:
一个对象,持有注册过
ref
attribute 的所有 DOM 元素和组件实例。 -
参考:
solt插槽
- 组件内的内容不会被渲染
- slot 相当于开启一段空间来存放标签的内容
- 当组件标签中的元素 要分开展示的时候 用slot属性标志元素 用name给slot标签起名
匿名插槽
<template id='hehe'>
<div class="son">
<slot></slot>
<h3>这里呵呵组件</h3>
</div>
</template>
具名插槽
<div id="app">
<hehe>
<span slot='top'>我想当第一</span>
<p slot="bottom">我想玩</p>
</hehe>
</div>
<template id='hehe'>
<div class="son">
<slot name='top'></slot>
<h3>这里呵呵组件</h3>
<slot name='bottom'></slot>
</div>
</template>
异步请求的解决-$nextTick
[Vue.nextTick( callback, context] )
-
参数:
{Function} [callback]
{Object} [context]
-
用法:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
Vue.component('banner',{
template:'#banner',
data(){
return{
list:[]
}
},
methods: {
// 初始化轮播图
initBanner(){
var mySwiper = new Swiper ('.swiper-container', {
// direction: 'vertical', // 垂直切换选项
loop: true, // 循环模式选项
})
}
},
mounted() {
// 模拟网络请求数据
setTimeout(()=>{
this.list = [
'https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2888261511,2808819884&fm=26&gp=0.jpg',
'https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2164734927,1367682520&fm=26&gp=0.jpg',
'https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2422437459,525040718&fm=26&gp=0.jpg'
]
// 真实dom没有更新
// 上一次数据修改 导致dom更新结束之后在执行内部的回调
this.$nextTick(()=>{
this.initBanner()
})
},1000)
// 组件创建成功过之后会直接执行
/*
网络请求是异步 dom的更新是异步的
初始化的时候 数据没有回来 导致初始化缺少元素 轮播图不能滚动
数据发生改变 先改变的是虚拟dom 在去修改真实dom 这个过程是一个异步的
*/
},
})
let vm=new Vue({
el:"#app",
})
eslint
帮助我们代码更加规范 错误非常多
奇怪报错
7:18 error Extra semicolon semi 多了一个分号。。
Unexpected trailing comma 后面多了个逗号
This relative module was not found: 引包名字出了问题
Block must not be padded by blank lines 多了一条空行
Missing space before opening brace 左括号前需要两个空格
For recursive components, make sure to provide the "name" option
这是直接在DOM中使用,引用时必须小写
“~”表示Web 应用程序根目录,“/”也是表示根目录,“…/”表示当前目录的上一级目录,“./”表示当前目录
早点删了保智商
路由
动态组件-完成切换
动态组件 is 属性 可以指定渲染某一个组件
使用is属性的标签不会被渲染
为了语义化 一般使用vue
提供的component标签
不知道是不是其他人也是这样,反正我这边用其他标签用is属性都好像不太行
路由基本概念
- 监听地址栏的改变 根据改变渲染不同的组件
基本使用
-
下载安装路由
npm install vue-router
-
创建路由表
- 引入
vue 与 vue-router
- 在
vue
中使用vue-router
- 创建路由实例 确定路由与组件的对应关系
- 抛出路由实例
- 引入
-
在min.js注册路由
-
就可以使用两个组件
控制地址拦的改变
router-link的插槽
-
标签内设置custom属性,表自定义router-link。
-
作用域插槽v-slot返回一个对象,对象内的值说明:
-
navigate:一个函数。指定渲染目标标签,须同时设置navigate和custom
-
href:跳转目标的路径。
-
route:目标页面的路由对象。
-
isActive
:路径是否匹配的状态。 -
isExactActive
:路径是否是精准匹配的状态;
<router-link to='/son1' tag="span" active-class="haha">son1</router-link> <-!--相当于一个a标签但其实在dom里面默认被渲染也是被渲染成a标签 tag属性可以改变成渲染元素 active class 可以改变点击的标签的渲染的class类名--> <-! 在router4中已经移除了 tag属性 如果我们写tag会得到一个warning <router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: 一般现在使用 v-slot 来进行一个标签的转换 写法 <router-link to="/about" custom v-slot="{ navigate }"> -->
占位的作用,根据地址拦渲染不同的组件
router-view的插槽
-
作用域插槽
v-slot
返回一个对象,对象内的值说明:
Component
:要渲染的组件route
:解析出的标准化路由对象
-
路由的模式mode hash 和历史
hash 路由 地址拦中有#
history 路由 没有#与正常显示的类似
csdn
简书 博客园 知乎 一周一篇文章
命名视图
app.vue
<router-link to='/namerouter' active-class="haha">命名视图</router-link>
<!-- 命名视图给视图起一个名字 -->
<!-- 占位的作用,根据地址拦渲染不同的组件 -->
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>
在router.js
{
path:'/namerouter',
name:'namerouter',// 通过name 属性为这个路由起个名字
components:{
default:son1,
a:son2,
b:recommend
}
}
命名路由
<router-link :to="{name:'hehe'}" active-class="haha">recommend</router-link>
重定向
{
path:'/',
redirect:'/son1' // 如果路径是/跳转到son1
}
与node的语法基本一致
声明式导航 与编程式导航
声明
编程
window.location.href = 'www.baidu.com'
进行一个组件切换 声明式
通过redirect 直接切换 编程式导航
编程式导航
push
a->b->c->d 每次返回一级 将新路由添加到浏览器访问历史的栈顶
// this.$router.push(path)
// this.$router.push({path:path})
// this.$router.push({name:'hehe'})
replace
a->b->c->d直接回到最初的起点 它并不是将新路由添加到浏览器访问历史的栈顶,而是替换掉当前的路由
路由传参
- 切换的时候传递参数
- 切换完毕 在目标组件接受参数
动态路由
中间的某一个或者某几个是变量
{
path:'/moving/:hehe',
component:moving
},
在目标组件用$router.params
来接收数据
query传参
相当于get 传递参数 数据会出现在地址拦上 缺少安全性 有数据长度限制
在目标组件通过this.$route.query()
进行接收
this.$router.push('/son1?us=123&ps=245')
this.$router.push({path:'/son1',query:{us:123,ps:456}});
params传参
不会出现在地址拦上 没有长度的限制问题
不能与path 一起使用
this.$router.push({name:'son1',params:{us:123,ps:456}})
在目标组件里通过 this.$router.param()
接收
嵌套路由
通过一个children 属性来实现多级路由的嵌套,需要注意的是当这样做的时候我们不能直接通过/xxx
的形式来访问子路由需要在外面的路径下加上子路由的路径
//路由表形成嵌套 子路由路径不加/ /表示为根路径
{
path:'/my',
component:My,
children:[
{
path:'userinfo',
component:UserInfo
},
{
path:'userlogin',
component:UserLogin
}
]
},
2. 在目标组件嵌套一个router-view
html
<template>
<div class="son1">
<h4>
这里是我的组件
</h4>
<!-- 显示的是我的组件下的二级路由 -->
<router-view></router-view>
</div>
</template>
<script>
路由守卫
- 有些页面登录后才能访问 没有登录不允许访问
全局守卫
// 全局前置守卫
router.beforeEach((to,from,next)=>{
const islogin = false
if(to.path==='/singer'){
if(islogin){
next()
}else{
next('/my/userlogin')
}
}else{
next()
}
})
路由独享守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
全局后置守卫
跳转完成后触发
router.afterEach((to, from) => {
// ...
})
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。