前面讲解了vue2的单点知识,下面用若依提供的vue项目,实战分析一下,拿到一个vue项目,如何进行分析并进行二次开发。
vue项目是单界面应用,所有的界面将在public下的index.html里呈现。
main.js是程序的入口,在这里,定义了vue实例对象。如下代码:
new Vue({
el: '#app',
router,//路由插件
store,//vuex插件,所有的组件中都可以使用store中的action,mutation和state数据。通过$strore调用或者mapXXX函数映射
render: h => h(App)
})
其中,el配置项是配置vm实例要填充的public/index.html里的元素对象。render属性配置的是用App.vue组件进行填充。在vm实例对象挂载完成之前,即mouted函数执行之前,页面显示的是public/index.html中本身的元素,在挂载完成后,public/index.html中会显示App.vue中的元素。
在public/index.html中,原有的是加载中插件,如下:
<body>
<div id="app">
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div>
</div>
</div>
所以,刷新界面时,先出现加载中界面,如下:

等vm实例挂载完成后,显示App.vue组件内容。
下面分析App.vue中组件的内容。
看template内容:
<template>
<div id="app">
<!-- 路由占位,router-link在哪 -->
<router-view />
</div>
</template>
这里只有router-view,说明这里要进行路由的切换展示。所以,接下来该分析路由的配置,看App.vue跳转到了哪个组件。
路由的配置在router/index.js下,进行分析:
{
path: '',
component: Layout,
redirect: 'index',
children: [
{
path: 'index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
]
}
这段路由配置就是App.vue挂载完成后的展示组件。首先,项目访问路径为’'(空)时,加载的组件是Layout组件,展示Layout组件内容。通过redirect属性重定向到index路径。index是子路由,在Layout中展示index.vue界面。这就是为何每次刷新,默认打开首页tab页的原因。
这里,补充个知识点:
不管是router-link的to属性,还是直接在浏览器输入路径,如果输入的是子路由的路径,那么界面会展示子路由的组件,也会展示父路由的组件。不会单独展示子路由对应的组件。
如:to=/home/SeatDistribute,则对应的view会显示App.vue和Home.vue和/home/SeatDistribute组件。
to=/home,view会显示App.vue组件和Home.vue组件。
根据路径,找router-view的位置:
路径为一层的,如:/home。则对应App.vue中的router-view。
路径为多层的,如/home/SeatDistribute,则找其父组件的router-view,即Home.vue组件中的router-view。
所以,上面重定向到index.vue组件后,也是显示Layout组件的。即在Layout组件内部,再显示index.vue组件。router定义子路由时,默认children子路由就是被父路由包裹的。
通过上面分析,可知App.vue展示的是Layout组件,那么下面就分析Layout组件。通过分析,Layout组件是布局组件,即后台管理系统的整体布局,是通过这个组件完成的。里面包含了很多子组件嵌套。下面先画一下其组件划分结构:

可见,将整体布局划分成上图的几个组件。这也体现出了vue组件化编程的思想。在每个组件内部,又对各个部分进行了组件的拆分,例如在navbar组件中,

每个元素,都划分成了一个组件。这里主要体会组件化编程思想。具体组件的实现方式,这里不做深入研究。已经提供好的功能,我们直接拿来用即可。
在main.js中定义vue的时候,可以看到使用了Vuex技术,如下:
new Vue({
el: '#app',
router,//路由插件
store,//vuex插件,所有的组件中都可以使用store中的action,mutation和state数据。通过$strore调用或者mapXXX函数映射
render: h => h(App),
beforeMount() {
debugger;
}
})
下面就分析一下Vuex技术在项目中是如何应用的。
首先,看stroe/index.js文件:
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app,
user,
tagsView,
permission,
settings
},
getters
})
export default store
可以看到,使用了模块化命名,分成了权限模块,设置模块,用户模块等几个模块。因为Vuex最终操作的都是state对象,所以,重点看一下这几个模块的state对象都存入了什么:
权限模块permission.js:
state: {
routes: [],
addRoutes: [],
defaultRoutes: [],
topbarRouters: [],
sidebarRouters: []
}
可见,权限模块state存入了路由数据。路由可以共享到每个组件去使用。
用户模块user.js:
state: {
token: getToken(),
name: '',
avatar: '',
roles: [],
permissions: []
}
用户模块state定义了token,用户名,用户角色,用户权限等数据,用于共享。
设置模块settings.js:
const state = {
title: '',
theme: storageSetting.theme || '#409EFF',
sideTheme: storageSetting.sideTheme || sideTheme,
showSettings: showSettings,
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
}
可见,settings.js模块定义了皮肤颜色,主题风格,边距等等数据用于共享。
各模块的Actions和Mutations对象定义了各种函数来操作这些state数据,这里就 不一一列举了。
通过上面存入Vuex中的数据可以知道,在项目中,把全局的一些信息,存入Vuex中。这些信息可以是前端自己设定的,也可以是后台获取的数据。这样,在项目的任何一个组件中,都可以通过$store属性或者mapXXX函数获取到这些共享数据。
Vuex有点儿类似于原生js中的全局变量的感觉。
前面讲路由时,路由都是在router/index.js里预置好的。但是在真实项目中,菜单肯定是通过权限,在后台获取的。分析一下若依框架,是如何实现权限分配和动态路由的。
首先找到菜单的组件,上面已经分析过,是Layout组件中的sidebar组件。点进去,看sidebar组件的实现:
<sidebar-item
v-for="(route, index) in sidebarRouters"
:key="route.path + index"
:item="route"
:base-path="route.path"
/>
可见,其遍历了sidebarRouters,而sidebarRouters通过Vuex的分析可知,其配置在了permissions模块的state中。所以,在permissions.js的Actions对象和Mutations对象中,肯定有操作这个数据的函数,找相应的代码。
代码比较分散,下面看其实现思路:
首先,在Actions函数中,利用axios发送请求到后台,获取用户菜单权限,该接口的返回值如下:
{
"msg": "操作成功",
"code": 200,
"data": [{
"name": "System",
"path": "/system",
"hidden": false,
"redirect": "noRedirect",
"component": "Layout",
"alwaysShow": true,
"meta": {
"title": "系统管理",
"icon": "system",
"noCache": false,
"link": null
},
"children": [{
"name": "User",
"path": "user",
"hidden": false,
"component": "system/user/index",
"meta": {
"title": "用户管理",
"icon": "user",
"noCache": false,
"link": null
}
}, {
"name": "Role",
"path": "role",
"hidden": false,
"component": "system/role/index",
"meta": {
"title": "角色管理",
"icon": "peoples",
"noCache": false,
"link": null
}
}, {
"name": "Menu",
"path": "menu",
"hidden": false,
"component": "system/menu/index",
"meta": {
"title": "菜单管理",
"icon": "tree-table",
"noCache": false,
"link": null
}
}, {
"name": "Dept",
"path": "dept",
"hidden": false,
"component": "system/dept/index",
"meta": {
"title": "部门管理",
"icon": "tree",
"noCache": false,
"link": null
}
}, {
"name": "Post",
"path": "post",
"hidden": false,
"component": "system/post/index",
"meta": {
"title": "岗位管理",
"icon": "post",
"noCache": false,
"link": null
}
}, {
"name": "Dict",
"path": "dict",
"hidden": false,
"component": "system/dict/index",
"meta": {
"title": "字典管理",
"icon": "dict",
"noCache": false,
"link": null
}
}, {
"name": "Config",
"path": "config",
"hidden": false,
"component": "system/config/index",
"meta": {
"title": "参数设置",
"icon": "edit",
"noCache": false,
"link": null
}
}, {
"name": "Notice",
"path": "notice",
"hidden": false,
"component": "system/notice/index",
"meta": {
"title": "通知公告",
"icon": "message",
"noCache": false,
"link": null
}
}, {
"name": "Log",
"path": "log",
"hidden": false,
"redirect": "noRedirect",
"component": "ParentView",
"alwaysShow": true,
"meta": {
"title": "日志管理",
"icon": "log",
"noCache": false,
"link": null
},
"children": [{
"name": "Operlog",
"path": "operlog",
"hidden": false,
"component": "monitor/operlog/index",
"meta": {
"title": "操作日志",
"icon": "form",
"noCache": false,
"link": null
}
}, {
"name": "Logininfor",
"path": "logininfor",
"hidden": false,
"component": "monitor/logininfor/index",
"meta": {
"title": "登录日志",
"icon": "logininfor",
"noCache": false,
"link": null
}
}]
}]
}, {
"name": "Monitor",
"path": "/monitor",
"hidden": false,
"redirect": "noRedirect",
"component": "Layout",
"alwaysShow": true,
"meta": {
"title": "系统监控",
"icon": "monitor",
"noCache": false,
"link": null
},
"children": [{
"name": "Online",
"path": "online",
"hidden": false,
"component": "monitor/online/index",
"meta": {
"title": "在线用户",
"icon": "online",
"noCache": false,
"link": null
}
}, {
"name": "Job",
"path": "job",
"hidden": false,
"component": "monitor/job/index",
"meta": {
"title": "定时任务",
"icon": "job",
"noCache": false,
"link": null
}
}, {
"name": "Druid",
"path": "druid",
"hidden": false,
"component": "monitor/druid/index",
"meta": {
"title": "数据监控",
"icon": "druid",
"noCache": false,
"link": null
}
}, {
"name": "Server",
"path": "server",
"hidden": false,
"component": "monitor/server/index",
"meta": {
"title": "服务监控",
"icon": "server",
"noCache": false,
"link": null
}
}, {
"name": "Cache",
"path": "cache",
"hidden": false,
"component": "monitor/cache/index",
"meta": {
"title": "缓存监控",
"icon": "redis",
"noCache": false,
"link": null
}
}]
}, {
"name": "Tool",
"path": "/tool",
"hidden": false,
"redirect": "noRedirect",
"component": "Layout",
"alwaysShow": true,
"meta": {
"title": "系统工具",
"icon": "tool",
"noCache": false,
"link": null
},
"children": [{
"name": "Build",
"path": "build",
"hidden": false,
"component": "tool/build/index",
"meta": {
"title": "表单构建",
"icon": "build",
"noCache": false,
"link": null
}
}, {
"name": "Gen",
"path": "gen",
"hidden": false,
"component": "tool/gen/index",
"meta": {
"title": "代码生成",
"icon": "code",
"noCache": false,
"link": null
}
}, {
"name": "Swagger",
"path": "swagger",
"hidden": false,
"component": "tool/swagger/index",
"meta": {
"title": "系统接口",
"icon": "swagger",
"noCache": false,
"link": null
}
}]
}, {
"name": "Http://ruoyi.vip",
"path": "http://ruoyi.vip",
"hidden": false,
"component": "Layout",
"meta": {
"title": "若依官网",
"icon": "guide",
"noCache": false,
"link": "http://ruoyi.vip"
}
}]
}
分析其返回值,可以看到,就是按照router的格式,将菜单数据进行了返回。其中,子菜单就以children属性,定义在了父菜单下面。菜单名称,定义在了meta属性里面。
这样,就根据用户权限获取了菜单路由信息。下面,看这些信息是如何进行使用的。
还回到Sidebar组件的这段代码:
<sidebar-item
v-for="(route, index) in sidebarRouters"
:key="route.path + index"
:item="route"
:base-path="route.path"
/>
可以看到,涉及到另一个自定义组件sidebar-item,遍历菜单,把获取到的路由信息传了过去,最终实现了菜单的展示和点击出现tab页面。具体实现不再详细解释。
若依框架自定义了几个指令,下面看如何进行自定义指令和这几个指令的作用:
在directive包下,进行了自定义指令。
重点看permissions相关的自定义指令。一个权限指令,一个角色指令,其实现思路就是根据Vuex中user的角色和权限数据,判断是否有某个角色或者某个权限,从而判断是否有权限操作某个按钮。即菜单中按钮权限的判断,是通过自定义指令完成的。
在一个组件中,有很多的标签,当是el-开头的时候,就是element-ui的标签,可以根据官网查找对应属性的意思等。不是以el开头的标签,可能是项目自定义的组件,也可能是第三方组件。具体的点进去一看便知。
前面讲到,history模式下,刷新浏览器,会报404,这里,再说清楚一点。
在开发环境中,即使使用history模式,刷新界面,不会报404,但是项目打包部署到web服务器上后,再访问前端项目,再刷新界面,会报404,这是为何呢?
个人理解,在开发环境中,vue-cli自行解决了history刷新报404的问题,直接通过路由,定位到了相应的组件。但是项目部署到web服务器上后,刷新界面,浏览器中的url直接就发送到web服务器上了,服务器默认并不会处理路径,而是直接根据路径找资源,找不到url的资源,所以就报404了。
项目部署后,如何解决history模式的404问题呢?根据不同的web服务器,进行简单的设置,就可以解决了。
具体可参考:不同的历史模式
下面记录在nginx下部署vue项目的过程。
首先,在package.json中, 运行build命令,对项目进行打包。
打包完成后,在项目根目录下,会生成dist文件,dist文件里,打包好的文件,有个index.html文件,整个vue项目,就在这个单界面里展示。
配置nginx服务器:
首先,配置nginx.config配置文件,重点如下:
server {
listen 80; #nginx端口,也是前端项目访问的端口
server_name localhost;#nginx的ip,也是前端工程访问ip
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root "F:/java_structure/vue/RuoYi-Vue-master/ruoyi-ui/dist";#vue项目打包dist后的路径
index index.html index.htm;#这里配置index就行,不用管
try_files $uri $uri/ /index.html;#解决history刷新报404问题,配置此项后刷新就不再报404了。
}
#vue项目想后台发送请求的前缀。在开发环境中,配置proxyTable可以进行代理转发。在nginx上,在此进行代理转发配置
location ^~/prod-api {
rewrite ^/prod-api/(.*)$ /$1 break; #此配置表明发送到后台的请求不带prod-api,将其自动去掉
proxy_pass http://localhost:8080; #后台服务器路径。此处需要注意,这里的后台服务器,是为vue项目提供数据支撑的服务器。而上面配置的listen和server_name,是nginx的port和ip,也是前端项目的port和ip。解决history模式404的问题,也是解决的nginx服务器返回的404的问题,并不是解决后台项目返回的404的问题,这点一定要清楚。
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
echarts可以和vue很好的配合使用,此外,再提供一个很好的统计报表可视化插件库:Viser
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195
我的Rails站点使用了一个确实不是很好的gem。每次我需要做一些新的事情时,我最终不得不花费与向实际Rails项目添加代码一样多的时间来为gem添加功能。但我不介意,我将我的Gemfile设置为指向我的gem的GitHub分支(我尝试提交PR,但维护者似乎已经下台)。问题是我真的没有找到一种合理的方法来测试我添加到gem的新东西。在railsc中测试它会特别好,但我能想到的唯一方法是a)更改~/.rvm/gems/.../foo。rb,这看起来不对或者b)升级版本,推送到Github,然后运行bundleup,这除了耗时之外显然是一场灾难,因为我不确定我所做的promise是否正
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho