Vue学习笔记---------Vue2
1. Hello,world!
- 插值语法: 用 {{ xxx }} 插入一个值 ,该值在data中自定义内容.
<body>
<div id="app">
<h1> 插值语法: </h1>
<h1> {{ info }} </h1>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#app', // 绑定Vue实例 第二种写法: Vue实例.$mount('#app')
data:{
info: 'Hello,World!',
}
})
</script>
- 指令语法: 在标签内使用vue指令解析标签包括标签属性,绑定事件等
<body>
<div id="app">
<h1> 指令语法: </h1>
<a v-bind:href="url">地址</a>
</div>
</body>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
url: 'www.bilibili.com'
}
})
</script>
2. 点击事件
点击事件需要Vue的指令语法: v-on:click=“method” 或是简写 @click=“method”.method是点击执行的具体函数名,该函数在下方Vue实例中的 methods 中定义.在 methods 中 this 指的是Vue实例.
<body>
<div id="root">
<button v-on:click="clickFun">点击事件</button>
</div>
</body>
<script TYPE="text/javascript">
new Vue({
el:'#root',
methods:{
clickFun(){
alert("点击事件!")
}
}
})
</script>
2.1 事件修饰符
- prevent : 阻止默认事件
- stop : 阻止冒泡事件
- once : 事件只触发一次
- capture : 使方法在捕获阶段就执行
- self : 只有当调用该方法时 event.target 是当前元素才会执行方法
- passive : 优先执行事件默认方法,无需等待事件回调函数的执行
2.2 键盘事件
使用指令语法@keyup.xxx 或是 @keydow.xxx 可以绑定键盘事件.
3. 计算属性
计算属性和 data 类似也是属性,但是计算属性在computed中定义.
计算属性有缓存,只有初次读取计算属性时 get() 方法才会被调用,或者计算属性所依赖的值发生变化时 ( 与watch效果类似 ) 才会被调用,并不是每次读取计算属性的值使都会进行计算.
<script TYPE="text/javascript">
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName(){
return this.firstName + '-' + this.lastName
}
}
})
</script>
4. 监视属性
使用 watch 来监视目标, handler 函数当被监视的值发生改变时被调用
<script TYPE="text/javascript">
new Vue({
el:'#root',
data:{
isWin: false,
},
watch:{
isWin(newValue,oldValue){
console.log(newValue,oldValue)
}
}
})
</script>
4.1 深度监视
通过deep配置是否开启深度监视, watch 默认是不能监视被监视对象内部值的变化,通过immediate配置让被监视属性的执行体直接执行一次.
deep:true,
5. 条件渲染
使用指令语法 v-if 或 v-show 可以条件的渲染指定元素,其区别在于前者为 false 时结构中也不存在,后者在结构中一直存在,只是显示与不显示的区别.所以在需要频繁切换显示与否的情况下用v-show更合适.
<body>
<div id="root">
<div v-show="isShow">能看到我吗?</div>
<button @click="changeShow">点我试试</button>
</div>
</body>
<body>
<div id="root">
<div v-if="isShow">能看到我吗?</div>
<button @click="changeShow">点我试试</button>
</div>
</body>
6. 循环指令
可以使用指令语法 v-for 循环遍历元素.
<body>
<div id="root">
<ul>
<li v-for="p in person">
姓名: {{p.name}};
年龄: {{p.age}};
</li>
</ul>
</div>
</body>
<script TYPE="text/javascript">
new Vue({
el:'#root',
data:{
person:[
{name:'张三',age:18},
{name:'李四',age:19}
]
},
})
</script>
建议在使用 v-for 遍历时同时使用 key 以保证被遍历元素的唯一性.
<body>
<div id="root">
<ul>
<li v-for="(p,index) in person" :key="index">
姓名: {{p.name}};
年龄: {{p.age}};
</li>
</ul>
</div>
</body>
<script TYPE="text/javascript">
new Vue({
el:'#root',
data:{
person:[
{name:'张三',age:18},
{name:'李四',age:19}
]
},
})
</script>
7. Vue的生命周期
生命周期又叫生命周期回调函数,就是钩子函数,钩子函数名是固定的,调用时机也是固定的.只有函数体可以自定义,然后会在固定时间点被执行.
- beforeCreate 此时未进行数据代理,无法通过vue实例获取data中的内容.
- Created 此时数据代理,数据监测已完成
- beforeMount 此时页面呈现的是虚拟DOM,此时对DOM的所有操作最终都不会生效.
- mounted 此时已经编译成为了真实DOM,初始化过程结束.
- beforeUpdate 当数据更新时会被调用,此时数据是更新后的数据,但未被渲染,即页面与数据不同步,页面是旧页面.
- Updated 数据已经更新,且页面也是新的.
- beforeDestroy data,method等都还存在,即将销毁.但是无法对数据进行修改.
- destroyed vue实例被销毁
8. 组件化编程
组件:实现页面局部功能的代码和资源的集合.提高代码的复用率.
使用组件的三个步骤:
- 创建组件 : 使用Vue.extend()创建组件,为了保证组件的复用,组件中data必须写成函数式,使用template配置组件页面结构.
- 注册组件 : 局部注册: new Vue实例时使用components进行注册;全局注册: Vue.component(‘组件名’,组件).
- 使用组件 : 通过组件名标签使用.
// 1. 创建组件
<script TYPE="text/javascript">
const people = Vue.extend({
template:`
<div>
<h1>你好,{{name}}!</h1>
</div>
`,
data(){
return{
name:'王也'
}
}
})
</script>
// 2. 注册组件
<script TYPE="text/javascript">
new Vue({
el:'#root',
// 键值对:key:组件名,value:创建的组件变量名
components:{
people,people
}
})
</script>
// 3. 使用组件
<body>
<div id="root">
<people></people>
</div>
</body>
9. Vue脚手架
- 编写vue组件,在components包下创建 组件名.vue 文件.
<template>
<div>
<h1>武当{{name}},拜见老天师!</h1>
</div>
</template>
<script>
export default {
name: 'WuDangPeople',
data(){
return{
name:'王也'
}
}
}
</script>
- 注册并使用组件,在src目录下创建 App.vue 文件.App组件统管其他所有组件.
<template>
<div>
<wu-dang-people></wu-dang-people>
</div>
</template>
<script>
import WuDangPeople from './components/People'
export default {
name: 'App',
components: {
WuDangPeople
}
}
</script>
- 创建Vue实例,并绑定App容器,在src目录下创建 main.js 文件.
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
render: h => h(App),
})
- 编写主页面,在主页面放置APP组件 ( App组件内部嵌套使用着其他组件 ).在public目录下创建 index.html 文件.
<!DOCTYPE html>
<html lang="">
<head>
</head>
<body>
<div id="app"></div>
</body>
</html>
10. 组件间传递值
10.1 props
props可以让组件接收从外部传进来的值.
- 在接收值的组件内部配置props
<template>
<div>
<h1>{{dept}}{{name}},拜见老天师!</h1> <br/>
</div>
</template>
<script>
export default {
name: "People",
props:{
dept:{
type:String,
required: true
},
name:{
type:String,
required: true
},
},
data(){
return{
newAge:this.age
}
},
}
</script>
- 在调用组件时进行传值
<template>
<div>
<People dept="武当" name="王也" :age="20"></People>
<People dept="哪都通" name="张楚岚" :age="23"></People>
</div>
</template>
注意: vue底层会监视通过props传进组件的值,如果进行修改就会发出警告.
10.2 组件自定义事件
10.2.1 通过 ref 绑定
通过 ref 绑定组件后,可以通过 $refs 获取到这个组件.当 People 这个组件的 ’ getName ’ 事件被触发时,就会调用 showName()方法.
<template>
<div>
<People ref="people"></People>
</div>
</template>
<script>
import People from './components/People'
export default {
name: "App",
components:{People},
methods:{
showName(name){
alert(name)
}
},
mounted() {
this.$refs.people.$on('getName',this.showName)
},
}
</script>
在组件内通过 $emit 可以触发事件.同时可以将值传递出去.
<template>
<div>
<h1>{{dept}}{{name}},拜见老天师!</h1> <br/>
<button @click="btn">who are you?</button>
</div>
</template>
<script>
export default {
name: "WuDangPeople",
data(){
return{
dept: '武当',
name: '王也'
}
},
methods:{
btn(){
this.$emit('getName',this.name)
}
}
}
</script>
10.2.2 通过v-on 绑定
<template>
<div>
// 当'getName'事件被触发时,就会调用 showName 方法.
<People @getName="showName"></People>
</div>
</template>
<script>
import People from './components/People'
export default {
name: "App",
components:{People},
methods:{
showName(name){
alert(name)
}
},
}
</script>
通过 $off 可以解绑事件
11. mixin
通过配置mixin可以提取多个组件中相同的配置项,在src目录下创建 xxx.js 文件.编写可提取的公共配置项.
export const mixin = {
methods:{
show(){
alert("罗天大醮")
}
}
}
在组件内配置mixin配置项引入并使用共同的配置.( show方法在mixin.js文件中定义,组件内引入后就可以使用 )
<template>
<div>
<button @click="show">点我了解比赛名称</button>
</div>
</template>
<script>
import {mixin} from '../mixin'
export default {
name: "People",
mixins:[mixin]
}
</script>
12. 全局事件总线
除了在父子组件中传值,还可以通过全局事件总线在同级组件间传值.
在 new Vue 实例时,给Vue实例的原型对象添加 b u s , 这个 bus ,这个 bus,这个bus全局可见,所有组件都可以找到,那么就可以通过这个$bus在多个组件中建立联系,互相传值.
- 在 main.js 文件中创建 Vue 实例的时候利用钩子 beforeCreate 创建全局事件总线.
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
// 创建全局事件总线
Vue.prototype.$bus = this
}
})
- 在需要接收值的组件里绑定自定义事件( 将接收值的组件与 $bus 绑定 ),记得在组件销毁前解绑时间.
<script>
export default {
name: "AnotherComponent",
methods:{
},
mounted() {
this.$bus.$on("giveName",(name)=>{
alert('我在Another组件里,Another组件已经收到值了,名字是: ' + name)
})
},
beforeDestroy() {
this.$bus.$off('giveName')
}
}
</script>
- 在需要传值的组件里设置事件触发,并传值.
<template>
<div>
<button @click="give">我是People组件的里的按钮,点我给Another组件传值</button>
</div>
</template>
<script>
export default {
name: "WuDangPeople",
data(){
return{
name: '王也'
}
},
methods:{
give(){
this.$bus.$emit('giveName',this.name)
}
}
}
</script>
这样就通过Vue实例的原型对象身上的$bus实现了任意组件间的通信.
13. 插槽
13.1 默认插槽
在需要插入不确定元素的地方保留一个占位 <slot></slot>
,当有需要填充的元素出现时,就会插入该插槽.
<template>
<div>
<h3>我喜欢的游戏</h3>
<slot>当没有元素需要插入本插槽时,显示本默认内容</slot> // 提前占位,设置插槽位置
</div>
</template>
<script>
export default {
name: "MyGames"
}
</script>
在使用组件时,组件内部出现需要插入的元素就会找到slot标签位置并插入.
<template>
<div>
<my-games>
// 该元素即为需要插入的元素,vue会自动找到插槽位置插入该元素.
<li v-for="game in games" :key="game"> {{game}} </li>
</my-games>
</div>
</template>
<script>
import MyGames from './components/Games'
export default {
name: "App",
components: {MyGames},
data(){
return{
games:['盗贼之海','命运2','Apex','Valorant','英雄联盟','WallPaper']
}
}
}
</script>
13.2 具名插槽
当出现多个插槽位置的时候,给插槽配置name属性,在插入的的时候可以寻找对应属性的插槽插入.
<template>
<div>
<my-games>
<h1 slot="first">我就是个臭打游戏的</h1>
<li slot="second" v-for="game in games" :key="game"> {{game}} </li>
</my-games>
</div>
<template>
<div>
<h3>我喜欢的游戏</h3>
<slot name="first">我是第一个插槽</slot>
<slot name="second">我是第二个插槽</slot>
</div>
</template>
13.3 作用域插槽
当插槽的使用者需要用到插槽所在的组件内的数据时,可以通过配置 scope ,将数据从插槽所在的组件传到插槽使用者手里. scope属性拿到的是一个对象,其包含定义插槽时标签体内配置的属性.
<template>
<div>
<h3>我喜欢的游戏</h3>
<slot :games="games">我是第二个插槽</slot>
</div>
</template>
<script>
export default {
name: "MyGames",
data(){
return{
games:['盗贼之海','命运2','Apex','Valorant','英雄联盟','WallPaper']
}
}
}
</script>
<template>
<div>
<my-games>
// gamesInfo拿到的是一个对象,内容是 games.
<template scope="gamesInfo">
<li v-for="game in gamesInfo.games" :key="game">{{game}}</li>
</template>
</my-games>
</div>
</template>
<script>
import MyGames from './components/Games'
export default {
name: "App",
components: {MyGames},
}
</script>
14. 路由
14.1 简单路由
在单页面应用中,根据Vue Router的配置,实现多组件切换展示,而不用刷新或打开新页面.
- 编写路由目标组件( 一般把通过路由展示的组件放在src目录下的pages包下 )
<template>
<div>
<h1>我是斩月,你的斩魄刀,黑崎一护!</h1>
</div>
</template>
<template>
<div>
<h1>我是冰轮丸,你的斩魄刀,日番谷冬狮郎!</h1>
</div>
</template>
- 在 src 下创建 router 包,包中创建 index.js 文件,编写路由配置.
- 引入 VueRouter 插件,并且 Vue.use 这个插件.
- 引入路由目标组件
- new VueRouter: 配置routes,配置路径和目标组件.
import VueRouter from "vue-router";
import Vue from "vue";
import Black from "@/components/Black";
import Ice from "@/components/Ice";
Vue.use(VueRouter)
export default new VueRouter({
routes:[
{
path:'/black',
component:Black
},
{
path:'/ice',
component:Ice
}
]
})
- 在 main.js 文件中引入路由插件并且Vue.use ,在Vue实例中配置route.
import Vue from 'vue'
import App from './App'
import VueRouter from "vue-router";
import router from './router/index'
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
el:'#app',
render: h => h(App),
router
})
- 在 App.vue 文件中,使用
<router-link to="/black"> xxx </router-link>
编写路由起点,以及使用<router-view></router-view>
占位路由目标组件的展示布局.路由布标组件将在<router-view></router-view>
处展示.
注意 : 在使用<router-link>
时,可以配置replace属性,以改变浏览器的历史记录模式,replace模式下,在路由新的组件时,浏览器添加新的历史记录的同时会干掉上一个记录,也就是在路由的过程中始终保持只有一条历史记录.
<template>
<div>
<div>
<router-link replace to="/black">黑崎一护</router-link>
<router-link replace to="/ice">日番谷冬狮郎</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
14.2 嵌套路由
- 在router路径下的index.js文件中配置多级路由.在父级路由配置下配置children,在其中嵌套子级路由.
export default new VueRouter({
routes:[
{
path:'/black',
component:Black
},
{
path:'/ice',
component:Ice,
children:[
{
path:'super',
component:Super
}
]
}
]
})
- 在父级组件中编写子级组件的路由布局.依旧是
<router-link>
和<router-view>
.
注意: 在多级路由中,父级组件中使用<router-link>
链接子组件时, to 属性的的路径要带上父级路径.
<template>
<div>
<h1>我是冰轮丸,你的斩魄刀,日番谷冬狮郎!</h1>
<div>
<router-link to="/ice/super">卍解</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
- 编写子级组件.
<template>
<div>
<h1>端坐于霜天吧,冰轮丸!</h1>
</div>
</template>
14.3 路由传参
14.3.1 通过query传参
- 在使用
<router-link>
的时候,通过配置 query 可以传递参数.
<template>
<div>
<h1>护廷十三队</h1>
<ul>
<li v-for="n in name" :key="n.id">
<router-link :to="{
path:'/number',
query:{
id:n.id,
name:n.name,
sword:n.sword
}
}">{{n.name}}</router-link>
</li>
</ul>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Title",
data(){
return{
name:[
{
id:'六番队队长',
name:'朽木白哉',
sword:'千本樱'
},
{
id:'十番队队长',
name:'日番谷冬狮郎',
sword:'冰轮丸'
},
{
id:'一番队总队长',
name:'山本元柳斋重国',
sword:'流刃若火'
}
]
}
}
}
</script>
- 在路由目标组件内可以通过 $route.query.xxx 来接收参数.
<template>
<ul>
<li>姓名:{{$route.query.name}}</li>
<li>职称:{{$route.query.id}}</li>
<li>斩魄刀:{{$route.query.sword}}</li>
</ul>
</template>
也可以通过params传参,写法和query大致一样
14.3.2 通过props传
- 传递还是一样的写法,
<router-link>
中配置path和query,只不过多了一步就是在路由配置文件中配置props.
export default new VueRouter({
routes:[
{
name:'number',
path:'/number',
component:Detail,
props($route){
return{
id:$route.query.id,
name:$route.query.name,
sword:$route.query.sword
}
}
}
]
})
- 接收时即可直接接收,不用在组件中使用$route.query.xxx了.
<template>
<ul>
<li>姓名:{{name}}</li>
<li>职称:{{id}}</li>
<li>斩魄刀:{{sword}}</li>
</ul>
</template>
<script>
export default {
name: "detail",
props:['id','name','sword']
}
</script>
14.4 命名路由
- 可以再路由配置文件中给路由起个名字
export default new VueRouter({
routes:[
{
name:'number',
path:'/number',
component:Detail
}
]
})
2.在调用路由的时候就可以不用写请求路径,直接写名字,在多级路由中可以简化代码.
<router-link :to="{
name:'number',
query:{
id:n.id,
name:n.name,
sword:n.sword
}
}">
{{n.name}}
</router-link>
14.5 编程式路由
- 写成函数去触发路由, $router.push .
<button @click="banKai(n)">卍解</button>
<script>
export default {
name: "Title",
methods:{
banKai(n){
this.$router.push({
name:'number',
query:{
banKai:n.banKai,
}
})
}
}
}
</script>
14.6 两个钩子函数
-
activated 被路由的组件激活时触发,
-
Deactivated 离开该组件时失活,
与
<keep-alive>
标签配合使用.
14.7 路由守卫
-
全局前置: 在路由触发时会调用,路由切换之前会调用.
Router.beforeEach((to,from,next) => { xxxxx; xxx; })
- to:目标组件;
- from:出发点;
- next: 拦截放行;
可以对next进行条件控制已达到权限拦截的效果.
- 全局后置: 在路由触发时会调用,路由切换之后会调用.
Router.afterEach((to,from) => {
xxxxx;
xxx;
})
- 独享路由守卫: 只控制单个路由组件的守卫
在路由配置文件中,单个路由组件配置对象中,配置beforeEnter
,就可以实现对单个路由组件的路由拦截控制.
routes:[
{
name:'number',
path:'/number',
component:Detail,
props($route){
return{
id:$route.query.id,
name:$route.query.name,
sword:$route.query.sword,
banKai:$route.query.banKai
}
},
beforeEnter:(to,from,next) => {
next()
}
}
]
- **组件内路由:**通过路由规则切换的组件内部的路由守卫.
beforeRouteEnter
: 通过路由规则进入该组件时被调用.beforeRouteLeave:
通过路由规则离开该组件时被调用.