网站建设费用包括哪些,如何建立外贸网站,厦门建设局长是谁,如何刷网站流量1.vue2和vue3的区别#xff08;vue3与vue2的区别#xff08;你不知道细节全在这#xff09;_vue2和vue3区别-CSDN博客#xff09;参考
Vue3 在组合式#xff08;Composition #xff09;API#xff0c;中使用生命周期钩子时需要先引入#xff0c;而 Vue2 在选项APIvue3与vue2的区别你不知道细节全在这_vue2和vue3区别-CSDN博客参考
Vue3 在组合式Composition API中使用生命周期钩子时需要先引入而 Vue2 在选项APIOptions API中可以直接调用生命周期钩子
// vue3
script setup
import { onMounted } from vue; // 使用前需引入生命周期钩子onMounted(() {// ...
});// 可将不同的逻辑拆开成多个onMounted依然按顺序执行不会被覆盖
onMounted(() {// ...
});
/script// vue2
script
export default { mounted() { // 直接调用生命周期钩子 // ... },
}
/script vue2只能有一个根节点vue3支持多个根节点 vue2和vue3的响应式原理 浅析一下vue2.0 和 vue3.0 响应式原理 - 掘金 (juejin.cn)参考 Vue 2 的响应式原理 在 Vue 2 中响应式系统是基于 Object.defineProperty 实现的。当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项Vue 将遍历此对象所有的属性并使用 Object.defineProperty 把这些属性全部转为 getter/setter使数据变得“响应式”。 getter用于依赖收集。当组件渲染时会访问到这些数据此时 Vue 会记录这些组件作为依赖。setter当数据改变时setter 会被触发然后通知所有依赖这个数据的组件重新渲染。 此外Vue 2 提供了 watch 选项用于观察和响应 Vue 实例上的数据变动。但 watch 本身并不是响应式系统的核心部分它只是 Vue 提供的一个工具用于在数据变化时执行异步或开销较大的操作。 Vue 3 的响应式原理 在 Vue 3 中响应式系统得到了重构基于 ES2015 的 Proxy 对象来实现。相比于 Object.definePropertyProxy 提供了更多的灵活性可以监听对象属性的添加、删除、修改等操作。 ProxyVue 3 使用 Proxy 来包装原始数据对象创建一个代理对象。这个代理对象会拦截对原始数据的读取和修改操作并在需要时触发相应的响应式逻辑。 Vue 3 提供了 ref 和 reactive 两个函数来创建响应式数据。 ref用于创建基本类型如数字、字符串等的响应式引用。ref 返回的是一个对象其 value 属性包含实际的值。reactive用于创建复杂类型如对象、数组等的响应式引用。reactive 返回的是一个代理对象可以直接操作这个代理对象来修改原始数据。 总结 Vue 2 的响应式系统基于 Object.defineProperty通过 getter/setter 来实现数据的依赖收集和变化通知。Vue 3 的响应式系统基于 Proxy提供了更强大的数据监听能力。它使用 ref 和 reactive 来创建响应式数据。 watch 在 Vue 2 和 Vue 3 中都是存在的但它并不是响应式系统的核心部分而是一个用于观察数据变化并触发相应逻辑的工具。 vue2 Object.defineProperty 和 vue 3 Proxy 区别 Object.defineProperty数据劫持 Proxy数据代理 语法Proxy构造函数var proxy new Proxy(target, handler); 常用生命周期对比如下表所示 vue2和vue3的监听有什么区别 Vue2和Vue3在监听功能上存在一些明显的区别这些区别主要体现在监听机制、语法和性能优化等方面。以下是详细的比较 监听机制 Vue2使用Object.defineProperty进行数据的劫持实现双向绑定。但这种方式对于新添加的属性无法直接进行监听需要通过Vue.set或this.$set方法手动添加响应式属性。 在Vue 2中如果你需要在数据对象上添加新的属性并且希望这个新属性也是响应式的即当它的值改变时视图也会更新你需要使用Vue.set方法或实例的this.$set方法。这是因为Vue 2使用Object.defineProperty来劫持对象的属性但这种方式只能对已经存在的属性进行劫持对于后来添加的属性则无法直接进行劫持。下面是一个使用Vue.set或this.$set添加响应式属性的例子
new Vue({ el: #app, data: { // 初始数据对象 person: { name: John, age: 30 } }, mounted() { // 使用 Vue.set 添加响应式属性 Vue.set(this.person, address, 123 Street); // 或者使用实例的 $set 方法添加响应式属性 // this.$set(this.person, city, New York); }
});
在上面的例子中person对象最初只有两个属性name和age。在组件挂载后mounted钩子中我们使用Vue.set方法向person对象添加了一个新属性address。现在address是一个响应式属性当它的值改变时任何依赖于它的视图都会更新。如果你使用的是Vue实例内部更常见的是使用this.$set方法因为this指向了Vue实例本身
mounted() { this.$set(this.person, city, New York);
} Vue3则采用了Proxy来代理对象它可以直接监听对象上的所有属性包括后续添加的属性无需手动添加响应式属性。 在Vue 3中由于使用了Proxy来创建响应式对象你可以直接向数据对象添加新属性而不需要使用Vue.set或this.$set。Proxy会拦截对对象属性的访问和修改使得新添加的属性也能保持响应式。以下是一个Vue 3的示例展示如何在组件中直接添加新属性
template div pName: {{ person.name }}/p pAge: {{ person.age }}/p pNew Property: {{ person.newProperty }}/p button clickaddNewPropertyAdd New Property/button /div
/template script
import { ref, onMounted } from vue; export default { setup() { const person ref({ name: John, age: 30 }); // 添加新属性的方法 function addNewProperty() { // 直接添加新属性不需要使用Vue.set或this.$set person.value.newProperty This is a new property!; } onMounted(() { // 组件挂载后你可以看到新属性已经被添加并且是响应式的 console.log(person.value.newProperty); // 初始为undefined因为还没有添加 }); // 直接调用方法来添加新属性 addNewProperty(); return { person, addNewProperty }; }
};
/script
在上面的示例中我们定义了一个响应式对象person并在addNewProperty方法中直接向其添加了一个新属性newProperty。当按钮被点击时这个新属性就会被添加到person对象中并且因为它是直接添加到响应式对象上的所以它是响应式的——即当它的值改变时视图也会自动更新。请注意虽然你不需要使用Vue.set或this.$set来添加新属性但如果你想要确保在添加新属性时触发视图更新即使新属性的值没有变化你可能需要强制Vue重新评估相关的计算属性或方法。这通常不是必要的因为当你直接修改响应式对象的属性时Vue会自动触发必要的更新。 监听语法 Vue2中的监听主要通过watch选项或this.$watch方法来实现用于监听data中的属性变化并在变化时执行相应的回调函数。Vue3同样提供了watch和watchEffect函数来监听数据变化但它们的用法更加灵活和强大。watch函数可以监听特定的数据源并在其变化时执行回调函数而watchEffect则会自动收集其依赖并在依赖变化时重新执行该函数。深度监听与立即执行 在Vue2中使用watch监听对象时如果需要深度监听对象内部属性的变化需要设置deep: true选项。另外如果需要监听器在创建时立即执行一次可以设置immediate: true选项。Vue3中的watch函数也支持深度监听和立即执行但语法和用法可能与Vue2有所不同。以下是Vue 2和Vue 3中watch的示例代码以展示深度监听和立即执行的不同语法和用法 在Vue 2中你可以使用watch选项来监听数据的变化并可以通过设置deep: true来实现深度监听以及设置immediate: true来让监听器在创建时立即执行一次。new Vue({ el: #app, data: { obj: { a: 1, b: 2 } }, watch: { obj: { handler(newVal, oldVal) { console.log(obj changed); // 注意这里不会深度监听obj内部属性的变化 }, deep: true, // 深度监听 immediate: true // 立即执行 } }, created() { // 由于设置了immediate: true这里会打印obj changed }
});
但是请注意上面的watch只会告诉你obj对象本身是否发生了变化比如是否替换了整个对象而不是它内部属性的变化。要监听obj内部属性的变化你需要一个更具体的watch或者使用computed属性来配合。 在Vue 3中watch函数的使用方式有所不同并且更灵活。你可以通过watch函数来监听单个数据或计算属性也可以监听多个数据源。以下是Vue 3中深度监听和立即执行的示例
import { ref, watch, onMounted } from vue; export default { setup() { const obj ref({ a: 1, b: 2 }); // 使用watch函数来监听obj的变化并设置深度监听和立即执行 watch( () obj.value, // 监听obj.value的变化 (newVal, oldVal) { console.log(obj changed, newVal, oldVal); }, { deep: true, // 深度监听obj内部属性的变化 immediate: true // 立即执行监听器 } ); // 注意由于Vue 3的setup是同步执行的immediate: true会在watch函数被调用时立即执行 onMounted(() { // setup中的代码是同步执行的所以这里不会看到因为immediate: true而打印的日志 }); return { obj }; }
};
在Vue 3中watch函数接受三个参数第一个参数是监听的数据源可以是一个getter函数也可以直接是ref或reactive对象的属性。
第二个参数是当数据源变化时要执行的回调函数。
第三个参数是一个选项对象其中可以包含deep和immediate等选项。
请注意Vue 3的setup函数是同步执行的所以immediate: true会在watch函数被调用时立即执行而不是在组件挂载onMounted时。 性能优化 Vue2的监听机制在性能上可能存在一定的开销尤其是在处理大量数据或复杂逻辑时。Vue3通过引入Proxy和Composition API等新技术对性能进行了优化和提升使得监听功能更加高效和灵活。其他特性 Vue3中的监听功能还支持一些其他特性如监听多个数据源、使用异步函数作为回调函数等。这些特性使得Vue3的监听功能更加强大和灵活。 综上所述Vue2和Vue3在监听功能上存在明显的区别。Vue3通过引入Proxy和Composition API等新技术对监听机制进行了改进和优化使得其性能更加高效、语法更加灵活、功能更加强大。因此在开发Vue项目时建议根据项目需求和技术栈选择合适的Vue版本进行使用。 2.vue2和vue3中组件之间的传值方式
1.父传子
v2和v3的父传子差不多
// ParentComponent.vue
template ChildComponent :messageparentMessage / 父组件定义的变量parentMessage用message来绑定
/template script
import ChildComponent from ./ChildComponent.vue; export default { components: { ChildComponent }, data() { return { parentMessage: Hello from Parent }; }
};
/script // ChildComponent.vue
template div{{ message }}/div
/template script
export default { props: [message] 用props来接收父组件绑定的方法
};
/script
2.子传父
子传父
// ChildComponent.vue
template button clicknotifyParentNotify Parent/button
/template script
export default { methods: { notifyParent() { this.$emit(child-event, Hello from Child); //点击按钮传递一个叫child-event的内容为Hello from Child} }
};
/script // ParentComponent.vue
template ChildComponent child-eventhandleChildEvent / //父组件绑定的方法和子组件传递过来的名字一样父组件用handleChildEvent方法接收打印出来
/template script
import ChildComponent from ./ChildComponent.vue; export default { components: { ChildComponent }, methods: { handleChildEvent(message) { console.log(message); // Hello from Child } }
};
/script 3.vuex
Vuex 示例这通常涉及到更多的代码这里只给出大致的概念
// store.js
import Vue from vue;
import Vuex from vuex; Vue.use(Vuex); export default new Vuex.Store({ state: { message: Hello from Vuex }, mutations: { updateMessage(state, payload) { state.message payload; } }
}); // 在组件中
this.$store.commit(updateMessage, New message);
// 在模板中
{{ $store.state.message }}
4.Vue3组件通信之一_provide()与inject()依赖注入函数Provide / Inject (依赖注入)
Vue3组件通信之一_provide()与inject()依赖注入函数-CSDN博客参考
// ParentComponent.vue (或更高层级的组件)
script
export default { provide() { return { message: Hello from Provide/Inject }; }
};
/script // ChildComponent.vue (或任意深层的组件)
script
export default { inject: [message], mounted() { console.log(this.message); // Hello from Provide/Inject }
};
/script 3.路由守卫Vue路由守卫详解-CSDN博客 Vue路由守卫是Vue Router提供的一种机制允许开发者在路由跳转前后执行一些逻辑判断或操作以确保应用程序的导航逻辑正确性和增强用户体验。以下是关于Vue路由守卫的详细解释 一、路由守卫的概念 路由守卫Route Guards是Vue Router中的一个功能允许我们在路由发生之前、之中、之后执行逻辑检查和操作。这些守卫可以用来实现权限验证、页面访问控制、数据预加载等逻辑确保用户在应用中的导航流程符合业务需求。 二、路由守卫的分类 Vue路由守卫主要分为以下三种类型 全局守卫 beforeEach(to, from, next)全局前置守卫在路由进入之前调用。常用于权限验证如果用户未登录可以重定向到登录页面。每个守卫方法接收三个参数to即将进入的目标路由对象、from当前导航正要离开的路由对象、next必须调用的函数来解析这个钩子。beforeResolve(to, from, next)全局解析守卫在路由解析之前调用它在beforeEach之后和afterEach之前调用。afterEach(to, from)全局后置守卫在路由跳转完成后调用通常用于记录日志或执行一些全局操作。路由独享守卫 beforeEnter(to, from, next)在路由配置中直接定义这些守卫只适用于特定的路由。组件内守卫 beforeRouteEnter(to, from, next)在渲染该组件的对应路由被确认前调用不能访问组件实例 (this)。beforeRouteUpdate(to, from, next)在当前路由改变但是该组件被复用时调用例如对于带有动态参数的路由。beforeRouteLeave(to, from, next)导航离开该组件的对应路由时调用。 三、路由守卫的使用 全局守卫示例 router.beforeEach((to, from, next) { // 进行权限验证等操作 if (to.meta.requireAuth) { if (localStorage.getItem(token)) { next(); } else { next({ path: /login, query: { redirect: to.fullPath } }); } } else { next(); }
}); 路由独享守卫示例 const router new VueRouter({ routes: [ { path: /admin, component: Admin, beforeEnter: (to, from, next) { // 进行权限验证等操作 // ... } } ]
}); 组件内守卫示例 export default { beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被确认前调用 // 注意这里不能访问组件实例 (this) // ... next(); }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // ... next(); }
} 四、总结 Vue路由守卫是Vue Router提供的一个强大功能通过它我们可以在路由跳转前后执行逻辑检查和操作以确保应用程序的导航逻辑正确性和增强用户体验。开发者可以根据具体需求选择使用全局守卫、路由独享守卫或组件内守卫。 4.webpack和vite的配置 webpack 与 vite的区别_webpack和vite的区别-CSDN博客 Vue2的打包方式 Vue2项目通常使用Webpack作为构建工具进行打包。Webpack是一个模块打包器可以将项目中的多个模块打包成一个或多个bundle供浏览器使用。在Vue2项目中Webpack的配置通常位于vue.config.js文件中或者通过其他方式进行配置。 在Vue2项目中打包过程可能包括以下几个步骤 设置路由模式根据项目需求选择hash模式或history模式。性能分析和CDN应用使用Vue CLI提供的性能分析工具对项目进行打包分析并根据需要将一些大文件或库文件通过CDN引入以减轻服务器负担和提高加载速度。Webpack配置通过vue.config.js或其他方式配置Webpack包括入口文件、输出目录、加载器loader和插件等。 Vue3的打包方式 Vue3项目在打包方式上与Vue2类似但也有一些新的特性和工具可以使用。 使用ViteVite是一个由原生ESM驱动的Web开发构建工具它提供了更快的冷启动速度、即时的热模块替换HMR和真正的按需编译。目前Vite主要用于Vue3项目因为它针对Vue3做了优化。使用Vite可以更快地构建和开发Vue3项目。Webpack虽然Vite是Vue3的推荐构建工具但Webpack仍然可以用于Vue3项目。在Vue3项目中Webpack的配置和使用方式与Vue2类似但可能需要针对Vue3的一些新特性进行调整。cross-env在Vue3项目中可以使用cross-env进行分环境配置根据不同的环境使用不同的接口和配置。这有助于更好地管理不同环境下的项目配置和依赖。 总结 Vue2主要使用Webpack作为构建工具进行打包配置方式相对传统和灵活。Vue3推荐使用Vite作为构建工具因为它提供了更快的构建速度和更好的开发体验。但Webpack仍然可以用于Vue3项目只是可能需要一些额外的配置和调整。 5.es6新语法有哪些20分钟上手ES6不会ES6好意思说自己会JS _const m (l r) 1;-CSDN博客
JavaScript高级——ES6基础入门_js es6-CSDN博客
ES6常用方法 总结大全_es6常用的方法-CSDN博客
6.vue中使用keep-alive进行组件缓存Keep-alive组件缓存的使用_keepalive: false-CSDN博客参考
keep-alive是Vue提供的一个内置组件被keep-alive组件包裹的内部组件其状态将被缓存 keep-alive包裹的组件其生命周期只能被执行一次再次进入时不会被执行 keep-alive包裹的组件会自动新增两个生命周期函数activated和deactivated每次进入都会被执行 activated( ) 当keepalive包含的组件再次渲染时触发 deactivated( ) 当keepalive包含的组件销毁时触发 keep-alive两个属性include和exclude,可以让keep-alive实现有条件的进行缓存。include匹配到的组件会被进行缓存exclude匹配到的组件不会被缓存
7. 计算属性computed和watch的区别
computed计算属性和watch侦听器的区别_watch和计算属性的区别-CSDN博客
计算属性Computed Properties
计算属性是基于它们的依赖进行缓存的。只有在它的相关依赖发生改变时才会重新求值。
template div p原始价格: {{ price }}/p p优惠价格: {{ discountedPrice }}/p /div
/template script
export default { data() { return { price: 100, discount: 0.1 // 10% 的折扣 }; }, computed: { discountedPrice() { // 当 price 或 discount 发生变化时这个函数才会重新计算 return this.price * (1 - this.discount); } }
};
/script
侦听器Watchers
侦听器允许你执行异步或开销较大的操作并可以访问数据变化的先前值和当前值。
template div input v-modelsearchQuery placeholder搜索... /div
/template script
export default { data() { return { searchQuery: }; }, watch: { // 当 searchQuery 发生变化时这个函数会被调用 searchQuery(newVal, oldVal) { // 这里可以执行一些异步操作比如 API 请求 console.log(搜索查询已更改: ${oldVal} - ${newVal}); // 模拟 API 请求 setTimeout(() { console.log(搜索结果为: ${newVal}); }, 1000); } }
};
/script 8.闭包和作用域 闭包
1.内部函数可以访问外部函数的局部变量。
2.外部函数嵌套内部函数
3.内部函数可以使用外部函数的局部变量
手写一个闭包
function makeSizer(size){
return function(){
docoment.body.style.fontsizesizepx;}
}
var size12makeSizer(12);//size12指向的函数可以设置body的fontSize为12px
var size14makeSizer(14);//size14指向的函数可以设置body的fontSize为14px
var size16makeSizer(16);//size16指向的函数可以设置body的fontSize为16px 作用域 作用域Scope 作用域指的是变量、函数和表达式在代码中的可访问性范围。换句话说它决定了在代码的不同部分哪些变量、函数或表达式是可见即可被访问和使用的。 在JavaScript以及其他许多编程语言中作用域主要有两种全局作用域和局部作用域包括函数作用域、块级作用域等。 全局作用域 定义在代码的任何地方都能访问到的变量或函数位于全局作用域中。在浏览器中全局作用域对应window对象。优点全局变量或函数可以在整个代码库中被访问这使得它们在某些情况下如跨多个函数或模块共享数据非常有用。缺点 过度使用全局变量可能导致命名冲突因为不同的脚本或模块可能会意外地使用相同的变量名。全局变量难以追踪和管理因为它们可以在任何地方被修改。可能导致意外的副作用因为对全局变量的修改可能会影响到代码的其他部分。 局部作用域 定义在特定的代码块如函数或块级作用域的大括号内中定义的变量或函数只在该代码块内可见。优点 减少了命名冲突的可能性因为每个局部变量都只在自己的作用域内存在。提高了代码的可读性和可维护性因为开发者可以更容易地理解每个变量或函数的作用和用途。减少了意外的副作用因为对局部变量的修改不会影响到代码的其他部分除非通过特定的机制如闭包。缺点在大型或复杂的代码中过多的嵌套作用域可能会使代码变得难以理解和跟踪。然而这通常可以通过良好的代码结构和模块化来解决。 块级作用域ES6 ES6ECMAScript 2015引入了let和const关键字它们提供了块级作用域。这意味着使用let或const声明的变量只在其所在的代码块例如if语句、for循环或任何由大括号{}包围的代码块内可见。 优点 提供了更细粒度的作用域控制有助于减少命名冲突和意外的副作用。使得代码更加清晰和可维护。 缺点 对于不熟悉ES6语法的开发者来说可能需要一些时间来适应新的作用域规则。在某些旧的浏览器或环境中可能不受支持需要进行兼容性处理。 9.防抖节流
防抖当事件被触发后延迟n秒再执行核心代码如果在这n秒内再次被触发就重新计时像王者里面的回城一样
场景可以使用防抖技术优化搜索框建议词列表展示功能
手写防抖
//定义一个变量指向延时器
var timenull;
//某事件会触发的回调函数
function doSomething(){
//先删除有可能已存在的延时器
clearTimeout(timer)
//创建新的延时器
timeseTimeout(function(){
//真正要执行的核心代码或者调用核心函数
//code
console.log(核心代码)},500)
}
节流是一种有效降低单位时间内核心代码执行次数的机制
场景如果事件被频繁触发节流能减少事件触发的频率因此节流是有选择性的执行一部分事件如使用节流优化滚动条事件的监听避免滚动事件的回调函数太过频繁执行
手写
function throttle(func, delay) { let lastCall 0; return function() { const now new Date().getTime(); if (now - lastCall delay) { return; } lastCall now; return func.apply(this, arguments); };
}
//可以像这样使用这个简化版的节流函数
const throttledScrollHandler throttle(function() { console.log(Scrolled!);
}, 250); // 每250毫秒最多执行一次 window.addEventListener(scroll, throttledScrollHandler);
9.模块化开发 和 面向对象编程 模块化开发 和 面向对象编程 是两种不同的编程概念它们各自在软件开发中扮演着重要的角色。 模块化开发Modular Programming 定义模块化开发是一种将程序划分为多个独立模块的开发方法。每个模块都具有特定的功能和接口模块之间通过接口进行通信实现代码的解耦和复用。优点 代码复用通过重用现有的模块可以提高开发效率减少代码冗余。易于维护由于每个模块具有明确的功能和接口因此可以单独测试和维护每个模块降低维护成本。易于扩展当需要添加新功能时可以通过添加新的模块或修改现有模块的接口来实现。实现方式在多种编程语言中如JavaScript、Python、Java等都支持模块化编程。具体的实现方式可能因语言而异但通常包括将代码组织成函数、类、包或模块等。 面向对象编程Object-Oriented Programming, OOP 定义面向对象编程是一种编程范式它将现实世界中的事物抽象为对象并使用类和对象等概念来设计和组织程序。在面向对象编程中数据和操作数据的方法被封装在对象中对象之间通过消息传递进行通信。核心概念 类Class定义对象的属性和方法的模板。对象Object类的实例化具有类的属性和方法。继承Inheritance子类继承父类的属性和方法实现代码的重用。多态Polymorphism不同的对象对同一消息做出不同的响应。封装Encapsulation将数据和方法封装在对象中隐藏对象的内部实现细节。优点 易于理解和维护由于面向对象编程将现实世界中的事物抽象为对象因此代码更易于理解和维护。易于扩展通过继承和多态等机制可以方便地扩展和修改程序的功能。易于复用通过封装和继承等机制可以实现代码的复用和共享。实现方式在多种编程语言中如Java、C、Python等都支持面向对象编程。这些语言提供了类和对象等概念以及继承、多态和封装等机制来实现面向对象编程。对于上面第2点不清楚的延伸什么是继承和封装 继承 和 封装 是面向对象编程OOP中的两个核心概念。 继承Inheritance定义继承是面向对象编程中的一个重要特性它允许一个类称为子类或派生类继承另一个类称为父类或基类的属性和方法。通过继承子类可以重用父类的代码并且可以添加或覆盖父类的行为以定义新的行为。 作用 代码重用子类可以继承父类的所有公共和受保护的属性和方法从而避免了重复编写相同的代码。扩展性子类可以在继承父类的基础上添加新的属性和方法或者覆盖父类的方法以实现不同的行为。多态性的基础继承是多态性的前提子类对象可以当作父类对象使用从而在运行时确定实际调用的方法动态绑定。 封装Encapsulation 定义封装是面向对象编程中的另一个核心概念它指的是将数据属性和操作这些数据的方法函数绑定在一起作为一个整体即对象来处理。封装隐藏了对象的内部状态和实现细节只对外提供必要的接口来访问和操作对象。作用 数据保护通过封装可以确保对象内部数据的完整性和安全性。外部代码只能通过对象提供的公共方法来访问或修改对象的属性从而防止了直接访问和修改对象内部数据的可能性。提高可维护性封装使得对象的内部实现细节对外部是隐藏的。这意味着如果对象的内部实现发生变化只要不改变对外提供的接口外部代码就无需修改。这大大提高了代码的可维护性。模块化设计封装有助于将复杂系统划分为更小的、更易于管理的模块。每个模块都有明确的接口和职责从而降低了系统的复杂性。 总的来说继承和封装是面向对象编程中非常重要的概念它们有助于提高代码的重用性、可扩展性和可维护性。 10.作为一个前端怎么处理图片也就是怎么实现图片懒加载 图片懒加载Lazy Loading是一种优化网页性能的技术它的核心思想是只在用户滚动到视图内时才开始加载图片而不是一开始就加载所有图片。这可以大大减少页面初始加载时间并降低服务器负载。作为一个前端开发者你可以通过以下步骤实现图片懒加载 设置占位图 在图片的原始位置放置一个占位图或者空白区域这样在页面初次加载时不会请求实际的图片资源。 检测滚动和视图 使用JavaScript监听页面的滚动事件并判断图片元素是否进入可视区域。这通常通过计算元素的位置与当前视口viewport的位置关系来实现。 动态加载图片 当图片元素进入可视区域时通过修改图片的src属性来触发图片的加载。为了避免页面重新布局可以先将图片的真实URL存储在一个自定义属性如data-src中然后在需要时将其赋值给src属性。 处理加载状态 在图片加载过程中你可能希望显示一个加载指示器如加载动画。当图片加载完成后可以通过监听图片的load事件来隐藏加载指示器。 优化和回退 考虑到一些浏览器可能不支持JavaScript或图片懒加载技术你应该提供一个回退方案比如使用noscript标签来包含普通的img元素以确保在非JavaScript环境下图片仍然能够正常显示。 使用现代浏览器特性 一些现代浏览器支持原生的图片懒加载功能例如通过为img标签添加loadinglazy属性。这可以简化实现并提高效率但你需要确保在不支持该属性的浏览器上有适当的回退策略。 库和插件 如果你不想从头开始实现图片懒加载可以考虑使用现有的JavaScript库或插件如lazyload.js、lozad.js等。这些库通常提供了丰富的配置选项和事件处理机制可以方便地集成到你的项目中。 响应式图片 在实现图片懒加载的同时不要忘记考虑响应式图片的需求。你可以使用picture元素和source元素来提供不同尺寸和分辨率的图片版本以适应不同的设备和屏幕尺寸。 测试和优化在实现图片懒加载后务必进行充分的测试以确保在各种设备和浏览器上都能正常工作。此外你还可以使用性能分析工具来检查图片加载对页面性能的影响并根据需要进行优化。 案例演示 1.使用HTML的loading属性 实现方式 在img标签中添加loadinglazy属性。浏览器会自动延迟加载设置了此属性的图片直到它们接近视口viewport为止。示例代码 img srcreal-image.jpg altLazy loaded image loadinglazy 注意事项 此方法依赖于浏览器的支持一些较旧的浏览器可能不支持loading属性。需要确保在不支持此属性的浏览器中有一个回退方案。 2. 使用JavaScript监听滚动事件 实现原理 监听页面的滚动事件scroll。当图片进入可视区域时将图片的src属性设置为真实的图片地址。示例代码简化版 img srcplaceholder.jpg data-srcreal-image.jpg altLazy loaded image classlazy script
// 监听滚动事件
window.onscroll function() { // 获取所有带有lazy类的图片元素 var lazyImages document.getElementsByClassName(lazy); // 遍历图片元素检查是否在可视区域 // ...此处省略具体的实现逻辑 // 如果在可视区域则替换src属性 lazyImage.src lazyImage.dataset.src;
};
/script 注意事项 监听滚动事件并计算图片位置可能会对性能产生影响特别是在有大量图片的情况下。可以使用防抖debounce或节流throttle技术来优化性能。 3. 使用Intersection Observer API 3.实现原理 Intersection Observer API 可以异步观察目标元素与其祖先元素或顶级文档视口的交叉状态。当目标元素的可见性发生变化时会触发一个回调函数。 示例代码简化版 var lazyImages document.querySelectorAll(img.lazy); if (IntersectionObserver in window) { let lazyImageObserver new IntersectionObserver(function(entries, observer) { entries.forEach(function(entry) { if (entry.isIntersecting) { let lazyImage entry.target; lazyImage.src lazyImage.dataset.src; lazyImageObserver.unobserve(lazyImage); } }); }); lazyImages.forEach(function(lazyImage){ lazyImageObserver.observe(lazyImage); });
} 注意事项 Intersection Observer API 提供了更好的性能和更简洁的代码。同样需要注意浏览器兼容性。 4. 使用第三方库 实现方式 使用如lazyload.js、lozad.js等第三方库来实现图片懒加载。这些库通常提供了丰富的配置选项和事件处理机制。注意事项 引入第三方库可能会增加项目的依赖和大小。需要确保所选的库与你的项目兼容并仔细阅读其文档以了解如何配置和使用。 以上是实现图片懒加载的几种常见方式你可以根据自己的需求和项目环境选择适合的方法。 延伸怎么用防抖debounce或节流throttle技术来优化图片懒加载性能
好处防抖debounce和节流throttle技术都是用于优化高频率触发事件如滚动事件的性能的手段。在图片懒加载的场景中我们可以使用这些技术来减少不必要的计算和DOM操作从而提升性能。
防抖的基本思想是设置一个定时器在事件被触发后n秒内函数只能执行一次如果在这n秒内又被重新触发则重新计算执行时间。在图片懒加载中我们可以使用防抖来确保在滚动停止后才开始检查图片是否在视口内。
function debounce(func, wait) { let timeout; return function executedFunction(...args) { const context this; clearTimeout(timeout); timeout setTimeout(() func.apply(context, args), wait); };
} // 使用防抖的图片懒加载函数
const checkLazyImages debounce(function() { // 检查并加载视口内的图片 // ...
}, 200); // 设置防抖时间为200毫秒 window.addEventListener(scroll, checkLazyImages); 节流的基本思想是设置一个冷却时间在事件被触发后n秒内只执行一次之后在这n秒内无论事件被触发多少次函数都不会执行。在图片懒加载中我们可以使用节流来确保检查图片是否在视口内的函数不会过于频繁地执行。
function throttle(func, limit) { let inThrottle; return function executedFunction(...args) { const context this; if (!inThrottle) { func.apply(context, args); inThrottle true; setTimeout(() inThrottle false, limit); } };
} // 使用节流的图片懒加载函数
const checkLazyImages throttle(function() { // 检查并加载视口内的图片 // ...
}, 200); // 设置节流间隔为200毫秒 window.addEventListener(scroll, checkLazyImages);
注意事项
在实际应用中防抖和节流的选择取决于具体的需求。如果你希望在用户停止滚动后一次性加载所有图片那么防抖可能更合适。如果你希望保持一定的加载频率无论用户是否停止滚动那么节流可能更合适。在实现防抖和节流函数时注意保持对原始函数上下文this和参数的引用。还可以使用已经实现了防抖和节流功能的库如lodash的_.debounce和_.throttle方法以避免重复造轮子。在图片懒加载的实现中除了使用防抖和节流外还可以考虑使用Intersection Observer API来更高效地检测图片是否进入视口。
11.vue3 toRef和toRefs的使用和区别
ref、reactive、toRef、toRefs的区别_ref和reactive,toref的区别-CSDN博客参考 toRef和toRefs在Vue 3中都是用于处理响应式数据的重要API但它们之间有着明显的区别。以下是它们之间的主要区别 功能与作用 toRef此函数用于将对象中的某个属性转化为响应式引用。它接收两个参数一个对象和一个字符串键名。这个键名指定了要从该对象中提取并转化为响应式引用的属性。例如let nameRef toRef(obj, name)。toRefs此函数用于将一个响应式对象转换为一个普通对象其中该对象的每个属性都是指向原始对象属性的响应式引用。这通常用于在模板或计算属性中解构响应式对象以便可以单独访问其属性同时保持其响应性。例如const stateRefs toRefs(state)。使用场景 toRef当你需要单独处理响应式对象中的某个属性并且希望保持该属性的响应性时你可以使用toRef。这样你可以在不改变原始对象结构的情况下轻松地修改和访问该属性的值。toRefs当你需要将整个响应式对象解构为多个独立的响应式引用并在模板或计算属性中单独使用这些引用时toRefs非常有用。这允许你以一种更加清晰和直观的方式处理复杂的响应式数据结构。返回值 toRef返回一个包含value属性的对象该value属性是响应式的并且与原始对象中的指定属性保持同步。toRefs返回一个普通对象该对象的每个属性都是一个响应式引用它们都与原始响应式对象的对应属性保持同步。示例 toRef示例 import { reactive, toRef } from vue const state reactive({ name: 张三, age: 20 }) const nameRef toRef(state, name) console.log(nameRef.value) // 输出张三 nameRef.value 李四 console.log(state.name) // 输出李四toRefs示例 import { reactive, toRefs } from vue const state reactive({ name: 张三, age: 20 }) const stateRefs toRefs(state) console.log(stateRefs.name.value) // 输出张三 stateRefs.name.value 李四 console.log(state.name) // 输出李四 综上所述toRef和toRefs的主要区别在于它们的功能、使用场景、返回值以及处理响应式数据的方式。选择使用哪一个取决于你的具体需求和场景。 12.在vue里面插槽的使用方法和场景有哪些
在Vue中插槽slot是一种非常有用的工具它允许父组件在子组件的模板中插入内容从而增强组件的复用性和灵活性。以下是关于Vue中插槽的使用方法和场景的详细解释
一、插槽的使用方法
1. 默认插槽匿名插槽
定义在子组件中使用slot/slot来占位表示一个默认插槽。使用在父组件中当使用子组件时可以直接在子组件标签内写入需要插入的内容这些内容将会替换子组件中的slot/slot标签。
2. 具名插槽
定义在子组件中可以给slot标签添加name属性来定义具名插槽。使用在父组件中需要使用template标签并搭配v-slot指令在Vue 2.6.0中使用slot属性结合template标签的方式已经被废弃推荐使用v-slot来指定内容要插入到哪个具名插槽中。
例如
!-- 子组件 --
template div slot nameheader/slot slot namebody/slot /div
/template !-- 父组件 --
template my-component template v-slot:header h2这是头部内容/h2 /template template v-slot:body p这是主体内容/p /template /my-component
/template
3. 作用域插槽
定义作用域插槽是一种特殊的插槽它允许子组件将数据传递给父组件的插槽内容。使用在子组件的slot标签上绑定一个数据对象然后在父组件的插槽模板中通过slot-scope在Vue 2.6.0中推荐使用v-slot语法来访问这些数据。 子组件ChildComponent.vue
template div slot namescopedSlot :useruser/slot /div
/template script
export default { data() { return { user: { name: John Doe, age: 30, occupation: Developer } }; }
};
/script 在这个子组件中我们定义了一个具名插槽scopedSlot并通过:useruser将数据对象user绑定到该插槽上。
父组件ParentComponent.vue
template div ChildComponent template v-slot:scopedSlotslotProps div h2Name: {{ slotProps.user.name }}/h2 pAge: {{ slotProps.user.age }}/p pOccupation: {{ slotProps.user.occupation }}/p /div /template /ChildComponent /div
/template script
import ChildComponent from ./ChildComponent.vue; export default { components: { ChildComponent }
};
/script 在父组件中我们使用template标签和v-slot:scopedSlotslotProps来定义作用域插槽。slotProps是一个对象它包含了子组件传递给插槽的所有属性在这个例子中是user对象。然后我们就可以在插槽模板中通过slotProps.user来访问这些数据了。 注意在Vue 3中作用域插槽的语法略有不同但基本概念是相同的。在Vue 3中你可以直接使用#前缀来引用具名插槽并使用v-slot指令的简写形式。例如 ChildComponent template #scopedSlot{ user } div h2Name: {{ user.name }}/h2 !-- ... -- /div /template
/ChildComponent 13. vuex 是什么为什么使用
vuex 是专门为 vue 提供的全局状态管理系统用于多个组件中数据共享、数据缓存等。无法持久化、内部核心原理是通过创造一个全局实例 new Vue 主要包括以下几个模块
State定义了应用状态的数据结构可以在这里设置默认的初始状态。Getter允许组件从 Store 中获取数据mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。Mutation是唯一更改 store 中状态的方法且必须是同步函数。Action用于提交 mutation而不是直接变更状态可以包含任意异步操作。Module允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
使用
首先你需要安装 Vuex。在你的项目中通过 npm 安装
npm install vuex
1. 创建 Vuex Store
在 store.js 或类似文件中
import Vue from vue;
import Vuex from vuex; Vue.use(Vuex); export default new Vuex.Store({ // state state: { count: 0 }, // mutations mutations: { increment(state) { state.count; }, decrement(state) { state.count--; } }, // actions actions: { incrementAsync({ commit }) { setTimeout(() { commit(increment); }, 1000); } }, // getters getters: { doubleCount(state) { return state.count * 2; } }, // modules modules: { // ... 你可以在这里定义模块 }
}); 2. 在 Vue 组件中使用 Vuex
在 Vue 组件中你可以通过 this.$store 来访问 store但通常建议使用辅助函数 mapState、mapGetters、mapMutations、mapActions 来简化代码。
template div p{{ count }}/p p{{ doubleCount }}/p button clickincrementIncrement/button button clickdecrementDecrement/button button clickincrementAsyncIncrement Async/button /div
/template script
import { mapState, mapGetters, mapMutations, mapActions } from vuex; export default { computed: { // 使用 mapState 辅助函数来映射 state 到计算属性 ...mapState([count]), // 使用 mapGetters 辅助函数来映射 getters 到计算属性 ...mapGetters([doubleCount]) }, methods: { // 使用 mapMutations 辅助函数来映射 mutations 到方法 ...mapMutations([increment, decrement]), // 使用 mapActions 辅助函数来映射 actions 到方法 ...mapActions([incrementAsync]) }
};
/script
3. 使用 Vuex Modules
Vuex 允许我们将 store 分割成模块module。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
例如我们可以有一个名为 user 的模块
// store/modules/user.js
const userModule { state: { name: Guest }, mutations: { setName(state, payload) { state.name payload; } }, // ... getters, actions 等
}; export default userModule;
然后在主 store 中引入这个模块
// store.js
import Vue from vue;
import Vuex from vuex;
import userModule from ./modules/user; Vue.use(Vuex); export default new Vuex.Store({ modules: { user: userModule } // ... 其他选项
}); 在组件中你可以通过命名空间namespaced来访问模块的状态、getters、mutations 和 actions。例如访问 user 模块的 name 状态
computed: { ...mapState(user, [name])
}