vue的学习有一阵子了,打算在这新的一年花一点时间去沉淀一下。本篇文章主要是围绕vue2.0官方文档进行简化和总结,如果读者是零基础,请阅读官方文档~
(2022/1/3… 持续更新
https://cn.vuejs.org/v2/guide
Vue主要采用了MVVM的设计模式,是原来的MVC设计模式的一个升级。以前传统的MVC,是将后端数据手动渲染到前端页面,将业务逻辑和前端渲染彻底分开。
MVVM本质上就是MVC 的改进版,指的是(Model,View,ViewModel),三者相互协调。
当数据源发生变化的时候,ViewMode就会监听到,负责自动渲染到视图层。
当表单数据发生变化时,也会被监听到,并且自动同步到Model的数据源之中。
Vue有很多模板语法和指令
1. v-text
v-text 作为属性可以覆盖原来标签的内容
<div id='app'>
<p v-text='message'>原来的内容p>
div>
<script type='text/javascript'>
var app = new Vue({
el: '#app',
data: {
message: 'Hello! Vue!'
}
});
script>
2. 插值表达式
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
<div id='app'>
<p>{{message}}p>
div>
Mustache 标签将会被替代为对应数据对象上 msg property 的值。无论何时,绑定的数据对象上 msg property 发生了改变,插值处的内容都会更新。
比如此处’Hello! Vue!’
用js代码修改为
通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:
<span v-once>这个将不会改变: {{ msg }}span>
3.v-html
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:
<div id='app' >
<p>{{message}}p>
div>
<script type='text/javascript'>
var app = new Vue({
el: '#app',
data: {
message: '你们好
'
}
});
script>
<div id='app'>
<p v-html='message'>p>
div>
<script type='text/javascript'>
var app = new Vue({
el: '#app',
data: {
message: '你们好
'
}
});
script>
要注意绝不要对用户提供的内容使用插值,防止xss攻击。
v-if 指令用于条件性地渲染一块内容。
也可以用 v-else 添加一个“else 块”:
<h1 v-if="awesome">Vue is awesome!h1>
<h1 v-else>Oh no h1>
v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用
<div v-if="type === 'A'">
A
div>
<div v-else-if="type === 'B'">
B
div>
<div v-else-if="type === 'C'">
C
div>
<div v-else>
Not A/B/C
div>
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。比如切换的时候会复用原有的input输入内容。
key attribute
即可:<template v-if="loginType === 'username'">
<label>Usernamelabel>
<input placeholder="Enter your username" key="username-input">
template>
<template v-else>
<label>Emaillabel>
<input placeholder="Enter your email address" key="email-input">
template>
<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' } ] }})
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} li>ul>
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} li>ul><script>new Vue({ el: '#v-for-object', data: { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } }})script>
因为vue的更新渲染策略,是采用就地更新的策略,而不是重新渲染,因此对于循环渲染,需要给vue一个提示key,以便它能跟踪每个节点,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:
key 最好是能唯一表示每一条数据的数字 如id
插值表达式不能直接应用到属性中,如。
<div id='app'> <p title="{{message}}">标题p> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { message: '这是一个标题' } }); script>
<div id='app'> <p v-bind:title="message">标题p> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { message: '这是一个标题' } }); script>
可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
<body> <div id='app'> <p>{{counter}}p> <button v-on:click="counter+=1">+1button> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, } }); script>body>
注意: 上面的代码在v-on:click里执行了一个js代码,也就是说在双引号里的代码是js代码,所以我们也能调用方法
在Vue构造实例里,增加methods,并且用v-on:绑定这个事件
<div id='app'> <p>{{counter}}p> <button v-on:click="show">+1button> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, }, methods: { show: function () { alert('123'); } }, }); script>
有时候我们需要在内联语句处理器中访问原始的 DOM 事件event,只需要传参即可~
对于某些事件,我们需要进行一些限制,如:阻止冒泡,限制原有行为。
我们通常用js来操作原生的dom事件
如下:防止表单提交自动刷新页面
<div id='app'> <button v-on:click="counter+=1">+1button> <form v-on:submit="sb"> <input v-model="counter">input> <input type="submit">input> form> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, }, methods: { show: function (e) { console.log(e); }, sb: function (event) { event.preventDefault(); alert("submit successful!"); } }, }); script>
<div id='app'> <button v-on:click="counter+=1">+1button> <form v-on:submit.prevent='sb'> <input v-model="counter">input> <input type="submit" v-on:click.prevent='sb'>input> form> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, }, methods: { show: function (e) { console.log(e); }, sb: function () { alert("submit successful!"); } }, }); script>
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop
.prevent
.capture
.self
.once
.passive
<a v-on:click.stop="doThis">a><form v-on:submit.prevent="onSubmit">form><a v-on:click.stop.prevent="doThat">a><form v-on:submit.prevent>form><div v-on:click.capture="doThis">...div><div v-on:click.self="doThat">...div>
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
如下列代码,按esc可以清空文本,按enter可以提交
<div id='app'> <button v-on:click="counter+=1">+1button> <form v-on:keyup.enter='sb'> <input v-model="counter" v-on:keyup.esc='counter=0'>input> <input type="submit" v-on:click.prevent='sb'>input> form> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, }, methods: { show: function (e) { console.log(e); }, sb: function () { alert("submit successful2!"); } }, }); script>
<script type='text/javascript'> var app = new Vue({ el: '#app', data: { counter: 0, }, methods: { show: function () { alert('123'); }, //在es6的语法中,方法可以省去function show2() { alert('666') } }, }); script>
Vue.js 可以用 v-model 指令在表单 、
及
创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
代码非常好理解,直接看代码即可~
<div id='app'> <h3>input 输入文本 展示h3> <p>{{data1}}p> <input v-model="data1">input> <br> <h3>input 复选选框 展示h3> <input type="checkbox" id="checkbox" v-model="checked"> <label for="checkbox">{{ checked }}label> <br> <div>多个复选框绑定同一个数组div> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jacklabel> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">Johnlabel> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mikelabel> <br> <span>Checked names: {{ checkedNames }}span> <br> <div>单选按钮div> <input type="radio" id="one" value="One" v-model="picked"> <label for="one">Onelabel> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Twolabel> <br> <span>Picked: {{ picked }}span> <h3>选择框selecth3> <select v-model='selected'> <option disabled value=''>请选择option> <option>Aoption> <option>Boption> <option>Coption> select> <div>Your Selected : {{selected}}div> <h3>多选框 selecth3> <select v-model='selected' multiple style="width: 50px"> <option>Aoption> <option>Boption> <option>Coption> select> <div>Your Selected : {{selected}}div> <h3>动态渲染 selecth3> <select v-model='selected' multiple style="width: 50px"> <option v-for='item in checkedNames' value='item'>{{item}}option> select> <div>Your Selected : {{selected}}div> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { data1: 0, checked: false, checkedNames: [], picked: '', selected: '', }, }); script>
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:
<input v-model.lazy="msg">
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
这通常很有用,因为即使在 type=“number” 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。
<input v-model.number="age" type="number">
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
<input v-model.trim="msg">
介绍
计算属性可以类比有返回值的函数,但是更加高效,因为会进行缓存,当且仅当能够影响结果的变量,发生变化的时候才会去重新计算。
注意
计算属性虽然长得像方法,但是无法进行传参。
<div id='app'> <button @click='f(getPower)'>getbutton> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { cnt: 2, }, methods: { f(a) { alert(a); } }, computed: { getPower() { return this.cnt * this.cnt; } } });
在watch里面
格式为
侦听的数据和计算属性 : function(){}
<div id='app'> <div> <input v-model.lazy="firstName">input> <input v-model.lazy="lastName">input> div> <p>your fullName is {{fullName}}p> <div>{{get}}div> div> <script type='text/javascript'> var app = new Vue({ el: '#app', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar', f: 1, }, methods: { }, computed: { get() { return this.f + 1; } }, watch: { firstName(val, oldVal) { this.fullName = val + ' ' + this.lastName; console.log(val + "<= " + oldVal); }, get(val, oldVal) { console.log(val + ' ' + oldVal); } } }); script>
vue create 项目名
assets 文件夹: 存放项目中用到的静态资源文件,css 样式表
components 文件夹: 封装的可复用组件放到此目录
main.js 项目入口文件,项目的运行要先执行main.js
里面的资源不会被webpack打包压缩,也是存储静态文件。
在工程化的项目中,vue通过main.js 把 App.vue 渲染到index.html 的指定区域中,main.js文件非常关键。
// 导入vue包 得到vue构造函数
import Vue from 'vue'
// 导入vue.vue 组件 把app.vue 模板结构渲染到html页面之中
import App from './App.vue'
Vue.config.productionTip = false
// 创建vue实例对象 以下两个写法都可以
new Vue({
// render 函数指定组件渲染到html页面之中 App 就是根组件
render: h => h(App),
}).$mount('#app')
new Vue({
el: '#app',
// render 函数指定组件渲染到html页面之中
render: h => h(App),
})
上文的$mount是内置函数,代表挂载的意思,举例:
<div id='app'>
{{username}}
div>
<script type="text/javascript">
const vm = new Vue({
// el:'#app',
data: {
username: 'fxw'
},
});
vm.$mount('#app');
script>
每个.vue组件由三部分组成
template -> 组件的模板结构
script 组件的js代码
style 组件的样式
固定写法
<template>
<div>
{{ username }}
div>
template>
<script>
//默认导出
export default {
//data 数据源
data(){
return{
username:'fxw',
}
},
};
script>
<style>
style>
用默认导出来代替之前的构造函数,data不能是一个对象,而是返回一个独立的函数,让其每个组件独立。
在组件中,this表示当前组件的实例对象
<style lang="less">
style>
App根组件
通过components注册的组件时私有子组件,如果某个组件使用的非常频繁,可以使用全局组件。
只需要注册一次,其他组件都能直接使用。
方法:在Vue 的main.js入口文件之中,通过Vue.component()的内置方法 可以注册全局组件。注意,这是vue的构造函数生成的实例的内置方法。
// 导入vue包 得到vue构造函数
import Vue from 'vue'
// 导入vue.vue 组件 把app.vue 模板结构渲染到html页面之中
import App from './App.vue'
import Test from './Test.vue'
import Count from '@/components/Count.vue'
Vue.config.productionTip = false
Vue.component('MyCount', Count) // 全局注册组件
var vue = new Vue({
// render 函数指定组件渲染到html页面之中
render: h => h(App),
}).$mount('#app')
vue create 项目名
assets 文件夹: 存放项目中用到的静态资源文件,css 样式表
components 文件夹: 封装的可复用组件放到此目录
main.js 项目入口文件,项目的运行要先执行main.js
里面的资源不会被webpack打包压缩,也是存储静态文件。
在工程化的项目中,vue通过main.js 把 App.vue 渲染到index.html 的指定区域中,main.js文件非常关键。
// 导入vue包 得到vue构造函数
import Vue from 'vue'
// 导入vue.vue 组件 把app.vue 模板结构渲染到html页面之中
import App from './App.vue'
Vue.config.productionTip = false
// 创建vue实例对象 以下两个写法都可以
new Vue({
// render 函数指定组件渲染到html页面之中 App 就是根组件
render: h => h(App),
}).$mount('#app')
new Vue({
el: '#app',
// render 函数指定组件渲染到html页面之中
render: h => h(App),
})
上文的$mount是内置函数,代表挂载的意思,举例:
<div id='app'>
{{username}}
div>
<script type="text/javascript">
const vm = new Vue({
// el:'#app',
data: {
username: 'fxw'
},
});
vm.$mount('#app');
script>
每个.vue组件由三部分组成
template -> 组件的模板结构
script 组件的js代码
style 组件的样式
固定写法
<template>
<div>
{{ username }}
div>
template>
<script>
//默认导出
export default {
//data 数据源
data(){
return{
username:'fxw',
}
},
};
script>
<style>
style>
用默认导出来代替之前的构造函数,data不能是一个对象,而是返回一个独立的函数,让其每个组件独立。
在组件中,this表示当前组件的实例对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fYOZval1-1644509154803)(Vue总结.assets/image-20220119222400294.png)]
template里只能有且只有一个div
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ingykzoY-1644509154804)(Vue总结.assets/image-20220119222756351.png)]
<style lang="less">
style>
App根组件
通过components注册的组件时私有子组件,如果某个组件使用的非常频繁,可以使用全局组件。
只需要注册一次,其他组件都能直接使用。
方法:在Vue 的main.js入口文件之中,通过Vue.component()的内置方法 可以注册全局组件。注意,这是vue的构造函数生成的实例的内置方法.每个组件都共享.
// 导入vue包 得到vue构造函数
import Vue from 'vue'
// 导入vue.vue 组件 把app.vue 模板结构渲染到html页面之中
import App from './App.vue'
import Test from './Test.vue'
import Count from '@/components/Count.vue'
Vue.config.productionTip = false
Vue.component('MyCount', Count) // 全局注册组件
var vue = new Vue({
// render 函数指定组件渲染到html页面之中
render: h => h(App),
}).$mount('#app')
通过注册props自定义属性,在使用模板的过程中可以使用,实现父向子传值。
export default {
props: ["init"],
data() {
return {
cnt: 0,
};
},
};
props是只读的,不建议直接修改props,而是用来传值,如下我将其初始值设为参数。
因为所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zozo29Gw-1644509154804)(Vue总结.assets/image-20220124163047447.png)]
props参数的默认值 default,让props不指向数组,指向一个对象。
我们先取消原参数传递
<MyCount></MyCount>
让修改组件中props
export default { props: { init: { default: 0, }, }, data() { return { cnt: this.init, }; },};
可以发现right组件的初始值为0了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HqvAvqlf-1644509154805)(Vue总结.assets/image-20220124164109490.png)]
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props
中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } }})
给某个组件增加h3 { color: red;}
发现是全局的,因为把样式都统一的放到一个页面下了,会影响。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-neI3j9Wl-1644509154805)(Vue总结.assets/image-20220124164754233.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5IbJVDB-1644509154806)(Vue总结.assets/image-20220124164830478.png)]
Left 组件
原理是给每个标签增加独一无二的属性,并且css修改对应选择器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VqFZPM0M-1644509154806)(Vue总结.assets/image-20220124170714144.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6gLQPC15-1644509154807)(C:\Users\37802\AppData\Roaming\Typora\typora-user-images\image-20220124171501771.png)]
需求:假设left,right都使用了cnt,我们只想修改left下的元素。当是right也用了cnt组件,我们不能直接使用全局的css。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ToXuCLDx-1644509154807)(Vue总结.assets/image-20220124171642823.png)]
</script><style lang="less" scoped>.left-container { padding: 0 20px 20px; background-color: orange; min-height: 250px; flex: 1;}h3 { color: red;}/deep/ h5 { color: red;}</style>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hoZ7aLB-1644509154808)(C:\Users\37802\AppData\Roaming\Typora\typora-user-images\image-20220124173328416.png)]
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OnpV6343-1644509154809)(Vue总结.assets/image-20220124182007357.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MsGFkmV-1644509154809)(Vue总结.assets/image-20220124181941327.png)]
自定义属性
子组件把自己的数据,传给父组件。
思路
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaDIFSnI-1644509154810)(Vue总结.assets/image-20220125005250106.png)]
this.$emit('numchange',参数);
<Right @numchange="go"></Right>
go(传过来的参数) { this.countFromSon = val;},
中间用一个js文件从当 EventBus,原理也是利用自定义事件的传值和监听。
用 $on(eventName) 监听事件使用 $emit(eventName) 触发事件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZVtQIIH2-1644509154810)(Vue总结.assets/image-20220125010013103.png)]
import Vue from "vue";export default new Vue();
import bus from "./eventBus.js";bus.$emit("share", this.count);
created(){ bus.$on('share',val=>this.right=val)},
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06FiAIDc-1644509154811)(Vue总结.assets/image-20220125011044044.png)]
用ref引用来操作dom元素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TQ2huLAB-1644509154811)(Vue总结.assets/image-20220127120549041.png)]
步骤
给 标签/Vue组件 元素增加属性 ref
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfD18Fzv-1644509154812)(Vue总结.assets/image-20220127122510905.png)]
调用即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yq2kDWcd-1644509154813)(Vue总结.assets/image-20220127122545979.png)]
父节点可以直接获取子节组件实例化,并且也能获取标签的dom引用。
如果我们渲染某个元素就立刻去调用其的引用,就会报错。
原因是vue是异步进行渲染的,组件来不及更新就被调用了,自然就报错了。
需要用nextTick,会等待dom重新渲染完毕的时候就会重新执行。
<input v-if="v" @blur="v = !v" ref="inputRef" /> <button v-else @click="show()">点我展示输入框</button> show() { this.v = !this.v; this.$nextTick(() => this.$refs.inputRef.focus()); },
函数 | 说明 |
---|---|
array.forEach(function(currentValue, index, arr), thisValue) | 不支持continue和every |
array.some(function(currentValue,index,arr),thisValue) | 找到是否存在一个,返回布尔值,有一项是true,就放回true |
array.every(function(currentValue,index,arr), thisValue) | 检测每个元素是否都符合,返回布尔值,如果每项都是true 就返回true |
array.filter(function(currentValue,index,arr), thisValue) | 返回满足条件的,创建新的数组,不改变原数组 |
array.reduce(function(total, currentValue, currentIndex, arr), initialValue) | 进行累加,initialValue可选,作为初始值,total为累加变量和最后的返回值 |
Vue 提供一个内置的组件component 实现组件的动态渲染
在一个多标签的界面中使用 is attribute 来切换不同的组件:
<template> <div class="app-container"> <h1>App 根组件</h1> <br /> <div> <button @click="comName = 'Left'">Left</button> <button @click="comName = 'Right'">Right</button> </div> <div class="box"> <component :is="comName"></component> </div> </div></template><script>// 1. 导入需要使用的 .vue 组件import Left from "@/components/Left.vue";import Right from "@/components/Right.vue";export default { data() { return { comName: Left, }; }, // 2. 注册组件 components: { Left: Left, Right, },};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rV7hV3Ix-1644509154813)(Vue总结.assets/image-20220203162526415.png)]
但是在切换组件的时候,之前的组件都会
很明显,这样就无法保存之前组件的状态。
我们可以用一个
元素将其动态组件包裹起来。
keep-alive 里面的component 都会被动态的缓存下来,
被缓存的组件状态为 inactive
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1VI8s8m3-1644509154813)(Vue总结.assets/image-20220203163958607.png)]
注意这个
要求被切换到的组件都有自己的名字,不论是通过组件的 name
选项还是局部/全局注册。
通常,我们在声明注册组件的时候没有指定name名称,则组件的名称默认就是注册时候的名称
自定义name在include的时候要用name名称.
<script>export default { name:'Myleft',}</script>
原来在keep-alive里面的所有组件都会被缓存,但是有的时候不需要,因此可以用include指定某些组件被缓存.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FFuYcCa-1644509154814)(Vue总结.assets/image-20220203165104074.png)]
插槽(Slot)是vue为组件封装者提供的能力,允许开发者封装组件的时候,保留一定的空间,给使用组件者填充.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y8D6Urs5-1644509154814)(Vue总结.assets/image-20220203165616982.png)]
例如下列代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edRJkzHN-1644509154815)(Vue总结.assets/image-20220203165944585.png)]
在left里面的p会被忽略,因此要在left里面设置一个插槽.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ScFVjYF-1644509154815)(Vue总结.assets/image-20220203170223672.png)]
vue官方规定,每个slot插槽都要有一个name名称. 如果省略了slot的name属性,则有一个default的名称
默认情况下,我们使用组件提供的内容,都会默认填充到名字为default的插槽之中.
<slot name="default"></slot>
v-slot必须放置到 template里面只是一个虚拟标签,不会渲染成任何实质性的元素
<Left> <template v-slot:插槽的名字> <p>v-slot必须放置到 template里面</p> </template> </Left>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMBAgWgg-1644509154815)(C:\Users\37802\AppData\Roaming\Typora\typora-user-images\image-20220203171010407.png)]
v-slot必须放置到 template里面
如果使用者没有指定模板丢入,那么就会展示原默认内容
没指定的话就是我!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YUYuLfuP-1644509154816)(C:\Users\37802\AppData\Roaming\Typora\typora-user-images\image-20220203171857656.png)]
我们下面设置了三个插槽
运用v-slot插槽
<Article> <template #header>无题template> <template #content>床前明月光template> <template #footer>李白template> Article>
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ugF8dMf-1644509154816)(Vue总结.assets/image-20220203174108623.png)]
使用的时候也能进行解构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fCo9yqje-1644509154816)(Vue总结.assets/image-20220203175134270.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OpYRPc4I-1644509154817)(Vue总结.assets/image-20220203175031321.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EyC3sV8v-1644509154817)(Vue总结.assets/image-20220203175345226.png)]
除了核心功能默认内置的指令 (v-model
和 v-show
),Vue 也允许注册自定义指令
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind
:只调用一次,指令与元素解绑时调用。
指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property
name
:指令名,不包括 v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为 2
。oldValue
:指令绑定的前一个值,仅在 update
和 componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如 v-my-directive="1 + 1"
中,表达式为 "1 + 1"
。arg
:传给指令的参数,可选。例如 v-my-directive:foo
中,参数为 "foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为 { foo: true, bar: true }
。vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode
:上一个虚拟节点,仅在 update
和 componentUpdated
钩子中可用。除了 el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset
来进行。
// 局部自定义指令 directives: { color: { //里面写各种生命周期钩子 bind(el, binding) { console.log(el); el.style.color = binding.value; }, inserted() {}, update() {}, }, },
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIXoXwkY-1644509154818)(Vue总结.assets/image-20220203203559639.png)]
用实例注册
// 注册一个全局自定义指令 `v-focus`Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() }})
import axios from "axios";Vue.prototype.axios = axios;//挂载到全局
如下面代码,直接使用this.axios
async get() { console.log(this.axios); const { data: res } = await this.axios.get( "http://www.liulongbin.top:3006/api/getbooks" ); console.log(res); },
路由( router ) 就是一个映射(对应关系)
自动实现实际地址和真实地址(对应组件)的映射
获取锚链接的js代码 location.hash
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sNE26Wa-1644509154818)(Vue总结.assets/image-20220204122859658.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQl5pilD-1644509154818)(C:\Users\37802\AppData\Roaming\Typora\typora-user-images\image-20220204123058596.png)]
在实例创建时给window的onhashchange添加事件,利用component动态渲染组件即可。
<template> <div class="app-container"> <div class="app-top"> <h1>app根组件</h1> <br /> <a href="#Index">首页</a> <a href="#Movie">电影</a> <a href="#About">关于</a> <br /> </div> <component :is="comName"></component> </div></template>export default { components: { Index, Movie, About }, data() { return { comName: "Index", }; }, created() { console.log(window); window.onhashchange = () => { let hash = window.location.hash; this.comName = hash.substr(2); }; },};
是vue.js给出的路由解决方案,只能在vue项目中使用。方便用于SPA单页面的模型。
npm i vue-router -S
创建路由模块:在src目录下 创建 router/index.js 的路由模块
index.js
//1. 导包import Vue from 'vue'import VueRouter from 'vue-router'import Home from "@/components/Home.vue";import Movie from "@/components/Movie.vue";import About from "@/components/About.vue";//2. 加载插件Vue.use(VueRouter);//3. 搭建路由规则var routes = [ { path: "/home", component: Home }, { path: "/movie", component: Movie }, { path: "/about", component: About },]//4. 创建实例对象给外部使用const router = new VueRouter({ routes: routes,});//5. 向外默认共享 export default router;
挂载到main.js里面的vue实例
import Vue from 'vue'import App from './App2.vue'//在模块化导入的时候 如果导的是一个文件夹,就会默认导入该文件夹下的index.js文件 //所以 import router from "@/router" 也是可以的import router from '@/router/index.js'Vue.config.productionTip = falsenew Vue({ router: router, render: h => h(App)}).$mount('#app')
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)// 1. 定义 (路由) 组件。// 可以从其他文件 import 进来const Foo = { template: 'foo' }const Bar = { template: 'bar' }// 2. 定义路由// 每个路由应该映射一个组件。 其中"component" 可以是// 通过 Vue.extend() 创建的组件构造器,// 或者,只是一个组件配置对象。// 我们晚点再讨论嵌套路由。const routes = [ { path: '/foo', component: Foo }, { path: '/bar', component: Bar }]// 3. 创建 router 实例,然后传 `routes` 配置// 你还可以传别的配置参数, 不过先这么简单着吧。const router = new VueRouter({ routes // (缩写) 相当于 routes: routes})// 4. 创建和挂载根实例。// 记得要通过 router 配置参数注入路由,// 从而让整个应用都有路由功能const app = new Vue({ router}).$mount('#app')// 现在,应用已经启动了!
<template> <div class="app-container"> <div class="app-top"> <h1>app根组件</h1> <br /> <a href="#/home">首页</a> <a href="#/movie">电影</a> <a href="#/about">关于</a> <br /> <router-view></router-view> </div> </div></template>
<template> <div class="app-container"> <div class="app-top"> <h1>app根组件</h1> <br /> <router-link to="/home">首页</router-link> <router-link to="/movie">电影</router-link> <router-link to="/about">关于</router-link> <br /> <router-view></router-view> </div> </div></template>
从下图可以发现 router-view 的本质也是 a链接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3VwLnn5-1644509154819)(Vue总结.assets/image-20220204225240065.png)]
访问地址A的时候,可以把请求重定向(区分转发)导地址B里。
//重定向var routes = [ { path: "/", redirect: '/home' }, { path: "/home", component: Home },]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QeNnnGy-1644509154819)(Vue总结.assets/image-20220204230808006.png)]
关于本身就是一个路由,但是关于里面又tab1和tab2,又有子集路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wdB84UF-1644509154820)(Vue总结.assets/image-20220204231629774.png)]
/
开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。****var routes = [ { path: "/", redirect: '/home' }, { path: "/home", component: Home }, { path: "/movie", component: Movie }, { path: "/about", component: About, children: [ { path: "tab1", component: Tab1 }, { path: "tab2", component: Tab2 }, ] },]
如果children数组中,某个路由规则的path为空字符串,则这条规则叫做默认子路由
下面代码:一进入about就默认使用tab1
{ path: "/about", component: About, children: [ { path: "", component: Tab1 }, { path: "tab2", component: Tab2 }, ] },
当不同的id值,都指向同一个组件时候,添加多个路由规则就让代码复用性很差。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJakglEJ-1644509154820)(Vue总结.assets/image-20220205150703257.png)]
利用:开头的字符来表示此级的地址路由规则是动态的,并且id值为id
<router-link to="/movie/1">电影1</router-link><router-link to="/movie/2">电影2</router-link><router-link to="/movie/3">电影3</router-link>routes{ path: "/movie/:id", component: Movie },
现在呢,像 /movie/1 和 /movie/2
都将映射到相同的路由。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。于是,我们可以更新 User
的模板,输出当前用户的 ID:
const User = { template: 'User {{ $route.params.id }}'}
你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params
中。例如:
模式 | 匹配路径 | $route.params |
---|---|---|
/user/:username | /user/evan | { username: 'evan' } |
/user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: '123' } |
除了 $route.params
外,$route
对象还提供了其它有用的信息,例如,
$route.query
(如果 URL 中有查询参数)$route.hash
#后面的东西$route.fullpath
全路径[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSvya5mD-1644509154821)(Vue总结.assets/image-20220205151946134.png)]
我们地址为
http://localhost:8080/#/movie/2?a=1&b=2
query就会解析url之中的查询参数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0OYlMb7-1644509154821)(Vue总结.assets/image-20220205152040667.png)]
动态路由规则能够携带参数,可以开启props进行传参,让路由所对应的组件通过props获取路由规则的动态参数
{ path: "/movie/:id", component: Movie,props:true}, export default { name: "Movie", // 接收 props 数据 props: ["mid"], }
在hash地址中,叫做“路径参数”。如:/movie/1
查询参数是url的最后?后面的参数项
在vue-router 里面也有一定的方法来代替原来的js方法
$router为导航对象
this.$router.push(‘hash地址’)
会增加一条历史记录(可以后退)
this.$router.replace('hash地址')
跳转到指定hash地址,替换掉当前的历史记录
this.$router.go(整数)
可以进行前进和后退 如-1代表后退一个 +1代表前进一个
实际开发vue提供了便捷的方法
this.$router.forward()
前进一个this.$router.back()
后退一层顾名思义,可以控制路由的访问权限
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtVvbvXS-1644509154822)(Vue总结.assets/image-20220205154523385.png)]
全局前置守卫:在跳转之前触发回调函数
//实例对象给外部使用const router = new VueRouter({ routes: routes,} );//全局导航守卫router.beforeEach((to, from, next) => { //to 代表目的路由参数对象 //from 代表当前位置的路由参数对象 //next 是函数变量 next() 代表放行 console.log(to); console.log(from); next()});
next()
的调用方式next()
直接放行next('hash')
地址 转发到这个页面next(false);
中断当前导航next(error)
(2.4.0+) 如果传入 next
的参数是一个 Error
实例,则导航会被终止且该错误会被传递给 router.onError()
注册过的回调。