##Vue面试题##
组件中通讯有$emit,props,vuex,provid和inject,$parent/$children,$refs,全局总线时间EvenBus,订阅与发布模式的subscrip/publish
2.1根节点不同
Vu2中必须使用根节点template或div来包裹,否则会报错
Vu3可以没有根标签
2.2组合式API和选项式API
在vue2中采用选项式API,将数据和函数集中起来处理,将功能点切割了当逻辑复杂的时候不利于代码阅读。
在vue3中采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护。
2.3生命周期的变化
Vue2中创建前beforeCreate和创建后created的生命周期钩子在Vue3中使用setup()这个钩子代替了
销毁前beforeDestory和销毁后Destoryed的钩子有所变化改为Unmount和Unmounted
其他钩子有所改变就加了On然后以驼峰命名形式:
挂载前:beforeMount -> onBeforeMount
挂载后:mounted -> onMounted
更新前:beforeUpdate -> onBeforeUpdate
更新后:updated -> onUpdated
异常捕获:errorCaptured -> onErrorCaptured
- 2.4v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,到是不建议这么做,会带来性能上的浪费
在vue3中v-if的优先级高于v-for了,一起使用会报错,解决方法:可以通过在外部添加一个标签,将v-for移到外层
2.5 diff算法不同
vue2中diff算法
1.遍历每一个虚拟节点,进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方
2.用patch记录的消息去更新dom
缺点:比较每一个节点,而对于一些不参与更新的元素,进行比较是有点消耗性能的
特点:特别要提一下Vue的patch是即使的,并不是打包所有修改最后一起操作DOM,也就是在Vue中边记录边更新。(React则是将更新放入队列后集中处理)。
vue3中的diff算法
在初始化的时候会给每一个虚拟节点添加一个patchFlags,是一个优化的标识。
指挥比较patchFlags发生变化的节点,进行识图更新。而对于patchFlags没有变化的元素作静态标记,在渲染的时候直接复用。
2.6响应式原理不同
1.vue2通过Object.definedProperty()的get()和set()来做数据的劫持,结合和发布订阅模式来实现。Object.definedProperty()会遍历每一个属性。
2.vue3是通过Proxy代理的方式实现。
3.proxy的优势:不需要像Object.definedProperty()的那样遍历每一个属性,有一定的性能提升proxy可以理解为在目标对象之前架设一层“拦截”,外界对该对象访问都必须通过这一层拦截。这个拦截可以对外界进行过滤和改写。、
4.当属性过多的时候利用Object.definedProperty()要通过遍历的方式监听每一个属性。利用proxy则不需要遍历,会自动监听所有属性,有利于性能的提升
2.7插槽的不同
1.vue2中具名插槽使用的是slot='',vue3中使用的是v-slot=''
2.vue2中作用域插槽,父组件使用的是slop-scope="data",而vue3中父组件使用插槽是使用#data或者#default="{data}"
vue3中具名插槽
- 子组件:
- <div>
- <slot name="person">slot>
- div>
- 父组件:
- <child>
- <template v-slot:person>
- <span>我是插槽插入的内容span>
- template>
- child>
Vue3作用域操作
- 子组件:
- <div>
- <slot :data="data">slot>
- div>
- 父组件:
- <child>
- <span #data>我是插槽插入的内容span> === <span #default="{data}">我是插槽插入的内容span>
- child>
2.8样式穿透
1.vue2中
- /deep/ .类名{} //less中
- ::v-deep .类名{} //scss中
2.vue3中
- :deep (.类名{}) //less中
- ::v-deep(.类名{}) //scss
Vue3主要改变的是在类名以及{}外层加了小括号来包裹,还有less样式穿透是的边话
- 1.beforecreate:可以在加个loading事件,在加载实例是触发
- 2.created:初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
- 3.mounted:挂载元素,获取到dom节点
- 4.updated:如果对数据统一处理,在这里写上相应函数
- 5.beforeDestroy:可以一个确认停止事件的确认框
- 6.nextTick:更新数据后立即操作dom
- 1.对象方法v-bind:class="{'orange':isRipe, 'green':isNotRipe}”
- 2.数组方法v-bind:class="[class1,class2]"
- 3.行内v-bind:style="{color:color,fontSize:fontSize+'px'}”
router-link标签会渲染为标签,在标签里填写to属性,值为路由的路径
编程式导航,使用router.push('/home')方法或router.replace('/home')方式形式跳转
View相当于视图,字面意思就是直观的讲就是页面呈现给数据
Model相当于数据层,数据就是即将在view层展示的
ModelView类似与中间件的用法,主要用于Model和View之间的桥梁,通过数据的双向绑定即可将两者之间联系起来,并保证数据的一致性。注意的是,Model和View两个是无法连接交互的,只能通过ViewModel这个中间件来通信。

ViewModel主要体现以下三个点:
ViewModel层通过观察数据层的变化,并对视图对应的内容进行实时更新。
ViewModel层通过监听视图层的变化,并能够通知数据发生相应变化。
ViewModel 层:把 View 需要的层数据暴露,并对 View 层的 数据绑定声明、 指令声明、 事件绑定声明 负责,也就是处理 View 层的具体业务逻辑。ViewModel 底层会做好绑定属性的监听。当 ViewModel 中数据变化,View 层会得到更新;而当 View 中声明了数据的双向绑定(通常是表单元素),框架也会监听 View 层(表单)值的变化。一旦值变化,View 层绑定的 ViewModel 中的数据也会得到自动更新。
修饰符分为:一般修饰符,事件修饰符,按键,系统
一般修饰符:
- .lazy:v-model在每次input事件触发后将输入框的值与数据进行同步。
.number约束用户只能输入数字类型
.trim
1.如果要自动过滤用户输入的首尾空白字符
事件修饰符
- <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>
-
- <a v-on:click.once="doThis">a>
按键修饰符
- .enter
- .tab
- .delete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
- .ctrl
- .alt
- .shift
- .meta
- 举例
- <input v-on:keyup.enter="submit"> 或者 <input @keyup.enter="submit">
以上开发中不是很常用
系统修饰键(可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或者键盘事件的监听器。)
- .ctrl
- .alt
- .shift
- .meta
- <input @keyup.alt.67="clear"> 或者 <div @click.ctrl="doSomething">Do somethingdiv>
一个元素绑定多个事件的写法
doSomething
一个元素绑定多个方法的写法
<a v-on:click="a(),b()">点我触发aba>
- <a @click="Event($event)">a>
正常情况是created先执行,因为要创建完vue之后,才能去监听数据,但在watch中设置了immediate为true这个配置时,watch就会比created先执行了,他每初始化时就会执行。
mixins称为混入对象数组
一、触发生命周期钩子函数时,先触发mixins组件中的钩子,再调用组件自身的函数。
二、当mixins数组中有watch,混入的组件中也存在watch,而且watch中的key相同时,混入组件中的watch会先触发,而后再是组件中的watch触发
三、虽然也能在建立mixin时添加data、template属性,但当组件自身也拥有此属性时以本身为准,从这一点也能看出制做者的用心(扩充)。
四、data、methods内函数、components和directives等键值对格式的对象均以组件自身或实例为准,组件自身没有定义才会去mixins混入的组件中去找。
五、watch,mixins数组中的组件和组件自身的watch会合并在一个数据中,mixins中的组件中的watch会先运行,而后再是组件自己的watch
六、mixins选项合并:当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。数据对象在内部会进行递归合并,在有同名的keys时以组件数据优先。
- var mixin = {
- created: function () { console.log(1) }
- }
- var vm = new Vue({
- created: function () { console.log(2) },
- mixins: [mixin]
- })
混入对象它可以在里面写入watch以及生命期钩子,还有data属性,计算属性,如果混入对象和组件中有相同的keys时会以组件里的数据优先。注意的时钩子函数是不进行覆盖的
extends称为继承,允许声明扩展另一个组件
- var CompA = { ... }
-
- // 在没有调用 `Vue.extend` 时候继承 CompA
- var CompB = {
- extends: CompA,
- ...
- }
mixins和extends区别
mixins混入在vue配置中接收的时一个数组(可理解为多继承),extends接收的是一个对象(单继承)
优先级的区别 extends>mixins,继承钩子函数的时候,是不进行覆盖的,extends的钩子函数先触发,而后再是mixins的钩子函数触发,最后就是组件自身的钩子函数触发。
mixins类似于面相切面的编程(AOP),extends是面向对象的编程。
补充面向切面的编程可以理解为,业务逻辑已经写在一个对象里了,然后很多组件都需要这个业务功能,如果这个组件需要用的话,直接引入就好了,这样可以很好的解决代码耦合性。
created():在Vue实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据的观测(data observer),property和方法的运算,watch/event事件的回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
activated():是在路由设置
在Vue中引入异步组件可以通过动态导入(Dynamic Import)和异步组件工厂函数(Async Component Factory Function)来实现
方法一:动态导入
在Vue中,可以使用动态导入的方式引入异步组件。动态导入是ES2015的语法特性,它可以在运行时动态地加载模块。
首先,确保你的项目支持ES2015模块语法。然后,可以使用import()函数来动态导入异步组件。假设你的异步组件文件位于AsyncComponent.vue,可以使用以下代码来引入:
- // 在需要使用异步组件的地方
- const AsyncComponent = () => import('./AsyncComponent.vue');
-
- // 在Vue组件中使用异步组件
- export default {
- // ...
- components: {
- AsyncComponent
- },
- // ...
- }
这样,AsyncComponent就成为了当前组件的一个异步组件。
方法二:异步组件工厂函数
Vue还提供了异步组件工厂函数的方法来引入异步组件。这种方法更加灵活,可以在需要时动态地加载组件。
首先,创建一个返回import()的函数,该函数返回一个Promise,Promise解析后返回异步组件。例如,假设你的异步组件文件位于AsyncComponent.vue,可以使用以下代码来引入:
- // 在需要使用异步组件的地方
- const AsyncComponent = () => ({
- component: import('./AsyncComponent.vue'),
- loading: LoadingComponent, // 可选,加载过程中显示的组件
- error: ErrorComponent, // 可选,加载失败时显示的组件
- delay: 200, // 可选,延迟显示加载组件的时间,默认200ms
- timeout: 3000 // 可选,加载超时时间,默认Infinity
- });
-
- // 在Vue组件中使用异步组件
- export default {
- // ...
- components: {
- AsyncComponent
- },
- // ...
- }
在上面的代码中,LoadingComponent和ErrorComponent是可选的,它们分别表示在加载过程中和加载失败时显示的组件。delay表示延迟显示加载组件的时间,默认为200毫秒,timeout表示加载超时时间,默认为Infinity。
无论你选择使用动态导入还是异步组件工厂函数,最终都可以在Vue组件中使用异步组件。例如,你可以在模板中这样使用:
- <template>
- <div>
- <AsyncComponent />
- div>
- template>
这样就成功引入了一个异步组件,并在Vue应用中使用它。
::v-deep+类名就可以穿透到某个类上
vue-loader 的处理阶段是在模块解析阶段之后的模块转换阶段。Vue Loader 是用于处理 Vue 单文件组件的 webpack 加载器。它会在模块转换阶段中对 Vue 单文件组件进行解析和转换操作。具体来说,vue-loader 会将 Vue 单文件组件的模板、脚本和样式进行解析,并将其转换为 JavaScript 模块,以便 webpack 可以进一步处理。
服务端渲染和预渲染的使用场景还是有较明显的区别的。预渲染的使用场景更多是我们所说的静态页面的形式。服务端渲染适用于大型的、页面数据处理较多且较为复杂的、与服务端有数据交互的功能型网站,一个明显的使用场景就是电商网站。
一、全局批量引入
创建一个.js文件,并在main.js中引入即可。
- import Vue from "vue"
- import upperFirst from "lodash/upperFirst"
- import camelCase from "lodash/camelCase"
- const requireComponent = require.context( //找到当前目录下,所有以vue,js文件结尾的,组件一个对象
- './', //组件所在目录的相对路径
- false, //是否查询其子目录
- /Base[A-Z]\w+\.(vue|js)$/ //匹配基础组件文件名的正则表达式
- )
- requireComponent.keys().forEach(fileName=>{
- // 获取文件名
- var names = fileName.split("/").pop().replace(/\.\w+$/,"");//BaseBtn
- // 获取组件配置
- const componentConfig = requireComponent(fileName);
- // 若该组件是通过"export default"导出的,优先使用".default",
- // 否则退回到使用模块的根
- Vue.component(names,componentConfig.default || componentConfig);
- })
二、局部批量引入
- <template>
- <div>
- <component v-bind:is="isWhich">component>
- div>
- template>
- <script>
- // 引入所有需要的动态组件
- const requireComponent = require.context(
- "./", //组件所在目录的相对路径
- true, //是否查询其子目录
- /\w+\.vue$/ //匹配基础组件文件名的正则表达式
- );
- var comObj = {};
- requireComponent.keys().forEach(fileName => {
- // 获取文件名
- var names = fileName
- .split("/")
- .pop()
- .replace(/\.\w+$/, "");
- // 获取组件配置
- const componentConfig = requireComponent(fileName);
- // 若该组件是通过"export default"导出的,优先使用".default",否则退回到使用模块的根
- comObj[names] = componentConfig.default || componentConfig;
- });
- export default {
- data() {
- return {
- isWhich: ""
- }
- },
- mounted() {},
- components: comObj
- };
- script>
三、动态组件使用方法
- <keep-alive>
- <component :is="isWhich">component>
- keep-alive>
使用标签保存状态,即切换组件再次回来依然是原来的样子,页面不会刷新,若不需要可以去掉。
通过事件改变is绑定的isWhich值即可切换成不同的组件,isWhich的值为组件名称。
可以使用数组中的reverse()方法让内容倒叙排列
在main.js中将axios对象放在vue实例的原型上
- beforeCreate() { //在Vue实例创建之前,添加一个全局的实例
- Vue.prototype.$http = axios
- // Vue.prototype.$bus = this; 事件总线的
- }
当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建的,就算重排,但是没有重绘。
axios的话可以用cancelToken来实现,如果时原生的XMLHttpRequest的话可以用xhr.abort()方法实现
下面时axios官网的代码
- const CancelToken = axios.CancelToken;
- const source = CancelToken.source();
-
- axios.get('/user/12345', {
- cancelToken: source.token
- }).catch(function (thrown) {
- if (axios.isCancel(thrown)) {
- console.log('Request canceled', thrown.message);
- } else {
- // 处理错误
- }
- });
-
- axios.post('/user/12345', {
- name: 'new name'
- }, {
- cancelToken: source.token
- })
-
- // 取消请求(message 参数是可选的)
- source.cancel('Operation canceled by the user.');
利用input事件,并传递数据,赋值给绑定的属性上。
不可以同名,会发生命名的冲突。因为计算属性和data都会挂在到vue实例上的。
同理method里的方法也是不能和data里的属性同名的,如果有Eslint的话会编译出错的,没有也是会发生运行时报错的。
通过prototype,定义到Vue的原型上。Vue.prototype[method]=method
插件方式: 创建一个插件,将全局方法添加到Vue的原型上,使其在所有Vue实例中可用。以下是一个示例:
- // myPlugin.js
- const MyPlugin = {
- install(Vue) {
- Vue.prototype.$myMethod = function () {
- // 全局方法的逻辑
- }
- }
- }
-
- // main.js
- import Vue from 'vue'
- import MyPlugin from './myPlugin.js'
-
- Vue.use(MyPlugin)
现在,在你的应用程序中的任何组件中,都可以通过this.$myMethod()调用全局方法$myMethod。
Mixin方式: Mixin是一种将组件选项混入到多个组件中的方式。你可以创建一个包含全局方法的Mixin,并将其混入到你的应用程序中的每个组件中。示例如下:
- // myMixin.js
- const MyMixin = {
- methods: {
- myMethod() {
- // 全局方法的逻辑
- }
- }
- }
-
- // main.js
- import Vue from 'vue'
- import MyMixin from './myMixin.js'
-
- Vue.mixin(MyMixin)
现在,你的每个组件都将继承MyMixin中定义的myMethod方法,可以通过this.myMethod()调用全局方法。
需要注意的是,插件方式和mixin方式都可以用来定义全局方法,但是插件方式更适合定义一些通用的、可复用的功能,而mixin方式更适合将特定的方法混入到多个组件中。根据你的需求和使用场景,选择适合的方式来定义全局方法。
这是因为过滤器的设计初衷是用于转换文本数据,而v-html指令用于渲染包含HTML标签的字符串,二者的使用场景不同。
主要有两种方法,在组件内处理返回一个想要的文本数据,在计算属性中处理
在组件内部处理:将过滤或转换的逻辑放在组件的方法中,在渲染之前对数据进行处理。然后,将处理后的数据绑定到v-html指令上。例如:
- <template>
- <div v-html="getFilteredHtml">div>
- template>
-
- <script>
- export default {
- data() {
- return {
- htmlContent: '
Hello, Vue.js!
' - };
- },
- methods: {
- getFilteredHtml() {
- // 进行过滤或转换的逻辑
- const filteredHtml = this.htmlContent.replace('Vue.js', 'Vue.js 2.0');
- return filteredHtml; //返回html文本数据
- }
- }
- };
- script>
使用计算属性:将过滤或转换的逻辑放在计算属性中,并将计算属性的值绑定到v-html指令上。例如:
- <template>
- <div v-html="filteredHtml">div>
- template>
-
- <script>
- export default {
- data() {
- return {
- htmlContent: '
Hello, Vue.js!
' - };
- },
- computed: {
- filteredHtml() {
- // 进行过滤或转换的逻辑
- const filteredHtml = this.htmlContent.replace('Vue.js', 'Vue.js 2.0');
- return filteredHtml;
- }
- }
- };
- script>
因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。
<img :src="require('../../../assets/images/xxx.png')" />
当使用Vue.js开发单页应用(SPA)时,由于SPA是基于JavaScript动态生成内容的,搜索引擎的爬虫在初始加载时可能无法获取到完整的页面内容。这可能导致搜索引擎无法正确地索引和展示你的应用程序。
为了解决这个问题,可以采取以下方法来进行Vue.js应用的SEO优化:
预渲染(Prerendering):预渲染是在构建阶段生成静态HTML文件,将这些静态文件作为初始页面提供给搜索引擎爬虫。这样,搜索引擎爬虫就能够获取到完整的页面内容并进行索引。你可以使用工具如Prerender SPA Plugin或Vue Prerender SPA Plugin来实现预渲染。
动态渲染(Dynamic Rendering):动态渲染是在服务器端使用类似于服务器端渲染(SSR)的技术生成静态HTML,并将其提供给搜索引擎爬虫。这样,搜索引擎爬虫可以获取到完整的页面内容。你可以使用工具如Nuxt.js来实现动态渲染。
合理使用元标签(Meta Tags):在Vue应用中,可以使用Vue的路由钩子或页面级别的组件来设置页面的元标签,包括标题(title)、描述(description)、关键字(keywords)等。这样可以让搜索引擎了解页面的相关信息,并在搜索结果中显示。
内部链接和导航:使用合适的内部链接和导航结构,使得搜索引擎爬虫能够通过链接访问到你的应用中的不同页面。确保使用标准的HTML链接,并避免使用JavaScript事件处理来实现导航。
提供站点地图(Sitemap):创建并提交站点地图给搜索引擎,以帮助搜索引擎爬虫发现和索引你的页面。站点地图应包含你应用中的所有页面的URL。
使用合适的URL结构:使用有意义、可读性好的URL结构,并尽量避免使用动态URL参数。这样有助于搜索引擎理解页面的内容,并提高页面在搜索结果中的可见性。
以上方法可以帮助你优化Vue.js应用的SEO,使搜索引擎能够正确地索引和展示你的应用程序。根据你的具体需求和项目情况,选择适合的方法或结合多种方法来进行SEO优化。
当你对Vue实例的数据进行修改时,Vue会异步地更新DOM。这意味着,如果你在数据变化之后立即去访问更新后的DOM,可能会得到一个未更新的状态。为了解决这个问题,Vue提供了$nextTick方法。
$nextTick方法接受一个回调函数作为参数,这个回调函数将在DOM更新循环结束之后被调用。这样,你就可以在回调函数中访问到更新后的DOM。
- new Vue({
- data() {
- return {
- message: 'Hello Vue!'
- };
- },
- methods: {
- updateMessage() {
- this.message = 'Updated message';
- this.$nextTick(() => {
- // DOM已更新 dom循环更新结束
- console.log('DOM updated');
- const element = document.getElementById('message'); //获取更新后的dom
- console.log(element.innerText); // 输出: "Updated message"
- });
- }
- }
- });
当你使用$nextTick时,会将回调函数添加到一个异步的更新队列中,等到Dom更新循环完在执行队列中的回调函数。
nextTick方法在源码内会通过各种方法检测DOM是否更新完成。如果有promise.then就用promise监听,没有就降级成MutationObserver,还不支持就降级setImmediate,都不支持就用setTimeout
.lazy修饰符用于延迟表单输入的事件,通常情况下用户输入,表单的v-model绑定的数据就会立即去更新。但是使用.lazy修饰符的话,他会将chang事件转换为input事件,也就是说要登input这个元素失去焦点或按下回车之后才会去更新
activated和deactivated
activated:页面第一次进入的时候,钩子的顺序是created->mounted->activated。当包含keep-alive组件被激活才会执行这个触发钩子,需要注意的是,该钩子只在组件被缓存并重新激活时触发,首次渲染时不会触发。
deactiveted:当包含keep-alive组件被停用会触deactivated,可以在这个钩子中执行一些需要在组件停用时进行的清理操作或保存状态的逻辑。
Object.assign(this.$data,this.$options.data())方法重置data
Object.assign(a,b)方法将所有可枚举属性的值从一个或多个源对象赋值到目标对象,第一个参数是目标对象,第二个是源对象。
this.$data获取当前状态下的data
this.$options.data()获取该组件初始状态下的data
- <template comments>
- ····
-
- template>
它类似轻量级的vuex,用于存储状态和管理
官方解析:返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器
如果在组件内部中进行强制刷新可以用
this.$forceUpdate()API方法
如果刷新某个子组件
v-if指令
在组件上加上key属性,当key值变更时,会自动的重新渲染
使用extends继承组件
使用HOC高阶组件+extends
使用mixin混入
组件拆分:将大型组件拆分为更小、可复用的组件,提高代码的可维护性和可测试性。
组件通信:合理使用组件通信机制,如使用props和events进行父子组件之间的通信,使用Vuex进行全局状态管理,或使用provide/inject进行跨层级组件的通信。
生命周期钩子:了解和合理使用Vue组件的生命周期钩子函数,确保在适当的时机执行必要的操作,如数据初始化、异步请求、DOM操作等。
计算属性和侦听器:使用计算属性来处理需要根据响应式数据动态计算的值,而不是在模板中直接计算。使用侦听器来监听数据的变化并执行相应的操作。
条件渲染和列表渲染:合理使用v-if、v-show和v-for指令进行条件渲染和列表渲染,避免不必要的DOM操作和性能损耗。
异步操作和副作用:在合适的生命周期钩子函数中处理异步操作和副作用,如在mounted钩子函数中进行数据请求。
样式管理:使用CSS预处理器(如Sass、Less)来管理样式,并遵循组件化的样式命名规范,避免样式冲突和污染。
代码规范和格式化:遵循一致的代码规范,并使用代码格式化工具(如ESLint、Prettier)来确保代码的一致性和可读性。
性能优化:合理使用Vue的优化技术,如利用v-if/v-else替代v-show、使用key管理列表渲染、使用懒加载和路由懒加载等,以提高应用的性能和用户体验。
错误处理和调试:捕获和处理Vue应用中的错误,使用Vue Devtools等调试工具进行应用调试和性能分析。
文档和注释:编写清晰、详细的文档和注释,使代码易于理解和维护,帮助团队成员快速上手和协作开发。
以上开发中可以做参考。
把所有需要传给父组件的参数,封装成一个对象。
这种情况先检查一下代码是否写错,若没有的话使用.native修饰符,它是用于将一个自定义事件绑定到根元素的原生DOM事件上。这意味着当触发该原生DOM事件时,同时会触发自定义事件。

它是调用了Object.keys(val)来遍历,结果会输出到一个数组里。JS的引擎不能保证输出的顺序一致
is是Vue.js中的一个动态组件特性,它允许你根据组件的属性或状态动态地选择要渲染的组件。
is特性主要用于以下几个方面:
条件渲染:你可以根据某个条件选择性地渲染不同的组件。通过在动态组件上使用is特性,你可以根据某个状态或属性的变化来切换组件的显示。
- <component :is="componentName">component>
- ```
-
- 在这个例子中,`componentName`是一个变量,它决定了要渲染的组件。当`componentName`的值发生变化时,对应的组件将被渲染。
可插拔组件:is特性使得你可以动态地切换组件,从而实现可插拔的组件系统。这对于构建可扩展的应用程序非常有用,因为它允许你根据需要添加或删除组件。
- <component :is="currentComponent">component>
- ```
-
- 在这个例子中,`currentComponent`可以根据用户的操作或其他条件的变化而改变,从而切换不同的组件。
动态表单:通过使用is特性,你可以根据用户的输入或选择来动态渲染不同类型的表单组件。这样可以使表单更加灵活和可扩展。
- <component :is="inputType">component>
- ```
-
- 在这个例子中,根据`inputType`的值的不同,可以渲染不同类型的输入组件,例如文本框、复选框或下拉列表。
以下是案例参考:
动态组件切换:
- <template>
- <div>
- <button @click="toggleComponent">Toggle Componentbutton>
-
- <component :is="currentComponent">component>
- div>
- template>
-
- <script>
- export default {
- data() {
- return {
- currentComponent: 'ComponentA'
- };
- },
- methods: {
- toggleComponent() {
- this.currentComponent = this.currentComponent === 'ComponentA' ? 'ComponentB' : 'ComponentA';
- }
- }
- }
- script>
- ```
- 在这个例子中,根据按钮的点击事件,`currentComponent`的值会在两个组件之间进行切换。
动态表单组件:
- <template>
- <div>
- <select v-model="inputType">
- <option value="text">Text Inputoption>
- <option value="checkbox">Checkboxoption>
- <option value="radio">Radio Buttonoption>
- select>
- <component :is="inputType">component>
- div>
- template>
-
- <script>
- import TextInput from './TextInput.vue';
- import Checkbox from './Checkbox.vue';
- import RadioButton from './RadioButton.vue';
-
- export default {
- components: {
- TextInput,
- Checkbox,
- RadioButton
- },
- data() {
- return {
- inputType: 'text'
- };
- }
- }
- script>
- ```
- 在这个例子中,根据`select`元素的值,选择性地渲染不同类型的输入组件。
v-once作用只渲染组件或者元素一次
当页面需要只渲染元素和组件一次的时候。相当于值改变了之后,不会更新重新渲染。这可以用于性能优化
递归组件是指组件自身在其模板中使用自身的情况。它是一种用于处理具有嵌套结构或层次关系的数据的常见技巧。
下面是一个使用递归组件的简单例子,展示了一个无限级的嵌套评论组件:
- <template>
- <div class="comment">
- <div class="comment-content">{{ comment.text }}div>
- <ul v-if="comment.replies && comment.replies.length">
- <li v-for="reply in comment.replies" :key="reply.id">
- <comment :comment="reply">comment>
- li>
- ul>
- div>
- template>
-
- <script>
- export default {
- name: 'Comment',
- props: {
- comment: {
- type: Object,
- required: true
- }
- }
- };
- script>
在这个例子中,Comment组件接收一个comment属性,该属性是一个包含评论信息的对象。在组件的模板中,它首先显示当前评论的内容,然后使用v-if指令检查是否有回复(replies),如果有,则使用v-for指令递归地渲染子评论。
使用递归组件时需要注意以下几点:
递归组件需要定义一个唯一的名称,以便在组件模板中引用自身。
递归组件需要通过递归调用自身来实现嵌套结构。
为了避免无限循环,递归组件应该有一个终止条件,通常是根据数据的某个属性判断是否继续递归下去。
在上述的评论组件示例中,终止条件是判断是否存在回复(replies),如果没有回复,则不再递归渲染子评论,从而避免了无限递归。
递归组件在处理具有层次结构的数据、树状结构或嵌套结构的场景中非常有用。它们让我们能够以一种简洁和灵活的方式处理复杂的数据结构,并且易于理解和维护。
通过this.$root这个属性
如果你使用原生的addEventListener方法来添加事件监听器,需要手动移除这些事件监听器,它们将一直存在于内存中,可能导致内存泄漏和不必要的事件处理。
因为Vue组件的生命周期管理是由Vue框架负责的,而不是由原生的事件监听器管理。
手动销毁的方法,再beforeDestory钩子中执行removeEventListeners方法
- <template>
- <button ref="myButton">Click Mebutton>
- template>
-
- <script>
- export default {
- mounted() {
- this.$refs.myButton.addEventListener('click', this.handleClick);
- },
- beforeDestroy() {
- this.$refs.myButton.removeEventListener('click', this.handleClick);
- },
- methods: {
- handleClick() {
- console.log('Button clicked!');
- }
- }
- };
- script>
JSX,是一种语法糖。可以再js中编写像html一样的代码。一般再React开发中用到
:class可以绑定一个变量,对象,绑定一个数组,绑定一个三元表达式 (注意的是绑定对象是,key为类名,值是布尔值,真代表添加这个key,否则不添加这个key)
:style可以绑定一个变量,对象,绑定函数的返回值,绑定一个三元表达式
函数式组件顾名思义就是调用一个函数来创建一个组件
可以使用createElement函数,它接受三个参数
tag :是html标签名或者自定义组件
data: 一个包含了元素的属性、事件监听器、样式等信息的对象(props,on自定义事件)
children:表示元素的子节点。它可以是一个字符串、一个数组或其他createElement调用的结果。
以下是一个创建了一个有属性和样式的button元素
- createElement('button', {
- attrs: {
- id: 'myButton',
- disabled: true
- },
- style: {
- color: 'red',
- backgroundColor: 'lightgray'
- },
- on: {
- click: event=>console.log(event)
- }
- }, 'Click me')
-
简单的创建其他组件
- //创建一个简单的div
- createElement('div', 'Hello, world!')
- //包含子节点的
- createElement('ul', [
- createElement('li', 'Item 1'),
- createElement('li', 'Item 2'),
- createElement('li', 'Item 3')
- ])
安装必要的依赖
- npm install vue@2 vue-class-component vue-property-decorator --save
- npm install typescript ts-loader --save-dev
创建配置tsconfig.json文件
- //tsconfig.json
- {
- "compilerOptions": {
- "target": "es5",
- "module": "es2015",
- "strict": true,
- "esModuleInterop": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "noImplicitAny": false,
- "allowSyntheticDefaultImports": true
- },
- "include": [
- "src/**/*.ts",
- "src/**/*.vue",
- "tests/**/*.ts",
- "tests/**/*.vue"
- ],
- "exclude": [
- "node_modules"
- ]
- }
- declare module '*.vue' {
- import Vue from 'vue';
- export default Vue;
- }
4. Vue文件中的script类型设置为ts
- <template>
- <div>
- <h1>{{ message }}h1>
- div>
- template>
-
- <script lang="ts">
- import { Vue, Component } from 'vue-property-decorator';
- // @Component 修饰符注明了此类为一个 Vue 组件
- @Component
- export default class MyComponent extends Vue {
- message: string = 'Hello, TypeScript!';
- }
- script>
vue作者有说过,全局事件挂载vue实例上的事件,不会自动销毁,只能手动销毁事件。做法是在当前组件销毁时把这个全局事件使用$off()函数
- beforeDestory(){
- this.$off("EventName",this.myhandle)
- //关闭EventName全局事件,第二个参数是一个可选的回调函数。如果提供了回调函数,只会取消指定事件名称和该回调函数的监听器。
- }
provide是给所有子孙组件的提供一些数据属性和事件的,而inject注入是子组件用于接收父组件传过来的数据和事件。
String,Boolean,Number,Object,Array,Function,Promise
可以,设置default属性Number和String可以正常设置,对象和数组需要使用工厂函数来返回默认值的内容,以及定义自定义的验证函数,以验证props传递的值是否符合特定的条件。通过自定义验证函数,我们可以对props的值进行更精确的验证和限制。
- arrProp: {
- type: Array,
- default: () => ({ key: 'value' }),
- },
自定验证函数validator
- props: {
- username: {
- type: String,
- validator: (value) => {
- // 自定义验证函数
- return value.length >= 4 && value.length <= 10;
- },
- },
- },
需要注意的是,自定义验证函数应该返回一个布尔值(true或false)。如果返回true,表示验证通过;如果返回false,表示验证失败。