Vue知识点整理(待更新)
参考Vue.js中文官网,Vue 知识点汇总(上)–附案例代码及项目地址,Vue 知识点汇总(下)–附案例代码及项目地址,Vue知识点汇总【持更】
文章目录
- Vue知识点整理(待更新)
- 一、基础知识
- 二、基础语法(渲染和绑定)
- 三、组件化 & 模块化开发(父子组件通讯)
- 四、Vue Cli和Webpack
- 五、vue-router的使用
- 六、状态管理
一、基础知识
-
【问】JS中attribute和property有什么区别?(attribute属性在HTML上,property属性值在js上;两者的区别是attribute不会同步property的值,而property可以同步attribute的值)
Note:
-
attribute
是HTML
标签上的特性,它的值只能够是字符串;attribute
可以简单理解成dom节点自带的属性,例如html中常用的id、class、title、align
。attributes是属于property的一个子集。attribute的赋值://注意参数1,2均是字符串 div1.setAttribute('class', 'a'); div1.setAttribute('title', 'b'); div1.setAttribute('title1', 'c'); div1.setAttribute('title2', 'd');
-
property是DOM中的属性,是JavaScript里的对象;property取值如下:
//取任何属性的只,用“.”即可 var id = div1.id; var className = div1.className; var childNodes = div1.childNodes; var attrs = div1.attributes; //此处再次强调: //1) class特性在变成属性时,名字改成了“className”,因此div1.className和div1.getAttrbute('class')相同。 //2) 上面代码中的div1.attributes是取的attributes这一属性,取出来保存到attrs变量中,attrs就成了一个NamedNodeList类型的对象,里面存储了若干个Attr类型。
-
在js中,attribute和property关系如下:
-
property能够从attribute中得到同步;
-
attribute不会同步property上的值;
-
attribute和property之间的数据绑定是单向的,attribute->property;
-
更改property和attribute上的任意值,都会将更新反映到HTML页面中;
-
-
-
【问】Vue.js是什么?(只关注于视图层,渐进式框架)
Note:
-
Vue (读音类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
-
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
-
-
【问】MVVM是什么?谈谈Vue的工作原理?
Note:
-
MVVM 是 Model - View - ViewModel 的缩写 可以看到他和之前的MVC很像,的确有人称之为一个加强优化版的MVC。 是一种模块化开发代码分层的思想或者框架!
-
模型(
Model
):模型和业务数据绑定,方便数据的使用和传递。 -
视图(
View
): 视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。 -
ViewModel
:首先它的创建需要将Model中的数据绑定在他身上(为模型到视图的映射提供桥梁)。将原来MVC中的业务逻辑剥离出来写在ViewModel中,简化view
和controller
。
-
-
使用步骤
1、模块中需要的数据,通过网络层请求得到 ,然后将数据绑定到Model层中。
2、将model
层中的数据转化到ViewModel
中,然后在ViewModel中处理一些逻辑问题。
3、将ViewModel中的数据绑定到控制器的View上,然后更新界面。MVVM模型适合作为前端的框架,用来实现前后端分离。
-
Vue官网对Vue的MVVM模型做出了解释:参考Vue中的MVVM
各层的作用:
-
View层:
①视图层
②在前端开发中就是DOM层
③主要作用是给用户展示各种信息 -
Model层:
①数据层
②数据可能是固定的死数据,更多是来自于服务器,从网络上请求下来的数据。 -
ViewModel层:
①视图模型层
②视图模型层是View和Model沟通的桥梁
③一方面它实现了Data Bindings来进行数据的绑定,将Model的改变实时反映到View中
④另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击,滚动,touch)时,可以监听到,并在需要的情况下改变对应的Data。
-
-
-
【问】Vue实例的生命周期分为哪几个阶段?(创建、运行和销毁;常见的生命周期函数包括
created
,mounted
和updated
等)Note:
-
生命周期概念:生命周期是指一个组件从创建 > 运行 > 销毁的整个过程,强调的是一个时间段。
生命周期函数概念:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点 。
-
组件生命周期函数的分类:
-
官网提供的Vue实例生命周期解释如下:
-
-
【问】关于Vue的特性有哪些?(数据驱动视图,双向数据绑定)
Note:
-
数据驱动视图:数据(
model
)的变化会驱动视图(View
)自动更新。 -
双向数据绑定:在网页中,form负责采集数据,Ajax负责提交数据。数据源的变化,会被自动渲染到页面上;页面上表单采集的数据发生变化的时候,会被 vue 自动获取到,并更新到数据源中。
-
-
【问】如何编写一个简单的Vue应用?(Vue实例挂载到某个元素上)
Note:
-
Vue.js
的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> </head> <body> <div id="app"> {{ message }} <!-- 声明式渲染 --> </div> </body> <script> var app = new Vue({ //创建Vue实例 el: '#app', //挂载点为id = "app"的DOM元素 data: { message: 'Hello Vue!' } }) </script> </html>
现在数据和 DOM 已经被建立了关联,所有东西都是响应式的,即在当前页面的控制台上修改
app.message = "Hello world"
,html页面会更新内容。
-
二、基础语法(渲染和绑定)
-
【问】Vue实例对象中常用属性有哪些?
Note:
-
el:""
:指定vue所操作的dom
范围,属性值是你获取的节点; -
data:{}
:就是vue的model
,是存放数据的,属性值是一个对象或者是一个函数,在组件中的data是一个函数; -
watch:{}
:vue
中的侦听器 -
computed:{}
:vue
中的计算属性,看起来像methods
,用起来像data
; -
methods:{}
:是vue中的事件方法;
-
-
【问】内容渲染指令有哪些?(插值表达式,v-text=‘’,v-html=‘’)
Note:
-
内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:
-
{{}}
插值表达式:在实际开发中用的最多,只是内容的占位符,不会覆盖原有的内容。注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中; -
v-text
:会覆盖元素内部原有的内容。 -
v-html
:不仅会覆盖原来的内容,而且可以把带有标签的字符串,渲染成真正的HTML内容;
比如:
<div id = "box1"> <p v-text="text2">这是我原本的内容</p> <div v-html="text3">这是我原本的内容</div> </div> <script> const vm1=new Vue({ el:'#box1', data:{ text1:'插值表达式的结果', text2:'v-text的结果', text3:'a href="http://www.baidu.com">v-html的结果</a>' } </script>
-
-
-
【问】属性绑定指令如何使用?(
v-bind:属性=
,常配合class,style,src和href属性使用)Note:
-
v-bind
:可为元素的属性动态绑定属性值,可简写为:
(v-bind:
语法糖)。 -
在开发中,有哪些属性需要动态进行绑定:比如图片的链接
src
、网站的链接href
、动态绑定一些类、样式等等,比如<!--html--> <a :href="'https://www.runoob.com/vue2/'+url">点击跳转vue菜鸟教程</a> <!--script--> const vm2=new Vue({ el:'#box2', data:{ url:'vue-tutorial.html' } })
-
v-bind:class=
:动态切换class
,比如:- 当数据为某个状态时,字体显示红色。
- 当数据另一个状态时,字体显示黑色。
绑定class有两种方式:
-
对象语法:
class
后面跟的是一个对象用法一:直接通过{}绑定一个类 <h2 :class="{'active': isActive}">Hello World</h2> 用法二:也可以通过判断,传入多个值 <h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>
-
数组语法:
class
后面跟的是一个数组用法一:直接通过{}绑定一个类 <h2 :class="['active']">Hello World</h2> 用法二:也可以传入多个值 <h2 :class="['active', 'line']">Hello World</h2>
-
v-bind:style
来绑定一些CSS内联样式,绑定style
有两种方式:-
对象语法:style后面跟的是一个对象类型,对象的
key
是CSS属性名称,
对象的value
是具体赋的值,值可以来自于data中的属性::style="{color: currentColor, fontSize: fontSize + 'px'}"
-
数组语法:style后面跟的是一个数组类型,多个值以“,“分割即可
<div v-bind:style="[baseStyles, overridingStyles]"></div>
-
-
-
【问】事件绑定指令如何使用?(
v-on:事件=方法
)Note:
-
vue提供了
v-on
事件绑定指令,用于为DOM元素绑定事件监听。原生DOM对象有onclick
、oninput
、onkeyup
等原生事件,替换为vue的事件绑定形式后,分别为v-on:click
、v-on:input
、v-on:keyup
; -
v-on:
可以用@
进行简写(v-on:
语法糖) -
在
v-on
指令所绑定的事件处理函数,可以接收事件参数对象event
; -
$event
是vue提供的特殊变量,用来表示原生的事件参数对象event
; -
参考代码如下:
<button @click="add">自增</botton> <button @click="changeColor">变色</botton> data(){ return{ count:'', } } methods:{ add(){ this.count++; }, changeColor(e){ e.target.style.backgroundColor='red'; } }
-
-
【问】事件修饰符,按钮修饰符是什么?
Note:
-
事件修饰符:在事件处理函数中调用
event.preventDefault()
(取消在浏览器中事件的默认动作)或event.stopPropagagation()
(阻止事件冒泡和捕获)是非常常见的需求。参考stopPropagation, preventDefault的区别
vue提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。常用的5个事件修饰符如下:参考[事件冒泡概念]((https://baike.baidu.com/item/%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1/4211429?fr=aladdin).prevent 阻止默认行为(例如:阻止a连接的跳转、阻止表单的提交等) .stop 阻止事件冒泡(即阻止传播到责任链中下一个事件处理器) .capture 以捕获模式触发当前的事件处理函数 .once 绑定的事件只触发1次 .self 只有在event.target是当前元素自身时触发事件处理函数
-
-
按钮修饰符:在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符,例如
<!--只有在"key"是'Enter'时调用'vm.submit()'...> <input @keyup.enter="submit"> <!--只有在'key'是'Esc'时调用'vm.clearInput()'...> <input @keyup.esc="clearInput">
-
【问】双向绑定指令如何使用?(
v-model
原理为v-on:input
+v-bind:value
;v-model对radio,checkbox,select等进行双向绑定)Note:
-
vue提供了
v-model
双向数据绑定指令,用来辅助开发者在不操作DOM的前提下,快速获取表单的数据。v-model
其实是一个语法糖,它的背后本质上是包含两个操作:-
v-bind
绑定一个value
属性 -
v-on
指令给当前元素绑定input
事件。在普通input
对应的input
事件中,vue
已经帮我们写好逻辑了。
也就是说下面的代码:等同于下面的代码:
<input type="text" v-model="message"> 等同于 <input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
-
-
v-model:radio
:复选框分为两种情况:单个勾选框和多个勾选框单个勾选框:
v-model
即为布尔值。此时input
的value
并不影响v-model
的值。参考https://jiuaidu.com/jianzhan/832729/<template> <div id="app"> <input type="radio" id="male" value="male" v-model="gender"> male <input type="radio" id="female" value="female" v-model="gender"> femalea <p>{{gender}}</p> </div> </template> <script> export default { name: 'app', data () { return { gender: '' } } } </script>
-
v-model:checkbox
:-
单个勾选框:
-
v-model
即为布尔值。 -
此时input的value并不影响
v-model
的值。
-
-
多个复选框:当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。当选中某一个时,就会将
input
的value
添加到数组中。代码:
<div id = "app"> <!--单个复选框--> <label for="check"> <input type="checkbox" v-model="checked" id="check">同意协议 </label> <p>是否选中:{{checked}} <p> <!--多个复选框--> <label><input type="checkbox" v-model="hobbies"value="篮球">篮球</Label> <label><input type="checkbox" v-model="hobbies"value="足球">足球</Label> <label><input type="checkbox" v-model="hobbies"value="台球">台球</Label> <p>您选中的爱好:{{hobbies}}</p> </div> <script> let app = new Vue ({ el:'#app', data:{ checked : false , hobbies: [] } }) </script >
-
-
v-model:select
:和checkbox
一样,select也分单选和多选两种情况。-
单选:只能选中一个值。
-
v-model
绑定的是一个值。 -
当我们选中option中的一个时,会将它对应的value赋值到mySelect中
代码:
<!--选择一个值--> <select v-model="mySelect"> <option value="apple">苹果</option> <option value="orange">橘子</option> <option value="banana">香蕉</option> </select> <p>您最喜欢的水果:{{mySelect}} </p> ...
-
-
多选:可以选中多个值。
-
v-model
绑定的是一个数组。 -
当选中多个值时,就会将选中的option对应的value添加到数组mySelects中
代码:
<select v-model="mySelect" multiple> <option value="apple">苹果</option> <option value="orange">橘子</option> <option value="banana">香蕉</option> </select> <p>您最喜欢的水果:{{mySelect}} </p> <script> let app = new Vue ({ el:'#app', data:{ mySelect:'apple', mySelects : [] } }) </script>
-
-
-
-
【问】条件渲染指令如何使用?它们之间有什么区别(
v-if
动态添加DOM元素,有更高的切换开销;v-show
动态添加样式,有更高的初始渲染开销)Note:
-
条件渲染指令包括:
v-if
和v-show
-
实现原理不同:
-
v-if
指令会动态地创建或移除DOM元素,从而控制元素在页面上的显示与隐藏; -
v-show
指令会动态为元素添加或移除style="display:none;"
样式,从而控制元素的显示与隐藏;
-
-
性能消耗不同:
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此:- 如果需要非常频繁地切换,则使用
v-show
较好 - 如果在运行时条件很少改变,则使用
v-if
较好
- 如果需要非常频繁地切换,则使用
-
两者使用的区别:
-
v-if
、v-else
、v-else-if
条件性的渲染某元素,判定为true时渲染,否则不渲染; -
v-show
条件不满足令其display
为none
。
<div v-if="score<60">不及格</div> <div v-else-if="60<=score&&score<90">中等</div> <div v-else="score>=90">优秀</div> <div v-show="true">display:block显示</div> <div v-show="false">display:none隐藏</div>
-
-
-
【问】列表渲染指令如何使用?(
v-for
常配合checkbox、options、li标签使用)Note:
-
vue
提供了v-for
列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。v-for
指令需要使用item in items
形式的特殊语法,其中:items
是待循环的数组item
是被循环的每一项
代码:
<ul id='app'> <li v-for="item in list"> 姓名是:{{item.name}} </li> </ul> <script> let app = new Vue ({ el:'#app', data:{ list: [ {'id' : 1, 'name': 'wang'}, {'id' : 2, 'name': 'liu'} ] } }) </script>
-
v-for
指令还支持一个可选的第二个参数,即当前项的索引。语法格式为(item,index) in items
,示例代码如下(item
,index
变量名可随便取):<ul id='app'> <li v-for="(item,index) in list"> 第{{index + 1}}个同学,姓名是:{{item.name}} </li> </ul>
-
【问】如何提高列表渲染指令的性能?(
v-for
在vue2.2+之后必须使用:key
来提高渲染效率),参考列表渲染 — Vue.jsNote:
-
当列表的数据变化时,默认情况下,vue会尽可能的复用已存在的DOM元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
-
为了给vue一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的
key
属性:<ul id='app'> <li v-for="(user,i) in list" :key="user.id"> 姓名是:{{item.name}} </li> </ul>
-
-
-
【问】keep-alive的基本使用?
Note:
-
keep-alive
是什么-
当组件被缓存时,会自动触发组件的
deactivated
生命周期函数。 -
当组件被激活时,会自动触发组件的
activated
生命周期函数。 -
当组件第一次被创建,会执行
created
生命周期函数,也会执行activated
生命周期函数。之后组件再被激活,只会触发activated
而不会触发created
。
-
-
keep-alive
的基本使用以及基本属性:<keep-alive> <组件名></组件名> <keep-alive>
-
include包含的组件(可以为字符串,数组,以及正则表达式,只有名称匹配的组件会被缓存)。
// 只缓存组件name为a和b的组件 <keep-alive include="a,b"> <component /> </keep-alive>
-
exclude排除的组件(可以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)。
// 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染) <keep-alive exclude="c"> <component /> </keep-alive> // 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存a组件 <keep-alive include="a,b" exclude="b"> <component /> </keep-alive>
-
max缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数);
// 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件 <keep-alive exclude="c" max="5"> <component /> </keep-alive>
-
-
-
【问】侦听器watch的作用及如何使用?(侦听器主要用于监听data中存储的数据对象是否发生变化;设置deep得到嵌套侦听器;设置immediate得到即时回调侦听器),参考侦听器 | Vue.js,《Vue 入门教程》Vue 侦听器
Note:
-
watch
侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。有两种创建方式:-
方法格式的侦听器:
watch : { key : function(new,old){} }
; -
对象格式的侦听器:
watch : {key : {handler(new,old){}, deep, immediate }
,支持创建嵌套侦听器和回调侦听器。
-
-
侦听器简单例子:
-
侦听器
watch
实际是vue
实例上的一个对象属性。当我们需要对vue
实例上某个属性进行侦听时,我们以需要被侦听的属性名作为watch
对象的键,以一个函数function
作为该键的值。 -
函数
function
接收两个参数:侦听数据变化之后的值newValue
;侦听数据变化之前的值oldValue
:
var vm = new Vue({ el: '#app', data() { return { count: 0 } }, watch: { count: function(newVal, oldVal) { // 具体处理逻辑 }, } })
-
-
深层侦听器:
watch
默认是浅层的,仅在被赋新值时,才会触发回调函数。如果想侦听所有嵌套的变更需要将deep
选项设置为true
,得到使用深层侦听器;export default { watch: { question : { handler(newValue, oldValue) { // 注意:在嵌套的变更中, // 只要没有替换对象本身, // 那么这里的 `newValue` 和 `oldValue` 相同 }, deep: true } } }
-
即时回调的侦听器:
watch
默认是懒执行的,仅当数据源变化时,才会执行回调。但在某些场景中,举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据,即在创建侦听器时,立即执行一遍回调。这里可以为侦听器设置immediate: rue
,强制回调函数立即执行:export default { // ... watch: { question: { handler(newQuestion) { // 在组件实例创建时会立即调用 }, // 强制立即执行回调 immediate: true } } // ... }
-
侦听器综合案例(对字典、整型进行监听):参考Vue基础之侦听器详解
const app = createApp({ data() { return { a: 1, b: 2, c: { d: 4 }, e: 5, f: 6 } }, watch: { // 侦听顶级 property a(val, oldVal) { console.log(`new: ${val}, old: ${oldVal}`) }, // 字符串方法名 b: 'someMethod', // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深 c: { handler(val, oldVal) { console.log('c changed') }, deep: true }, // 侦听单个嵌套 property 'c.d': function (val, oldVal) { // do something }, // 该回调将会在侦听开始之后被立即调用 e: { handler(val, oldVal) { console.log('e changed') }, immediate: true }, // 你可以传入回调数组,它们会被逐一调用 f: [ 'handle1', function handle2(val, oldVal) { console.log('handle2 triggered') }, { handler: function handle3(val, oldVal) { console.log('handle3 triggered') } /* ... */ } ] }, methods: { someMethod() { console.log('b changed') }, handle1() { console.log('handle 1 triggered') } } }) const vm = app.mount('#app') vm.a = 3 // => new: 3, old: 1
-
-
【问】计算属性computed是什么?(如果相关数据发生改变,computed会重新计算并返回结果,有点类似watch侦听的意思,应该也是采用观察者设计模式;默认走缓存),参考计算属性
Note:
-
关于
computed
计算属性的理解:1、computed 和 data同级,计算属性写在computed中;
2、写起来像方法,用起来像属性;
3、计算属性虽然称为属性,但其本质是一个函数;
4、虽然计算属性本质是一个函数,但是在页面中使用计算属性时,不要加
()
;5、一定要有返回值;
6、可以使用
data
中的已知值;7、只要跟计算属性相关的数据发生了变化,计算属性就会重新计算,不相关的属性无论如何变化,都不会导致计算属性变化;
8、计算属性名不能和
data
中的数据重名(因为要使用data中的数据)。 -
使用例子:
<template> {{reversedMsg}} </template> export default { data(){ return{ msg : "" } }, computed: { reversedMsg(){ return this.msg.split('').reverse().join('') } } // ... }
-
-
【问】computed与watch的区别和使用场景?,参考Computed 和 Watch 的区别
Note:
-
computed
计算属性的作用:-
1)解决模板中放入过多的逻辑会让模板过重且难以维护的问题。例如两个数据的拼接或字体颜色的判断。
-
2)它支持缓存,只有依赖的数据发生了变化,才会重新计算。例如模板中多次用到数据拼接可以用计算属性,只执行一次计算,除非数据发生变化。
-
3)不支持异步,如果有异步操作,无法监听数据的变化。
-
4)如果属性值是函数,默认使用
get
方法,函数的返回值就是属性的属性值。还有一个set
方法,当数据变化时就会调用set
方法。 -
5)
computed
的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。
-
-
watch
侦听器的作用:-
1)它不支持缓存,数据变化时,它就会触发相应的操作。
-
2)支持异步监听。
-
3)接受两个参数,第一个是最新的值,第二个是变化之前的值。
-
4)监听
data
或者props
传来的数据,发生变化时会触发相应操作。有两个参数:-
immediate
:立即触发回调函数。 -
deep
:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。
-
-
-
computed
与watch
的使用场景:-
computed
:是多对一,多个数据影响一个。当需要进行数值计算,并且依赖于其它数据时,应该使用computed
,因为可以利用computed
的缓存特性,避免每次获取值时都要重新计算(缓存多个值)。 -
watch
:是一对多,一个数据发生变化,执行相应操作会影响多个数据。当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
-
-
三、组件化 & 模块化开发(父子组件通讯)
-
【问】Vue中如何注册组件?(
Vue.extend()
创建,Vue.component()
注册)Note:
-
组件的使用分成三个步骤:
- 创建组件构造器;
- 注册组件;
- 使用组件;
-
组件使用的简单案例(这里的组件是全局的组件):
<div id="app"> <!--3.使用组件--> <my-cpn></my-cpn> <div> <div id="app1"> <!--3.使用组件--> <my-cpn></my-cpn> <div> <script src="../js/vue.js"></script> <script> //1.创建组件构造器 const myComponent = Vue.extend({ template: `<div> <h2>组件标题</h2> <p>我是组件中的一个段落内容</p> </div>` }); //2.注册组件,并且定义组件标签的名称 Vue.component('my-cpn',myComponent) let app = new Vue({ el:'#app' }) let app1 = new Vue({ el:'#app1' }) </script>
-
Vue.extend()
:调用Vue.extend()
创建的是一个组件构造器。-
通常在创建组件构造器时,传入
template
代表我们自定义组件的模板。 -
该模板就是在使用到组件的地方,要显示的HTML代码。
-
事实上,这种写法在
Vue2.x
的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
-
-
Vue.component()
:调用Vue.component()
是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。所以需要传递两个参数:-
注册组件的标签名
-
组件构造器
-
组件必须挂载在某个Vue实例下,否则它不会生效。
-
-
-
【问】什么是全局组件和局部组件?
Note:
-
当我们通过调用
Vue.component()
注册组件时,组件的注册是全局的,这意味着该组件可以在任意Vue示例下使用。 如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件。 -
全局组件看上一问代码;
-
局部组件代码如下(效果为
app1
对应的div
没有被渲染):<div id="app"> <!--3.使用组件--> <my-cpn></my-cpn> <div> <div id="app1"> <!--3.使用组件--> <my-cpn></my-cpn> <div> <script src="../js/vu.js"></script> <script> //1.创建组件构造器 const myComponent = Vue.extend({ template: `<div> <h2>组件标题</h2> <p>我是组件中的一个段落内容</p> </div>` }); let app = new Vue({ el:'#app' //2.注册局部组件,并且定义组件标签的名称 components : { 'my-cpn' : myComponent } }) let app1 = new Vue({ el:'#app1' }) </script>
-
-
【问】什么是父组件和子组件?(父组件中注册了子组件为
child-cpn
,则此时实例不能注册该子组件child-cpn
)Note:
-
父组件和子组件:组件和组件之间存在层级关系,而其中一种非常重要的关系就是父子组件的关系。我们来看通过代码如何组成的这种层级关系(在父组件创建(
Vue.extend()
)中通过components
属性引入子组件):<div id="app"> <!--3.使用组件--> <parent-cpn></parent-cpn> <div> <script src="../js/vue.js"></script> <script> //1.创建一个子组件构造器 const childComponent = Vue.extend({ template: `<div> <p>我是子组件child</p> </div>` }); //1.创建一个父组件构造器 const parentComponent = Vue.extend({ template: `<div> <p>我是父组件parent</p> <child-cpn></child-cpn> </div>` , components: { 'child-cpn' : childComponent } }); let app = new Vue({ el:'#app' //2.注册局部组件,并且定义组件标签的名称 components : { 'parent-cpn' : parentComponent } }) </script>
-
父子组件错误用法:以子标签的形式在Vue实例中使用
-
因为当子组件注册到父组件的
components
时,Vue会编译好父组件的模块 -
该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)
-
<child-cpn></child-cpn>
是只能在父组件中被识别的。类似这种用法,<child-cpn></child-cpn>
是会被浏览器忽略的。
-
-
-
【问】父组件和子组件之间如何通讯?(渲染父组件时会同时渲染子组件;父传子用
props
,子组件通过props
定义要接收到参数;子传父用$emit
:子组件定义事件,父组件定义方法)Note:
-
父传子用
props
:子组件通过props
定义要接收到参数-
第一步:引入子组件。
-
第二步:在数据源中定义要传入子组件的数据
parentMsg
。 -
第三步:在使用
child
组件时传入parentMsg
。<child :自定义属性名="parentMsg"></child>
。 -
第四步:在子组件中,要
props:['自定义属性名']
来接收传过来的参数。
父组件参考代码:
<template> <div> <h2>parent</h2> <!--3、传入parentMsg--> <child :visible="visible"></chld> </div> </template> <script> //1、引入子组件 import child from './child.vue' export default { data() { return { //2、定义要传入子组件的数据parentMsg visible:'true' } }, components:{ child } } </script>
子组件参考代码:
<template> <div> {{visible}} </div> </template> <script> export default { name:'child', //使用prors对象可以设置配置项,使用prors数组不可以。 // props:{ // parentMsg:{ // type:String, // default:'i am child' // } // } props:['visible']//接收 } </script>
-
-
子传父用
$emit
:子组件定义事件,父组件定义方法emit
使用方法:this.$emit(‘自定义事件名’,所需要传的值)
-
第一步:首先在子组件中定义一个事件,并且使用
emit
发送给父组件,在示例中子组件使用的click
事件触发发送自定义事件(sendmsg)
。 -
第二步:在父组件中需要定义方法(
getmsg
)接受自定义事件(sendmsg
): -
第三步:在使用子组件时,
<child @sendmsg="getmsg">
。
【子组件】发送值代码:
<template> <div> <button @click="childmsg">点我试试</button> </div> </template> <script> export default { name:'child', data() { return { msg:"This is the first word from child" } }, methods:{ //点击按钮则向父组件传自定义事件sendmsg,childmsg childmsg(){ this.$emit('sendmsg',this.msg) } } } </script>
【父组件】接收值代码:
<template> <div> <child @sendmsg="getmsg"></child> </div> </template> <script> import child from './child.vue' export default { data() { return { } }, components:{ child }, methods:{ getmsg(val){ console.log(val) } } } </script>
-
-
-
【问】兄弟组件是什么?其之间如何进行数据共享?(可通过EventBus事件总线对象实现,即
$emit
发送数据(等价notify
),$on
监听数据(等价wait
),基于事件驱动通信,参考Vue 兄弟组件之间的通信Note:
-
Vue中实现兄弟组件的通讯一般为2种方式:
-
一种方法是让父组件允当两个子组件之间的中间件(中继);
-
另一种就是使用EventBus(事件总线),它允许两个子组件之间直接通讯,而不需要涉及父组件。
由于中继方式比较简单,这里不做赘述,只讲
EventBus
方式。 -
-
EventBus
事件总线方式:-
第一步:在兄弟组件同目录下创建
eventBus.js
,然后创建vue实例:import Vue from 'vue' export default new Vue()
-
第二步:在【兄弟组件A】中,引入
eventBus.js
(定义为bus
对象),接着定义数据msg
,编写方法用于在监听到share
事件后发送msg
。import bus from './eventBus.js' <button @click="sendMsg"> export default{ data(){ return{ msg:'hello' } }, methods:{ sendMsg(){ bus.$emit('share',this.msg); } } }
-
第三步
:在【兄弟组件B】中,引入eventBus.js
,定义数据newMsg,编写方法用于接收msg
和赋值给newMsg
:import bus from './eventBus.js' <button @click="sendMsg"> export default{ data(){ return{ newMsg:[] } }, created:{ bus.$on('share',val=>{ this.newMsg=val; }) } }
Note:
-
这里声明事件为
share
-
兄弟组件之间通过
Vue
实例对象进行通信,通过obj.$emit
向其他兄弟组件发送关于share
事件的消息,其他兄弟组件通过obj.$on
监听share
事件的消息(即对象的wait
和notify
操作)
-
-
-
【问】插槽是什么?插槽的用法(需要先理解父子组件之间如何通讯;默认插槽,具名插槽,作用域插槽(默认,具名,解构),动态插槽名),参考插槽 Slots | Vue.js
Note:总体思想是父组件指定内容,子组件渲染内容(子组件中的
slot
起到占位符的作用)。-
v-slot
的基本用法:父组件可以通过子组件中的插槽显示自定义的内容-
vue
官方规定:每一个slot
插槽都要有一个name
名称
如果省略了slot
的name
则有一个默认名称default
默认情况下,使用组件时提供的内容会被填充到name
为default
的插槽内。 -
使用
v-slot:xxx
, 其中xxx
为插槽name
值,只能放在父组件标签内 -
v-slot
是一个虚拟标签,只起到包裹性质的作用,不会被渲染为实质性的html
元素,v-slot:xxx
可以简写为#xxx
-
v-slot
在父子组件中的使用:【父组件声明了子组件为Left,并使用具名插槽】 <Left> <template v-slot:mySlot> <p>这是在 Left 组件声明的p标签</p> </template> </Left> 【子组件定义了mySlot插槽】 <div style="color:#33e;background:#ee2"> <slot name="mySlot"></slot> </div>
-
-
默认插槽(
default
):-
当使用组件指定了插槽内容时,优先显示指定的内容
当没有指定内容时,渲染 slot 标签内的默认内容 -
简单演示:父组件显式提供的内容会取代子组件的默认内容
//父组件声明子组件为SubmitButton <SubmitButton>Save</SubmitButton> //子组件默认内容 <button type="submit"> <slot> Submit <!-- 默认内容 --> </slot> </button>
-
-
具名插槽(
name
):-
在一个组件中包含多个插槽出口是很有用的,为了将内容置入组件的不同插槽中,要用带有
name
属性的插槽 -
简单演示:没有提供
name
的<slot>
出口会隐式地命名为 “default”(默认插槽) 。//子组件定义多个插槽 <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
在父组件中使用
<BaseLayout>
时,我们需要一种方式将多个插槽内容传入到各自目标插槽的出口。此时就需要用到具名插槽了//父组件将子组件声明为<BaseLayout> <BaseLayout> <template v-slot:header> <!-- header 插槽的内容放这里 --> </template> </BaseLayout>
-
具名插槽传入内容时需要使用一个含
v-slot
指令的<template>
元素;v-slot
有对应的简写#
,因此<template v-slot:header>
可以简写为<template #header>
,意思是:将这部分模板片段传入子组件的 header 插槽中
-
-
渲染作用域 & 作用域插槽(通过
v-slot
传入props
获取子组件插槽的属性):-
渲染作用域:插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。
<span>{{ message }}</span> <FancyButton>{{ message }}</FancyButton>
这里的两个
{{ message }}
插值表达式渲染的内容都是一样的。插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,这和 JavaScript 的词法作用域规则是一致的。换言之:
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
-
作用域插槽:在上面的渲染作用域可知,插槽的内容无法访问到子组件的状态。然而在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。这里可以像对组件传递
props
那样,向一个插槽的出口上传递attributes
-
条件:在封装组件时,为预留的
<slot>
提供属性对应的值 -
格式:
1)子组件:
<slot v-bind:username='username' name='box1'></slot>
2)父组件:
<template v-slot:box1='username_props'>
在封装组件时,为预留的<slot>
提供属性对应的值,叫做作用域插槽。这些属性对应的值可以在父组件中访问到,默认为空对象。 -
默认作用域插槽演示:
//父组件 <MyComponent v-slot="slotProps"> {{ slotProps.text }} {{ slotProps.count }} </MyComponent>
v-slot="slotProps"
可以类比这里的函数签名,和函数的参数类似,我们也可以在v-slot
中使用解构://父组件 <MyComponent v-slot="{text,count}"> {{ text }} {{ count }} </MyComponent>
-
具名作用域插槽演示:
具名作用域插槽的工作方式也是类似的,插槽props
可以作为v-slot
指令的值被访问到:v-slot:name="slotProps"
,当使用缩写时是这样#name="slotProps"
//子组件 <slot name="header" message="hello"></slot> //父组件 <MyComponent> <template #header="headerProps"> {{ headerProps }} </template> <template #default="defaultProps"> {{ defaultProps }} </template> <template #footer="footerProps"> {{ footerProps }} </template> </MyComponent>
最终
headerProps
的结果是{ message: 'hello' }
-
-
作用域插槽的例子:
子组件在其作用域下完成与
user
对象的绑定<div> <slot v-bind:user="user" name="box3"></slot> <slot v-bind:msg="hello world" name="box4"></slot> </div> data(){ return:{ user:{ firstname:'lan', lastname:'chun' } } }
父组件通过向插槽传props,可以获取到子组件的user对象值
<子组件名> <template v-slot:box3="slotProps1"> {{slotProps1.user.firstname}} {{slotProps1.user.lastname}} </template> <template v-slot:box4="slotProps2"> {{slotProps2.msg}} </template> </子组件名>
-
动态插槽名(在插槽
v-slot
上使用动态参数)-
动态参数:参考模板语法 | Vue.js
同样在指令参数上也可以使用一个
JavaScript
表达式,需要包含在一对方括号内:<!-- 注意,参数表达式有一些约束, 参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释 --> <a v-bind:[attributeName]="url"> ... </a> <!-- 简写 --> <a :[attributeName]="url"> ... </a>
这里的
attributeName
会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。举例来说,如果你的组件实例有一个数据属性attributeName
,其值为"href"
,那么这个绑定就等价于v-bind:href
。相似地,你还可以将一个函数绑定到动态的事件名称上:
<a v-on:[eventName]="doSomething"> ... </a> <!-- 简写 --> <a @[eventName]="doSomething">
在此示例中,当
eventName
的值是"focus"
时,v-on:[eventName]
就等价于v-on:focus
。 -
动态插槽名:
动态指令参数在
v-slot
上也是有效的,即可以定义下面这样的动态插槽名:<base-layout> <template v-slot:[dynamicSlotName]> ... </template> <!-- 缩写为 --> <template #[dynamicSlotName]> ... </template> </base-layout>
注意这里的表达式和动态指令参数受相同的语法限制。
-
-
-
四、Vue Cli和Webpack
-
【问】什么是Webpack?(模块和打包)
-
【问】Webpack如何配置?
-
【问】Webpack对less文件进行处理?
-
【问】Webpack对图片文件进行处理?
-
【问】Webpack对ES6语法进行处理?
-
【问】Webpack如何配置vue.js?
-
【问】Vue Cli是什么?有什么安装前提?
-
【问】Vue Cli2和Vue Cli3有什么区别?
五、vue-router的使用
-
【问】前端路由的概念和原理?
-
【问】路由的基本使用?
-
【问】路由的重定向
-
【问】什么是路由的懒加载
-
【问】什么是嵌套路由
-
【问】什么是动态路由匹配
-
【问】什么是声明式导航和编程式导航
-
【问】什么是路由守卫?
-
【问】怎样进行路由传参?
-
【问】什么是Promise呢?
-
【问】Promise的基本使用
-
【问】Promise的链式调用
六、状态管理
-
【问】什么是状态管理?
-
【问】Vuex核心概念是什么?
-
【问】核心状态有哪些?怎样进行管理的?
-
【问】vue的项目结构
-
【问】Vuex在项目中的基本使用