-
一、前言介绍: 随着社会的发展和科学技术的进步,互联网技术越来越受欢迎。网络传播的生活方式逐渐受到广大人民群众的喜爱。越来越多的互联网爱好者开始在互联网上满足他们的基本需求,同时逐渐进入各个用户的生活起居。互联网具有许多优点,例如便利性,速度,高效率和低成本。因此,类似于驾校管理,满足用户工作繁忙的需求,不仅是方便用户随时查看信息的途径,而且还能提高管理效率。本文首先以驾校管理过程的基本问题作为研究对象。在开发系统之前,我们对现有状况进行了详细的调查和分析。最后,我们利用计算机技术开发了一套完整合适的驾校管理。该系统的实现主要优势是:该系统主要采用计算机技术开发,它方便快捷;系统可以通过管理员界面查看系统所涉及的驾校管理所有信息管理。 驾校管理软件是一款方便、快捷、实用的信息服务查询软件。随着智能网络在全球市场的不断普及以及各种智能平台的使用,作为中国主流智能的技术开发系统,自然需要这样的软件来满足更多用户的需求和体验。系统的开发与人们的日常需求相关,如通过管理系统获取到个人中心、学员管理、驾校教练管理、预约教练管理、预约教练管理、评价教练管理、考试成绩管理、考试通知管理、报考信息管理、练车通知管理、预约练车管理、驾考套餐管理、报名信息管理、车辆信息管理等信息详细情况,了解最新资讯信息等。 二、主要技术: 2.1 Spring Boot框架介绍: Spring框架是Java平台上的一种开源应用框架,提供具有控制反转特性的容器。尽管Spring框架自身对编程模型没有限制,但其在Java应用中的频繁使用让它备受青睐,以至于后来让它作为EJB(EnterpriseJavaBeans)模型的补充,甚至是替补。Spring框架为开发提供了一系列的解决方案,比如利用控制反转的核心特性,并通过依赖注入实现控制反转来实现管理对象生命周期容器化,利用面向切面编程进行声明式的事务管理,整合多种持久化技术管理数据访问,提供大量优秀的Web框架方便开发等等。Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上特定Java注解来配置对象,开发者可以通过依赖查找或依赖注入来获得对象。Spring框架具有面向切面编程(AOP)框架,SpringAOP框架基于代理模式,同时运行时可配置;AOP框架主要针对模块之间的交叉关注点进行模块化。Spring框架的AOP框架仅提供基本的AOP特性,虽无法与AspectJ框架相比,但通过与AspectJ的集成,也可以满足基本需求。Spring框架下的事务管理、远程访问等功能均可以通过使用SpringAOP技术实现。Spring的事务管理框架为Java平台带来了一种抽象机制,使本地和全局事务以及嵌套事务能够与保存点一起工作,并且几乎可以在Java平台的任何环境中工作。 2.2 MYSQL数据库: 数据库是系统开发过程中不可或缺的一部分。 在WEB应用方面,MySQL AB开发了一个具有很大优势的MySQL关系数据库管理系统。 MySQL可以将数据存储在不同的表中,这非常灵活,并且还可以提高系统在实际应用中的速度。 数据库访问最常用于标准SQL语言,MySQL用于SQL语言,因此它具有高度兼容性。数据库的操作是必不可少的,包括对数据库表的增加、删除、修改、查询等功能。现如今,数据库可以分为关系型数据库和非关系型数据库,Mysql属于关系性数据库,Mysql数据库是一款小型的关系型数据库,它以其自身特点:体积小、速度快、成本低等,Mysql数据库是目前最受欢迎的开源数据库。 在WEB应用技术中, Mysql数据库支持不同的操作系统平台,虽然在不同平台下的安装和配置都不相同,但是差别也不是很大,Mysql在Windows平台下两种安装方式,二进制版和免安装版。安装完Mysql数据库之后,需要启动服务进程,相应的客户端就可以连接数据库,客户端可通过命令行或者图形界面工具登录数据库。 三、系统设计: 3.1 系统架构设计: 3.2 登录时序图设计: 四、功能截图: 4.1 登录注册: 4.2 前端页面: 4.2.1 系统首页: 4.2.2 教练模块: 4.2.3 考试须知: 4.2.4 预约练车: 4.2.5 车辆信息: 4.2.6 系统公告信息: 4.2.7 个人中心模块: 4.2.8 用户后台模块: 4.3 后端管理: 4.3.1 教练管理: 4.3.2 考试通知: 4.3.3 报名管理: 4.3.4 车辆信息: 4.3.5 系统公告等 五、代码实现: /** * 登录相关 */ @RequestMapping("users") @RestController public class UserController{ @Autowired private UserService userService; @Autowired private TokenService tokenService; /** * 登录 */ @IgnoreAuth @PostMapping(value = "/login") public R login(String username, String password, String captcha, HttpServletRequest request) { UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username)); if(user==null || !user.getPassword().equals(password)) { return R.error("账号或密码不正确"); } String token = tokenService.generateToken(user.getId(),username, "users", user.getRole()); return R.ok().put("token", token); } /** * 注册 */ @IgnoreAuth @PostMapping(value = "/register") public R register(@RequestBody UserEntity user){ // ValidatorUtils.validateEntity(user); if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) { return R.error("用户已存在"); } userService.insert(user); return R.ok(); } /** * 退出 */ @GetMapping(value = "logout") public R logout(HttpServletRequest request) { request.getSession().invalidate(); return R.ok("退出成功"); } /** * 密码重置 */ @IgnoreAuth @RequestMapping(value = "/resetPass") public R resetPass(String username, HttpServletRequest request){ UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username)); if(user==null) { return R.error("账号不存在"); } user.setPassword("123456"); userService.update(user,null); return R.ok("密码已重置为:123456"); } /** * 列表 */ @RequestMapping("/page") public R page(@RequestParam Map<String, Object> params,UserEntity user){ EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>(); PageUtils page = userService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.allLike(ew, user), params), params)); return R.ok().put("data", page); } /** * 列表 */ @RequestMapping("/list") public R list( UserEntity user){ EntityWrapper<UserEntity> ew = new EntityWrapper<UserEntity>(); ew.allEq(MPUtil.allEQMapPre( user, "user")); return R.ok().put("data", userService.selectListView(ew)); } /** * 信息 */ @RequestMapping("/info/{id}") public R info(@PathVariable("id") String id){ UserEntity user = userService.selectById(id); return R.ok().put("data", user); } /** * 获取用户的session用户信息 */ @RequestMapping("/session") public R getCurrUser(HttpServletRequest request){ Long id = (Long)request.getSession().getAttribute("userId"); UserEntity user = userService.selectById(id); return R.ok().put("data", user); } /** * 保存 */ @PostMapping("/save") public R save(@RequestBody UserEntity user){ // ValidatorUtils.validateEntity(user); if(userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())) !=null) { return R.error("用户已存在"); } userService.insert(user); return R.ok(); } /** * 修改 */ @RequestMapping("/update") public R update(@RequestBody UserEntity user){ // ValidatorUtils.validateEntity(user); UserEntity u = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", user.getUsername())); if(u!=null && u.getId()!=user.getId() && u.getUsername().equals(user.getUsername())) { return R.error("用户名已存在。"); } userService.updateById(user);//全部更新 return R.ok(); } /** * 删除 */ @RequestMapping("/delete") public R delete(@RequestBody Long[] ids){ userService.deleteBatchIds(Arrays.asList(ids)); return R.ok(); } } @Configuration public class InterceptorConfig extends WebMvcConfigurationSupport{ @Bean public AuthorizationInterceptor getAuthorizationInterceptor() { return new AuthorizationInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getAuthorizationInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**"); super.addInterceptors(registry); } /** * springboot 2.0配置WebMvcConfigurationSupport之后,会导致默认配置被覆盖,要访问静态资源需要重写addResourceHandlers方法 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/resources/") .addResourceLocations("classpath:/static/") .addResourceLocations("classpath:/admin/") .addResourceLocations("classpath:/front/") .addResourceLocations("classpath:/public/"); registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/work/"); super.addResourceHandlers(registry); } } ———————————————— 版权声明:本文为CSDN博主「java李杨勇」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_39709134/article/details/128781905
-
方式一: <el-table-column prop="endTime" label="结束时间" width="90" :formatter="formatDate"> </el-table-column> methods: { //方法区 formatDate(row, column) { // 获取单元格数据 let data = row[column.property] if(data == null) { return null } let dt = new Date(data) return dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate() + ' ' + dt.getHours() + ':' + dt.getMinutes() + ':' + dt.getSeconds() }, } 方式二: <el-table-column label="创建时间" align="center" prop="createTime" :formatter="formatDate" :show-overflow-tooltip="true" /> import {formatDate} from '@/utils/index' 1 methods: { // 时间格式方法 formatDate(row, column) { // 获取单元格数据 let data = row[column.property] return formatDate(data) }, utils/index.js export function formatDate(cellValue) { if (cellValue == null || cellValue == "") return ""; var date = new Date(cellValue) var year = date.getFullYear() var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds } ———————————————— 原文链接:https://blog.csdn.net/Amnesiac666/article/details/122882947
-
1 使用方法 1.1 组件模板引用 <PageNotice ref="pageNotice" sound="/xxx/new_message.mp3" /> 1.2 支持的参数 sound: 通知时播放的声音 1.3 动态调用方法 $refs.pageNotice.tip('你好','新消息')$refs.pageNotice.tip('有新客户访问') 2 组件源码 PageNotice组件源代码如下 <template> <div> <audio ref="audio" :src="sound"></audio> </div> </template> <script> export default { name: "PageNotice", props: { sound: { type: String, default: '' }, }, data() { return { tipTimer: null, tipTimerCount: 0, titleOld: null, } }, methods: { tip(msg, type) { this.doPageTitle(msg, type) if (this.sound) { this.doPlaySound() } }, doClearTimer() { clearInterval(this.tipTimer) this.tipTimer = null if (this.titleOld) { window.document.title = this.titleOld } this.tipTimerCount = 0 }, doPageTitle(msg, type) { type = type || '提醒' if (this.tipTimer) { this.doClearTimer() } this.titleOld = document.title this.tipTimerCount = 0 this.tipTimer = setInterval(() => { this.tipTimerCount++ if (this.tipTimerCount % 2 === 0) { window.document.title = '【' + type + '】' + msg } else { window.document.title = '' + msg } if (this.tipTimerCount > 6) { this.doClearTimer() } }, 500) }, doPlaySound() { let audio = this.$refs.audio if (!audio) { return } try { audio.pause() audio.play() } catch (e) { } } } } </script> 转载自https://blog.csdn.net/ModStartCMS/article/details/128238805
-
卫士介绍vue组件内部有三种导航卫士:beforeRouteEnterbeforeRouteUpdate beforeRouteLeavebeforeRouteLeave 的三个参数分别是1:to:要去的页面2:from: 本页面地址3:next 下一步实现过程data里面定义了一个变量data(){ return { timer: null, } }把定时器的任务定义在activated事件中,这样子,当清除定时后,下次再次进入当前路由的话,可以再次唤起定时器activated() { this.timer= setInterval(() => { console.log(window.location.pathname);//当前路由 }, 10000); },清除定时器的方法beforeRouteLeave(to, from, next){ next(); if (this.timer) { clearInterval(this.timer); this.timer= null; } },
-
Vue-validator 是Vue的表单验证插件,供大家参考,具体内容如下Vue版本: 1.0.24Vue-validator版本: 2.1.3基本使用<div id="app"> <validator name="validation"> <form novalidate> <div class="username-field"> <label for="username">username:</label> <input type="text" id="username" v-validate:username="['required']" /> </div> <div class="comment-filed"> <label for="comment">comment:</label> <input type="text" id="comment" v-validate:comment="{maxlength: 256}" /> </div> <div class="errors"> <p v-if="$validation.username.required">请输入你的名字</p> <p v-if="$validation.comment.maxlength">您的评论太长了</p> </div> <input type="submit" value="send" v-if="$validation.valid" /> </form> </validator></div><script src="//cdn.bootcss.com/vue/1.0.24/vue.js" type="text/javascript" charset="utf-8"></script><script src="//cdn.bootcss.com/vue-validator/2.1.3/vue-validator.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript"> new Vue({ el: '#app' });</script>将要验证的表单包裹在validator自定义元素指令中,而在要验证的表单控件元素的 v-validate 属性上绑定相应的校验规则。验证结果会保存在组建实例的 $validation 属性下。 $validation 是由 validator 元素和 name 属性和 $ 前缀组件验证结果结构{ // 表单整体验证 "valid": false, // 字段校验是否通过 "invalid": true, // valid 取反 "touched": false, // 校验字段所在元素获得通过焦点时返回true,否则返回false "untouched": true, // touched 取反 "modified": false, // 当元素值与初始值不同时返回true,否则返回false "dirty": false, // 字段值改变过至少一次返回true,否则返回false "pristine": true, // dirty 取反 // 字段单一验证 "username": { "required": true, "modified": false, "pristine": true, "dirty": false, "untouched": true, "touched": false, "invalid": true, "valid": false }, "comment": { "maxlength": false, "modified": false, "pristine": true, "dirty": false, "untouched": true, "touched": false, "invalid": false, "valid": true }}校验结果由两部分组成。表单整体校验结果和单个字段校验结果。验证器语法v-validate 指令语法:v-validate[:field]=”array literal | object literfal | binding”校验字段名fieldfield用来标识校验字段,之后可以用该字段来引用校验结果v-validate 指令用来定义校验规则,其值可以是数组字面量,对象字面量,组件实例数组属性名。数组字面量当校验器不需要额外参数时,可以使用数组字面量形式,如 required 校验器,只要出现就带I表该校验器所在元素是必填项。<div id="app"> <validator name="validation"> <form novalidate> Zip: <input type="text" v-validate:zip="['required']" /><br /> <div> <span v-if="$validation.zip.required">邮政编码是必填项</span> </div> </form> </validator></div>对象字面量对象字面量语法适合需要额外参数的校验器。如限制输入长度的校验器 minlength,需要说明限制长度多少。<div id="app"> <validator name="validation"> <form novalidate> ID: <input type="text" v-validate:id="{ required:true, minlength: 3, maxlength: 16 }" /> <br /> <div> <p v-if="$validation.id.required">ID不能为空</p> <p v-if="$validation.id.minlength">你的ID名字太短</p> <p v-if="$validation.id.maxlength">你的ID名字太长</p> </div> <input type="submit" value="send" v-if="$validation.valid" /> </form> </validator></div>还可以用 对象字面量语法通过 rule 字段来自定义验证规则<div id="app"> <validator name="validation"> <form novalidate> ID: <input type="text" v-validate:id="{minlength: {rule: 3}, required: true, maxlength: {rule: 16}}" /> <br /> <div> <p v-if="$validation.id.required">ID不能为空</p> <p v-if="$validation.id.minlength">你的ID名字太短</p> <p v-if="$validation.id.maxlength">你的ID名字太长</p> </div> <input type="submit" value="send" v-if="$validation.valid" /> </form> </validator></div>实例数据属性v-validate 的值可以是组建实例的数据属性。这样可以用来动态绑定校验规则。<div id="app"> <validator name="validation"> <form novalidate> ID: <input type="text" v-validate:id="rules" /><br /> <div> <p v-if="$validation.id.required">不能为空</p> <p v-if="$validation.id.minlength">你的ID太短</p> <p v-if="$validation.id.maxlength">你的ID太长</p> </div> </form> </validator></div><script src="//cdn.bootcss.com/vue/1.0.24/vue.js" type="text/javascript" charset="utf-8"></script><script src="//cdn.bootcss.com/vue-validator/2.1.3/vue-validator.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript"> new Vue({ el: '#app', data: { rules: { required: true, minlength: 3, maxlength: 16 } } }); </script>内置校验规则vue-validator 内置一些常用的验证规则:required — 输入值不能为空pattern — 必须匹配pattern表示的正则表达式minlength — 输入值长度不能小于minlength表示的值maxlength — 输入的值不能大于maxlength表示的值min — 输入值不能小于min表示的值max — 输入值不能大于max表示的值与v-model同时使用vue-validator会自动校验通过v-model动态设置的值。<div id="app"> <validator name="validation"> <form novalidate> message: <input type="text" v-model="msg" v-validate:message="{required: ture, minlength: 8}" /> <br /> <p v-if="$validation.message.required">message不能为空</p> <p v-if="$validation.message.minlength">message输入太长位数</p> </form> </validator></div><script src="//cdn.bootcss.com/vue/1.0.24/vue.js" type="text/javascript" charset="utf-8"></script><script src="//cdn.bootcss.com/vue-validator/2.1.3/vue-validator.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript"> var vm = new Vue({ el: '#app', data: { msg: '' } }); setTimeout(function () { vm.msg = 'hello world!'; }, 2000); </script>重置校验结果通过在Vue组件实例上调用$resetValidation();方法来动态重置校验结果。<div id="app"> <validator name="validation"> <form novalidate> <div class="username-field"> <label for="username">username:</label> <input type="text" id="username" v-validate:username="['required']" /> </div> <div class="comment-filed"> <label for="comment">comment:</label> <input type="text" id="comment" v-validate:comment="{maxlength: 256}" /> </div> <div class="errors"> <p v-if="$validation.username.required">用户名不能为空</p> <p v-if="$validation.comment.maxlength">输入文字超过256个</p> <input type="submit" value="send" v-if="$validation.valid" /> <button type="button" @click="onReset">Reset Validation</button> </div> <pre>{{$validation | json}}</pre> </form> </validator></div><script src="//cdn.bootcss.com/vue/1.0.24/vue.js" type="text/javascript" charset="utf-8"></script><script src="//cdn.bootcss.com/vue-validator/2.1.3/vue-validator.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript"> new Vue({ el: '#app', methods: { onReset: function () { this.$resetValidation(); } } }); </script>分组校验vue-validator支持分组校验。例如重复密码功能。<div id="app"> <validator name="validation" :groups="['passwordGroup']"> <form novalidate> username: <input type="text" v-validate:username="['required']" /><br /> password: <input type="password" v-validate:password="{ minlength: 8, required: true }" group="passwordGroup" /><br /> comfirm password: <input type="password" v-validate:password-comfirm="{minlength: 8, required: true}" group="passwordGroup" /> <div class="errors"> <p v-if="$validation.username.required">用户名不能为空</p> <p v-if="$validation.password.required">密码不能为空</p> <p v-if="$validation.password.minlength">密码不能少于8位</p> <p v-if="$validation.password-comfirm.required">重复密码不能为空</p> <p v-if="$validation.password-comfirm.minlength">密码不能少于8位</p> <p v-if="$validation.passwordGroup.valid">密码不一致</p> </div> </form> </validator></div><script src="//cdn.bootcss.com/vue/1.0.24/vue.js" type="text/javascript" charset="utf-8"></script><script src="//cdn.bootcss.com/vue-validator/2.1.3/vue-validator.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript"> new Vue({ el: '#app' }); </script>原文链接:https://www.jb51.net/article/110609.htm?_=1515146398
-
一、计算属性computed 1.1.什么是计算属性computed ⭐⭐ computed 是基于它的依赖缓存,只有在它的相关依赖发生改变时才会进行更新。官方文档是这样说的:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性 1.2.复杂数据的处理-computed ⭐⭐ 拼接字符串、分数是否及格、message记录一段文字,这里是用computed实现的 {{fullname}} {{scorelevel}} {{reversetext}}
-
本文主要介绍了Vue新一代状态管理工具Pinia的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧+目录前言Pinia是尤雨溪强烈推荐的一款Vue状态管理工具,也被认为是下一代Vuex的替代产品。优点去除了mutations,只有 state,getters和actions,其中actions支持了同步和异步操作不会像Vuex那样有模块嵌套,Pinia只有store的概念,store之间可以相互使用,互不影响,达到模块扁平化的效果更好地支持ts更好地支持Vue2/Vue3逻辑更加清晰,开发起来更加简单安装npm i pinia创建并挂载1.在src目录下新建store目录并在其下面创建index.js文件,代码如下:123import { createPinia } from 'pinia'const store = createPinia()export default store2.在main.js中引入store并挂载,代码如下:1234567import { createApp } from 'vue'import App from './App.vue'import store from './store/index'createApp(App).use(store).mount('#app')创建store在src/store文件夹下创建一个js文件,命名按照需求即可,我这边定义为main.js,代码如下:1234567891011import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, actions: {}, getters: {}})其中defineStore的第一个参数为该store的名称,第二个参数为一个对象,包含了该store的state,getters和actions,state改为了函数形式,目的应该是像Vue2 options API中的data类似,避免多个store中定义的属性相互受到影响。使用store此处使用Vue3的SFC语法,主要是Pinia更适合Vue3这种组合式API风格,方便演示回显与修改state1234567891011121314151617181920 {{ store.msg }} {{ count }} + 使用方法与Vuex基本类似,要使用哪个store,就直接进行引入,非常方便,没那么多层级引用其中,我们使用了Pinia中的storeToRefs方法,此方法能够直接解构出该store的state中的某个值,并且是响应式的;如果我们直接从state上解构,那么解构出的值就不是响应式的了。如果我们要修改state中的值,不能直接去修改解构出的值,得去修改state上对应的属性使用$patch对多条数据直接修改使用$patch的方式对数据进行修改,可以加快修改速度,性能更好。$patch 方法可以接受两种类型的参数,对象型和回调函数型。$patch + 对象$patch + 函数 注:使用回调函数型时,回调接收一个state参数,state指代的就是对应store中的state使用方式如下:12345678910111213141516171819202122232425262728293031 {{ store.msg }} {{ count }} $patch+对象 $patch+回调 使用actions1.在src/store/main.js的actions对象中,添加一个方法,代码如下:12345678910111213141516import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, actions: { changeState() { this.count++ this.msg = this.msg === 'hello' ? 'hello world' : 'hello' } }, getters: {}})2.使用方式为:store.方法名,代码如下:1234567891011121314151617181920 {{ store.msg }} {{ count }} 使用action 使用gettersPinia中的getter和Vue中的计算属性类似,在获取state之前会进行处理,具有缓存性,如果值没有改变,即使多次调用,实际上也只会调用一次。1.在src/store/main.js的getters对象中进行添加,代码如下:1234567891011121314151617import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, getters: { getState(state) { console.log('getState被调用了'); // getter 中不仅可以传递state直接改变数据,也可以使用this来改变数据 return `${state.msg} + ${this.count}` } }})2.使用方式如下:123456789101112 使用getter获取数据:{{ store.getState }} 使用getter获取数据:{{ store.getState }} 使用getter获取数据:{{ store.getState }} 我们可以看到,即使执行了三遍一样的代码,但最终还是只调用了一次。多个store相互调用在Pinia中,可以在一个store中import引入另外一个store,然后通过调用引入的store方法的形式,获取引入的store的状态。1.在src/store目录下,新建一个文件.js,代码如下:123456789import { defineStore } from 'pinia'export const userStore = defineStore('user', { state: () => { return { name: '吴同学' } }})2.在需要用到的store中进行引入,并通过getters的方式获取,代码如下:12345678910import { defineStore } from 'pinia'import { userStore } from './user'export const mainStore = defineStore('main', { getters: { getUserState() { return userStore().name } }})数据持久化Pinia与Vuex一样,刷新页面后,数据就会重置,有时候我们需要将数据进行持久化存储,我们可以使用pinia-plugin-persist这个插件安装npm i pinia-plugin-persist --save使用1.在src/store/index.js文件夹下,引入并使用,代码如下:1234567import { createPinia } from 'pinia'import piniaPluginPersist from 'pinia-plugin-persist'const store = createPinia()store.use(piniaPluginPersist)export default store2.在对应的store里开启持久化存储12345678910111213141516import { defineStore } from 'pinia'import { userStore } from './user'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, // 开启数据缓存 persist: { enabled: true }})更新数据以后,我们就能在浏览器控制台中看到已经将数据存储到了sessionStorage中数据默认是存在sessionStorage中的,还会以store的名称作为key。但是我们可以对其修改,并且还可以只持久化部分state中的属性,代码如下:1234567891011121314151617181920212223import { defineStore } from 'pinia'import { userStore } from './user'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, // 开启数据缓存 persist: { enabled: true, strategies: [ { key: 'mainStore', // 修改存在缓存中的key值 storage: localStorage, // 修改存储方式为localStorage paths:['msg'] // 只持久化msg,此时刷新页面msg数据会被保留,其他state将会重置 } ] }})总结Pinia就是Vuex的替代产品,相比于Vuex,Pinia更好地兼容了Vue本身,代码更加简洁,开发起来也更加便捷。以上就是关于Pinia的介绍,如果觉得对你有帮助,就请点个赞,谢谢大家!转载自https://www.jb51.net/article/255470.htm
-
本文实例为大家分享了vue实现轮播图片的具体代码,供大家参考,具体内容如下11234567891011121314<template> <section class="body"> <section class="wrap"> <swiper :options="swiperOption" class="swiper-wrap" ref="mySwiper" v-if="banner.length!=0"> <swiper-slide v-for="(item,index) in banner" :key="index" > //点击图片跳到哪里,这里跳到home页面 item举例:{img:http://www.***.com/home/images/index_img02.png,url:/home} <img :src="item.img" alt="" @click="skip_out_page(item.url)" /> </swiper-slide> <!-- 常见的小圆点 --> <div class="swiper-pagination" v-for="(item,index) in banner" :key="index" slot="pagination" ></div> </swiper> </section> </section></template>12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061<script> export default { data() { const that = this; return { imgIndex: 1, swiperOption: { //是一个组件自有属性,如果notNextTick设置为true,组件则不会通过NextTick来实例化swiper,也就意味着你可以在第一时间获取到swiper对象,假如你需要刚加载遍使用获取swiper对象来做什么事,那么这个属性一定要是true notNextTick: true, //循环,而不是每次都突然回到第一个 loop: true, //设定初始化时slide的索引,加载页面时显示的第几个,从0开始 initialSlide: 0, //自动播放 autoplay: { /*切换轮播图片的时间,即上次切换成功后到再次需要切换的时间*/ delay: 1500, stopOnLastSlide: false, /* 触摸滑动后是否继续轮播 false触摸后不再点击继续轮播,true触摸后不再点击不轮播,停在最后一次页面*/ disableOnInteraction: false }, //滑动速度,时间单位,越小越快,与上面 delay 区别,speed是完成切换所需时间,delay是切换成功后停留多长时间再切换 speed: 800, //滑动方向 direction: "horizontal", //小手掌抓取滑动 grabCursor: true, on: { //滑动之后回调函数 slideChangeTransitionStart: function() { /* realIndex为滚动到当前的slide索引值 */ that.imgIndex= this.realIndex - 1; }, }, //分页器设置 pagination: { el: ".swiper-pagination", clickable: true, type: "bullets" } }, banner: [] } }, methods: { skip_out_page(v) { window.location.href = v }, get_data() { this.$http.get('test').then(res => { if(res.data.code == '0000'){ this.banner = res.data.img_info } }); } }, mounted() { this.get_data() } }</script>12345678910111213141516171819<style lang="scss"> .swiper-wrap{ width: 100%; height: 210px; background-color: #fff; } .swiper-pagination{ background: #fff; } .swiper-pagination-bullet{ background: #ccc; width: 10px; height: 10px; opacity: 1; } .swiper-pagination-bullet-active{ background: #00C293; }</style>以上就是本文的全部内容转载自https://www.jb51.net/article/255485.htm
-
Pinia是尤雨溪强烈推荐的一款Vue状态管理工具,也被认为是下一代Vuex的替代产品。优点• 去除了mutations,只有 state,getters和actions,其中actions支持了同步和异步操作• 不会像Vuex那样有模块嵌套,Pinia只有store的概念,store之间可以相互使用,互不影响,达到模块扁平化的效果• 更好地支持ts• 更好地支持Vue2/Vue3• 逻辑更加清晰,开发起来更加简单安装npm i pinia创建并挂载1.在src目录下新建store目录并在其下面创建index.js文件,代码如下:123import { createPinia } from 'pinia'const store = createPinia()export default store2.在main.js中引入store并挂载,代码如下:1234567import { createApp } from 'vue'import App from './App.vue'import store from './store/index' createApp(App).use(store).mount('#app')创建store在src/store文件夹下创建一个js文件,命名按照需求即可,我这边定义为main.js,代码如下:1234567891011import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, actions: {}, getters: {}})其中defineStore的第一个参数为该store的名称,第二个参数为一个对象,包含了该store的state,getters和actions,state改为了函数形式,目的应该是像Vue2 options API中的data类似,避免多个store中定义的属性相互受到影响。使用store此处使用Vue3的SFC语法,主要是Pinia更适合Vue3这种组合式API风格,方便演示回显与修改state1234567891011121314151617181920<script lang="ts" setup> import { mainStore } from '../store/main' import { storeToRefs } from 'pinia' const store = mainStore() const { count } = storeToRefs(store) // 单条数据直接修改 const handleAddCount = () => { store.count++ }</script> <template> <div> <p>{{ store.msg }}</p> <p>{{ count }}</p> <button @click="handleAddCount">+</button> </div></template>• 使用方法与Vuex基本类似,要使用哪个store,就直接进行引入,非常方便,没那么多层级引用• 其中,我们使用了Pinia中的storeToRefs方法,此方法能够直接解构出该store的state中的某个值,并且是响应式的;如果我们直接从state上解构,那么解构出的值就不是响应式的了。• 如果我们要修改state中的值,不能直接去修改解构出的值,得去修改state上对应的属性使用$patch对多条数据直接修改使用$patch的方式对数据进行修改,可以加快修改速度,性能更好。$patch 方法可以接受两种类型的参数,对象型和回调函数型。$patch + 对象$patch + 函数 注:使用回调函数型时,回调接收一个state参数,state指代的就是对应store中的state使用方式如下:12345678910111213141516171819202122232425262728293031<script lang="ts" setup> import { mainStore } from '../store/main' import { storeToRefs } from 'pinia' const store = mainStore() const { count } = storeToRefs(store) // 使用$patch + 对象 const updateWithObj = () => { store.$patch({ msg: store.msg === 'hello' ? 'hello world' : 'hello', count: store.count + 2 }) } // 使用$patch + 回调 const updateWithFun = () => { store.$patch((state) => { state.msg = state.msg === 'hello' ? 'hello world' : 'hello' state.count = state.count + 3 }) }</script> <template> <div> <p>{{ store.msg }}</p> <p>{{ count }}</p> <button @click="updateWithObj">$patch+对象</button> <button @click="updateWithFun">$patch+回调</button> </div></template>使用actions1.在src/store/main.js的actions对象中,添加一个方法,代码如下:12345678910111213141516import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, actions: { changeState() { this.count++ this.msg = this.msg === 'hello' ? 'hello world' : 'hello' } }, getters: {}})2.使用方式为:store.方法名,代码如下:1234567891011121314151617181920<script lang="ts" setup> import { mainStore } from '../store/main' import { storeToRefs } from 'pinia' const store = mainStore() const { count } = storeToRefs(store) // 使用action修改数据 const onActionClick = () => { store.changeState() }</script> <template> <div> <p>{{ store.msg }}</p> <p>{{ count }}</p> <button @click="onActionClick">使用action</button> </div></template>使用gettersPinia中的getter和Vue中的计算属性类似,在获取state之前会进行处理,具有缓存性,如果值没有改变,即使多次调用,实际上也只会调用一次。1.在src/store/main.js的getters对象中进行添加,代码如下:1234567891011121314151617import { defineStore } from 'pinia'export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, getters: { getState(state) { console.log('getState被调用了'); // getter 中不仅可以传递state直接改变数据,也可以使用this来改变数据 return `${state.msg} + ${this.count}` } }})2.使用方式如下:123456789101112<script lang="ts" setup> import { mainStore } from '../store/main' const store = mainStore()</script> <template> <div> <p>使用getter获取数据:{{ store.getState }}</p> <p>使用getter获取数据:{{ store.getState }}</p> <p>使用getter获取数据:{{ store.getState }}</p> </div></template>我们可以看到,即使执行了三遍一样的代码,但最终还是只调用了一次。多个store相互调用在Pinia中,可以在一个store中import引入另外一个store,然后通过调用引入的store方法的形式,获取引入的store的状态。1.在src/store目录下,新建一个文件.js,代码如下:123456789import { defineStore } from 'pinia' export const userStore = defineStore('user', { state: () => { return { name: '吴同学' } }})2.在需要用到的store中进行引入,并通过getters的方式获取,代码如下:12345678910import { defineStore } from 'pinia'import { userStore } from './user' export const mainStore = defineStore('main', { getters: { getUserState() { return userStore().name } }})数据持久化Pinia与Vuex一样,刷新页面后,数据就会重置,有时候我们需要将数据进行持久化存储,我们可以使用pinia-plugin-persist这个插件安装npm i pinia-plugin-persist --save使用1.在src/store/index.js文件夹下,引入并使用,代码如下:1234567import { createPinia } from 'pinia'import piniaPluginPersist from 'pinia-plugin-persist' const store = createPinia()store.use(piniaPluginPersist) export default store2.在对应的store里开启持久化存储12345678910111213141516import { defineStore } from 'pinia'import { userStore } from './user' export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, // 开启数据缓存 persist: { enabled: true }})更新数据以后,我们就能在浏览器控制台中看到已经将数据存储到了sessionStorage中数据默认是存在sessionStorage中的,还会以store的名称作为key。但是我们可以对其修改,并且还可以只持久化部分state中的属性,代码如下:1234567891011121314151617181920212223import { defineStore } from 'pinia'import { userStore } from './user' export const mainStore = defineStore('main', { state: () => { return { msg: 'hello', count: 1 } }, // 开启数据缓存 persist: { enabled: true, strategies: [ { key: 'mainStore', // 修改存在缓存中的key值 storage: localStorage, // 修改存储方式为localStorage paths:['msg'] // 只持久化msg,此时刷新页面msg数据会被保留,其他state将会重置 } ] }})总结Pinia就是Vuex的替代产品,相比于Vuex,Pinia更好地兼容了Vue本身,代码更加简洁,开发起来也更加便捷转载自https://www.jb51.net/article/255470.htm
-
前言这些内容是博主在学习过程中记录下来的,有一些不重要的点就跳过了,需要时自行查询文档。其实V2到V3的学习成本不高,熟悉V2的话,看完这篇文章就可以上手V3。Vue3官网在线源码编译地址1,setupsetup是所有Composition API的容器,值为一个函数。组件中所用到的数据、方法等等,均要配置在setup中,它会在beforeCreate之前执行一次,注意:V3里this不再是指向Vue实例,访问this会是undefined1.1,返回值若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。若返回一个渲染函数:则可以自定义渲染内容。1.2,注意点尽量不要与V2配置混用V2配置(data、methos、computed…)中可以访问到setup中的属性、方法。但在setup中不能访问到V2配置(data、methods、computed…)。如果有重名, setup优先。setup不能是一个async函数因为返回值不再return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)1.3,语法<script>import { ref, reactive } from 'vue'export default { name: 'Home', setup(props, context) { const title = ref('标题') const data = reactive({ value: '哈哈哈' }) return { title, data } }}</script>1.4,setup的参数props:值为对象,包含组件外部传递过来,且组件内部声明接收了的属性context:上下文对象attrs: 值为对象,包含组件外部传递过来,但没有在props配置中声明的属性, 相当于this.$attrsslots: 收到的插槽内容, 相当于this.$slotsemit: 分发自定义事件的函数, 相当于this.$emit2,ref 创建响应式数据使用ref可以创建一个包含响应式数据的引用对象(reference对象,简称ref对象),可以是基本类型、也可以是对象。语法// 创建const xxx = ref(value)// 使用xxx.value// 在模板中<div>{{xxx}}</div>3,reactive 创建响应式数据定义一个对象类型的响应式数据,内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作语法// 创建const xxx = reactive({ xxx: ''})// 使用xxx.xxx4,computed 计算属性与V2中computed配置功能一致语法import { computed } from 'vue'setup(){ // 简写语法 let fullName = computed(() => { return person.firstName + '-' + person.lastName }) // 完整语法 let fullName = computed({ get(){ return person.firstName + '-' + person.lastName }, set(value){ const nameArr = value.split('-') person.firstName = nameArr[0] person.lastName = nameArr[1] } }) return fullName5,watch 监听与V2中watch配置功能一致,语法有点改动语法情况一:监视ref定义的响应式数据watch(sum, (newValue, oldValue) => { console.log('sum变化了', newValue, oldValue)}, {immediate:true})情况二:监视多个ref定义的响应式数据watch([sum, msg], (newValue,oldValue) => { console.log('sum或msg变化了', newValue,oldValue)}) 情况三:监视reactive定义的响应式数据// 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue// 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视watch(person, (newValue, oldValue) => { console.log('person变化了', newValue, oldValue)}, { immediate:true, deep:false }) // 此处的deep配置不再奏效情况四:监视reactive定义的响应式数据中的某个属性watch(() => person.job, (newValue, oldValue) => { console.log('person的job变化了', newValue, oldValue)}, { immediate:true, deep:true }) 情况五:监视reactive定义的响应式数据中的某些属性watch([() => person.job, () => person.name], (newValue, oldValue) => { console.log('person的job变化了', newValue, oldValue)}, { immediate:true, deep:true })特殊情况:此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效watch(() => person.job, (newValue, oldValue) => { console.log('person的job变化了', newValue, oldValue)}, { deep:true })6,watchEffect 监听回调和watch的区别是,watch既要指明监视的属性,也要指明监视的回调。而watchEffect,不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性,不用写返回值。语法// 回调中用到的数据只要发生变化,则直接重新执行回调watchEffect(() => { const x1 = sum.value const x2 = person.age console.log('watchEffect配置的回调执行了')})7,生命周期生命周期全都写在setup中7.1,改变beforeDestroy 改名为 beforeUnmountdestroyed 改名为 unmountedbeforeCreate => setupcreated => setupbeforeMount => onBeforeMountmounted => onMountedbeforeUpdate => onBeforeUpdateupdated => onUpdatedbeforeUnmount => onBeforeUnmountunmounted => onUnmounted7.2,语法setup() { onMounted(() => { console.log('mounted') })}8,toRef 创建ref创建一个ref对象,其value值指向另一个对象中的某个属性语法const state = reactive({ foo: 1, bar: 2})const fooRef = toRef(state, 'foo')// 传递propsexport default { setup(props) { useSomeFeature(toRef(props, 'foo')) }}9,toRefs 响应式转换将响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应property的ref语法const state = reactive({ foo: 1, bar: 2})const stateAsRefs = toRefs(state)// 此时state和stateAsRefs是关联的10,shallowReactive 响应式外层转换只处理对象最外层属性的响应式(浅响应式)。适用于:一个对象数据,结构比较深, 但变化时只是外层属性变化语法const state = shallowReactive({ foo: 1, nested: { bar: 2 }})11,shallowRef 基本数据响应式只处理基本数据类型的响应式, 不进行对象的响应式处理。适用于:一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换语法const shallow = shallowRef({ greet: 'Hello, world'})12,readonly 响应式变只读让一个响应式数据变为只读的(深只读),应用于不希望数据被修改时语法const shallow = shallowRef({ greet: 'Hello, world', // 只读 nested: { bar: 2 // 只读 }})13,shallowReadonly 响应式变只读让一个响应式数据变为只读的(浅只读),应用于不希望数据被修改时语法const shallow = shallowReadonly({ foo: 1, // 只读 nested: { bar: 2 // 非只读 }})14,toRaw 响应式变非响应式将一个由reactive生成的响应式对象转为普通对象,对这个普通对象的所有操作,不会引起页面更新。语法const foo = {}const Foo = reactive(foo)console.log(toRaw(Foo) === foo) // true15,markRaw 标记永远不响应式标记一个对象,使其永远不会再成为响应式对象,有些值不应被设置为响应式的,例如复杂的第三方类库等,当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。语法const foo = markRaw({})console.log(isReactive(reactive(foo))) // false// 嵌套在其他响应式对象中时也可以使用const bar = reactive({ foo })console.log(isReactive(bar.foo)) // false16,customRef 依赖更新控制创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收track和trigger函数作为参数,并且应该返回一个带有get和set的对象。语法<script>import { customRef } from 'vue'export default { name: 'Home', setup() { // 实现防抖函数 const fn = function(value, delay = 500) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearInterval(timeout) timeout = setTimeout(() => { console.log(newValue) value = newValue trigger() }, delay) } } }) } const keyword = fn('', 500) return { keyword } }}</script>17,provide & inject 通信实现祖与后代组件间通信,父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据语法// 祖组件setup(){ let car = reactive({ name:'奔驰', price:'40万' }) provide('car', car)}// 后代组件setup(props, context){ const car = inject('car') return { car }}18,响应式数据的判断18.1,isRef检查一个值是否为一个ref对象语法const val = ref('xxx')isRef(val) // true18.2,isReactive检查一个值是否为一个isReactive对象语法const val = isReactive({})isRef(val) // true18.3,isReadonly检查一个对象是否是由readonly创建的只读代理语法const state = reactive({ name: 'John'})console.log(isReactive(state)) // true18.4,isProxy检查对象是否是由reactive或readonly创建的proxy语法const state = reactive({ name: 'John'})console.log(isProxy(state)) // true19,teleport 移动dom组件Teleport提供了一种干净的方法,允许我们控制在DOM中哪个父节点下渲染了HTML,而不必求助于全局状态或将其拆分为两个组件。语法<teleport to="移动位置"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <button @click="isShow = false">关闭弹窗</button> </div> </div></teleport>// to的格式<teleport to="#some-id" /><teleport to=".some-class" /><teleport to="[data-teleport]" />// disabled的格式<teleport to="#popup" :disabled="displayVideoInline"> <video src="./my-movie.mp4"></teleport>20,Suspense 异步渲染组件等待异步组件时先渲染一些额外内容,让应用有更好的用户体验语法<template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template #default> <Child/> </template> <template #fallback> <h3>加载中.....</h3> </template> </Suspense> </div></template>import { defineAsyncComponent } from 'vue'const Child = defineAsyncComponent(() => import('./components/Child.vue'))components: { Child}21,全局API调整将全局的API,即:Vue.xxx调整到应用实例(app)上V2的api V3的apiVue.config.xxxx app.config.xxxxVue.component app.componentVue.directive app.directiveVue.mixin app.mixinVue.use app.useVue.prototype app.config.globalProperties22,移除api名称 现状Vue.config.productionTip 已移除config.keyCodes 已移除$children 已移除$listeners 已移除$on 已移除$off 已移除$once 已移除filters 已移除.native 已移除23,Ref 获取DOM由于V3中不在存在this,所以ref的获取调整了23.1,单个ref语法<div ref="Qrcode" class="qr_codeode_url" />import { ref } from 'vue'export default { setup() { const Qrcode = ref(null) // 挂载后 onMounted(() => { console.log(Qrcode.value) }) return { Qrcode } }}23.2,循环中的refV3中在for循环元素上绑定ref将不再自动创建$ref数组。要从单个绑定获取多个ref,请将ref绑定到一个更灵活的函数上语法<div v-for="item in list" :ref="setItemRef"></div>import { onBeforeUpdate, onUpdated } from 'vue'export default { setup() { let itemRefs = [] const setItemRef = el => { if (el) { itemRefs.push(el) } } onBeforeUpdate(() => { itemRefs = [] }) onUpdated(() => { console.log(itemRefs) }) return { setItemRef } }}itemRefs不必是数组:它也可以是一个对象,其ref可以通过迭代的key被设置如有需要,itemRef也可以是响应式的,且可以被侦听24,emits 自定义事件定义一个组件可以向其父组件触发的事件// 在子组件中<h1 @click="father">{{ msg }}</h1>export default { name: 'HelloWorld', props: { msg: { type: String, default: '' } }, emits: ['close'], setup(props, { emit }) { const father = function() { emit('close', 'child') } return { father } }}// 在父组件中<HelloWorld :msg="msg" @click="fn" @close="fn2" />25,$nextTick 异步更新使用方式修改import { nextTick } from 'vue'nextTick(() => { // ...})26,hook 生命周期事件通过事件来监听组件生命周期中的关键阶段语法// V2的语法<template> <child-component @hook:updated="onUpdated"></template>// V3的语法<template> <child-component @vnode-updated="onUpdated"></template>// 驼峰写法<template> <child-component @vnodeUpdated="onUpdated"></template————————————————版权声明:本文为CSDN博主「鹏多多i」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/pdd11997110103/article/details/121035412
-
this.$nextTick(() => { // iframedom let iframe = this.$refs.iframedom console.log(iframe) if (iframe.attachEvent) { iframe.attachEvent('onload', function () { that.ifloading = false }) } else { iframe.onload = function () { that.ifloading = false } } })
-
需求标准页面引入Vue库,element库进行开发。现状原来系统自动引入Vu库的,现在需要在库中引入Vue和和Element,并将Element到Vue上。现在引入了两个库element是原来Vue的,但是element先加载完成,导致报错
-
写在前面CSDN话题挑战赛第1期活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f参赛话题:前端面试宝典话题描述:欢迎各位加入话题创作得小伙伴,如果我没有猜错得话,我觉得你是应该同我一样是一位前端人。如今前端在IT事业中的占比越来越重,已经成为不可缺少的部分,前端技术也是层出不穷,各种技术类、技术框架也蜂拥而出,前端面试的难度也随之增加,如果我们拥有一套前端面试宝典。如果你是应聘者:你就可以从容的solo面试官,如果你是面试官:你就可以将应聘者拷问到骨子里!总之我们大家一起将自己的面试经验以及学习到的知识点汇聚于此,形成一套体系的前端面试宝典。让读者无论是面试还是学习都能够有非常大的收获。就让我们携手共筑前端面试宝典吧!!!创作模板:携手共筑前端面试宝典题目一考点答案题目二考点答案题目三考点答案题目四考点答案题目一Vue如何添加自定义指令考点考察对Vue添加自定义指令方法的掌握答案添加自定义指令的两种方式:全局指令: 通过 Vue.directive() 函数注册一个全局的指令。局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令。题目二Vue框架有哪些优点,为什么前端人都喜欢Vue考点了解Vue的优点才能更加方便使用Vue框架答案Vue的优点轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;简单易学:Vue是由国人开发出来的,易于理解和学习(不用学习令人头疼的英语)双向数据绑定:延续了angular 的特点,在操作数据封面更加容易组件化:延续了react的优点,实现html的封装和重用,在构建单页面应用方面有着相当明显的优势数据和结构的分离:数据和结构分离,只需要操作数据就能完成操作,不需要对代码进行修改,使数据更改变得so easy使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;虚拟DOM:dom操作十分耗能,不再使用原生的dom,而且使用虚拟的DOM进行操作运行速度更快:跟react进行比较,同样是操作虚拟 dom ,就性能而言, vue的运行速度存在很大的优势(速度快才是真的快)题目三Vue响应式原理是什么考点理解Vue响应式原理是怎样工作的答案响应式:当数据改变后,Vue会通知使用该数据的代码比如说:视图渲染使用了一个数据那么当这个数据改变后,视图会响应式的自动更新Vue 它是通过那个Object.defineProperty()来更新定义 data中的所有属性题目四Vuex是什么,Vuex有哪几种属性考点熟悉掌握Vuex的使用,并熟记Vuex有哪些属性答案Vuex是什么Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex有哪些属性Vuex有五种属性分别是State、Getters、Mutations、Action、Modules属性 描述State 存放数据状态,不可以直接修改里面的数据Getters 类似Vue的计算属性,主要用于过滤数据Mutations Mutations定义的方法动态修改Vuex 的 store 中的状态或数据Action 将Mutation里面处理数据的方法变成可异步处理数据的方法,简单的说就是异步操作数据Modules 项目特别复杂的时候,可以让每一个模块拥有自己的State、Mutation、Action、Getters,使得结构非常清晰,方便管理。写在最后CSDN话题挑战赛第1期活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f原文链接:https://blog.csdn.net/xqe777/article/details/124692250
-
-
### 1watch #### 1.1常用方式: + 场景: 查询输入框默认查询一次,当输入内容的发生改变执行查询.getmess() ``` moutend(){ this.getmess() } watch(){ inValue(){ this.getmess() } } ``` #### 1.2立即执行 ``` watch:{ inValue:{ handler(newvalue,oldvalue){ this.getmess() } immediate:true } } ``` 监听inVlaue 值的修改,触发handler函数,监听当前对象可以配置俩个属性 + immediate 组件加载后会立即执行handle回调 + deep 深度监视,默认值值false ### 2常见的组件通讯 #### 2.1props **父子组件传值(props可以是一个数组或对象)** ``` //父组件<fatherPage :mess="mess"> //子组件 props:{ mess:{ type:Array , default:()=>[], required:true } } ``` + type 接收数据类型 String,Number,Boolean,Array,Object,Date,Function,Symbol + default 默认值,Number 类型填写数字,String 默认为字符串 特殊的 [] {} 箭头函数默认返回 + required 是否为必传传项目 #### 2.2$emit **子父组件产值,子组件通过触发父级事件传参实现通信** >注: @send在组件上定义,是自定义事件,不是点击事件。 ``` //父组件 <fatherPage @send="send"> method:{ send(mess){ console.log(mess) } } //子组件 this.$emit('send','我是子组件参数') ``` #### 2.3vuex **vuex 简答说就是一个全局状态管理者,通过挂载到vue实例方便每个组件可以访问** ``` state: 定义数据的对象(厂库) ,使用: this.$store.state ,也可以通过计算属性扩展出[...mapState] mutation:同步修改state的值 action:异步调用函数mutation,修改action的值 getter:类型于计算属性,可以直接拿到state的值,操作数据并返回,一般多于简化数据. modules: 模块化,将不同页面数据统一管理。 ``` **工作流程** + 组件调用this.$dispatch()触发action{} 对应异步回调函数 + action 对应函数发送网路请求,返回数据同构commit()调用mutation + mutation 存储 网络请求数据 + 用过可以通过 ``` computed: { ...mapState({ bannerlist: (state) => state.find.bannerlist, }), }, ``` #### 2.4 attrs 和 listeners #### attrs **场景** 父子组件传值多个属性传值,需要多个props来接收,sttrs就可以解决的这一问题 但是attrs **获取父组件传值拿到的是未在子组件props接收属性** ``` //父组件 <father name="姓名" age="99" imgUrl="963./852dasda.png"> //子组件 mounted(){ console.log(this.$attrs) //拿到的是未被props接收的参数 } ``` #### listeners **场景** 父组件通过 v-on="listeners" 传入内部组件,内部组件可以通过this.$lisenter接收函数 ``` //父组件 <fatherPage @send="send"> //子组件 mounted(){ console.log(this.$listeners) //可以拿到change事件 } ``` #### 2.5 provide 和 inject **场景** 用于高阶插件/组件库,主要通过父级组件向其后代组件注入一个依赖,只要是父级组件内 的组件都可以访问到这个父级传递的属性.不必要在意结构层次.只要是存在上下游关系 ``` //父组件 provide{ //provide 顶i有一个属性和方法 name:'Im is father compoments' sayNmae(){ console.log('Im name Sayname') } } //下游组件 inject:[name,sayName] mounted(){ console.log(this.name) this.sayName() } ``` + 在父组件下面所有的子组件都可以利用inject + provide 和 inject 绑定并不是可响应的。 #### 2.5 parent 和 children parent 父实例 children子实例 ``` //父组件组件 moutend(){ console.log(this.$children) //拿到第一个子级的属性和方法 } //子组件 moutend(){ console.log( console.log(this.$parent) // 可以拿到 parent 的属性和方法 ) } ``` + children和parent 并不保证顺序,也不是响应式的 只能拿到一级父组件和子组件 #### 2.6 $refs **父组件渲染子组件可以通过为子组件绑定ref=""属性 ,在父组件可以通过$refs拿到子组件实例** ``` //父组件 <father ref="home"> mounted(){ console.log(this.$refs.home) } ``` #### 2.6 EventBus **使用** 声明一个全局Vue实例变量EventBus,把所有得数据事件监听都存储到这个得变量 ``` // 在 main.js Vue.prototype.$eventBus=new Vue() // 传值组件 this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值') // 接收组件 this.$eventBus.$on("eventTarget",v=>{ console.log('eventTarget',v);//这是eventTarget传过来的值 }) ```
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签