首先我们来说说我们为什么需要脚手架?
以前有的时候我们简单的写个页面代码是直接写在一个html文件中,写完了可以直接打开看效果。但是如果是一个完整的项目涉及模块化以及组件化开发,这个项目想要跑起来我们不可能直接去打开某个页面看效果。毕竟一大堆vue文件我们的浏览器压根不认识。而Vue的脚手架就可以让我们快速的将一个Vue项目跑起来。我们还可以借助它将我们的项目编译成原始的html、css文件,让我们的浏览器可以认得它。
当然这只是其中一个好处,脚手架还能帮我们进行依赖管理,版本管理等等
我们直接使用脚手架创建一个项目my-app:
vue create my-app
注意:
这里不能使用驼峰命名法,不能有大写字母
在一个html文件中我们想使用Elemen-UI直接使用script引入外部脚本即可,Element-UI官网上的helloworld就是这么做的:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-button @click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world">
<p>Try Element</p>
</el-dialog>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function() {
return { visible: false }
}
})
</script>
</html>
注意:
script标签在没有声明类型的情况下,默认是引入外部的脚本,如果引入某个模块,资源就会加载失败。
那么我们在项目中怎么使用Element-UI呢?
首先我们要使用包管理工具下载Element-UI的依赖:
npm i element-ui -S
我们来详细说说这个命令:
在CLI创建的项目中我们使用的是包管理工具。package.json表示我们的项目配置文件:
我们可以看到devDependencies和dependencies这两个属性:
我们项目中的node_modules文件夹就装着我们项目所需的依赖文件。上面的这条命令就是将element-ui下载到我们的node_modules文件夹中。
对于CLI项目而言,在我们使用启动命令的时候,他会通过webpack将我们项目中的vue文件通过打包的方式变成静态资源,然后运行在我们本地的开发服务器上。(打包包括了我们项目中的依赖、组件文件、页面等)
我们命令中的-S
的作用就是:它会把我们下载的依赖添加到package.json文件中,后面即使我们没有了node_modules文件夹,我们也可以根据我们的package.json依赖文件从而重新去进行下载。
这里有两种方式:
在 main.js 中写入以下内容:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
以上代码便完成了 Element 的引入。需要注意的是,样式文件需要单独引入。
Vue.use(ElementUI)
是将ElementUI里面的组件全局注入到Vue中。
直接查看官方文档即可,这里不多赘述
按需引入
按需引入可以在代码打包的时候减小我们代码的体积。
安装依赖:
npm i vue-router@3.6.5
然后我们创建router文件夹,在此文件夹中创建index.js。
因为我们是模块化工程,所以我们要在index.js文件中首先添加:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
然后开始一系列的基本操作:
注意这里爆红是因为我们的name值不符合eslint的规范,我们可以在vue.config.js文件中将他关闭:
注意这里的name属性是与
router/index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "../pages/Home"
import User from "../pages/User"
Vue.use(VueRouter)
const router = new VueRouter({
routes:[
{
path:"/home",
component:Home
},
{
path: "/user",
component: User
}
]
})
export default router
然后我们通过访问http://localhost:8080/#/user
,http://localhost:8080/#/home
就可以看到我们路由对应的组件了。
我们这里直接借助Element-UI快速布局我们的首页框架,我们的成体如下:
直接粘贴代码:
Main.vue:
<template>
<div>
<el-container>
<el-aside width="200px">
Aside
el-aside>
<el-container>
<el-header>
Header
el-header>
<el-main>
<router-view>router-view>
el-main>
el-container>
el-container>
div>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
我们直接在Elemet-UI中找到对应的样式。
我们在NavMenu 导航菜单
一栏找到如下的样式:
考虑到菜单栏是一个功能比较单一的部分,所以我们把它独立封装成一个组件命名为CommonAside
,并将其放在component包下:
<template>
<div>
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
<el-radio-button :label="false">展开el-radio-button>
<el-radio-button :label="true">收起el-radio-button>
el-radio-group>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location">i>
<span slot="title">导航一span>
template>
<el-menu-item-group>
<span slot="title">分组一span>
<el-menu-item index="1-1">选项1el-menu-item>
<el-menu-item index="1-2">选项2el-menu-item>
el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3el-menu-item>
el-menu-item-group>
<el-submenu index="1-4">
<span slot="title">选项4span>
<el-menu-item index="1-4-1">选项1el-menu-item>
el-submenu>
el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu">i>
<span slot="title">导航二span>
el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document">i>
<span slot="title">导航三span>
el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting">i>
<span slot="title">导航四span>
el-menu-item>
el-menu>
div>
template>
<style>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
style>
<script>
export default {
name:"CommonAside",
data() {
return {
isCollapse: true
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
}
}
}
script>
然后我们在Main组件中进行引入:
然后放到我们的侧边导航栏区域
这里引入的组件标签最好是使用小驼峰+中划线的标准形式:
我们拿到下图这种样式之后,先跟我们目标导航栏做个对比。我们可以发现我们要做的导航栏有两种选项,一种是带子项的,另一种是不带子项的。
于是我们保留导航一、导航二,将导航三、四删掉。
然后来看看我们的菜单栏数据:
[
{
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
},
{
path: '/mall',
name: 'mall',
label: '商品管理',
icon: 'video-play',
url: 'MallManage/MallManage'
},
{
path: '/user',
name: 'user',
label: '用户管理',
icon: 'user',
url: 'UserManage/UserManage'
},
{
label: '其他',
icon: 'location',
children: [
{
path: '/page1',
name: 'page1',
label: '页面1',
icon: 'setting',
url: 'Other/PageOne'
},
{
path: '/page2',
name: 'page2',
label: '页面2',
icon: 'setting',
url: 'Other/PageTwo'
}
]
}
]
我们可以根据是否有children将我们的导航栏分为有孩子和无孩子的。这里我们可以使用计算属性分类:
computed: {
//筛选没孩子的
noChildren() {
return this.menuData.filter(item => !item.children)
},
//筛选有孩子的
hasChildren() {
return this.menuData.filter(item => item.children)
}
},
然后将有孩子的放到导航二中去用for循环进行遍历,将没有孩子的放到导航一中去用for循环进行遍历:
<template>
<div>
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
<el-radio-button :label="false">展开el-radio-button>
<el-radio-button :label="true">收起el-radio-button>
el-radio-group>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<el-menu-item :index="item.name" v-for="item in noChildren" :key="item.name">
<i :class="`el-icon-${item.icon}`">i>
<span slot="title">{{item.label}}span>
el-menu-item>
el-menu>
div>
template>
这里有几个注意点:
我们打开页面的时候,整个导航列表应该还是展开的(不包括子栏),这个怎么去控制呢?
我们可以查看Element-UI的官方文档:
可以发现是通过collapse
属性进行控制的,那么我们将它设为false即可
我们在遍历的时候需要一个索引key,我们可以去用name属性当作这个key
然后就是图标问题:
我们使用的是Element-UI里面提供的Icon图标集合,我们发现他们都有共同的前缀el-icon
:
然后我们的菜单数据中提供了图表的后缀,我们将前缀与后缀相结合给class赋值,即可得到对应的图标:
这里我们使用的是js字符串的模板语法
最后一点我们在for循环的时候需要将el-menu-item
中的index属性也赋值称为一个独一无二的值:
如果不设置的话点击一个选项栏,其他的选项栏也会产生高亮
方法和注意点与一级菜单相似,我们这里直接上代码:
<el-submenu index="1" v-for="item in hasChildren" :key="item.name">
<template slot="title" >
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{item.label}}</span>
</template>
<el-menu-item-group v-for="child in item.children" :key="child.name">
<el-menu-item :index="child.name">{{child.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
一级二级导航栏代码整合:
<template>
<div>
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
<el-radio-button :label="false">展开</el-radio-button>
<el-radio-button :label="true">收起</el-radio-button>
</el-radio-group>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse">
<el-menu-item :index="item.name" v-for="item in noChildren" :key="item.name">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{item.label}}</span>
</el-menu-item>
<el-submenu index="1" v-for="item in hasChildren" :key="item.name">
<template slot="title" >
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{item.label}}</span>
</template>
<el-menu-item-group v-for="child in item.children" :key="child.name">
<el-menu-item :index="child.name">{{child.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</div>
</template>
经过对比我们要对以下的几点进行优化:
展开收起
按钮接下来我们一个个的说一下解决思路与代码:
1)背景颜色以及字体颜色、被选择时的颜色优化
我们这一块的配置都是沿用Element-UI的示例:
我们找到它的代码:
我们可以看到我们上述的几个属性都在这里设置好了,官方文档里面也有介绍:
我们直接cv过来,然后我们还有一个注意点,初始化的时候默认就选择了首页项,也就是说我们直接把首页项设为默认高亮,这个需求可以借助default-active属性来完成。完整代码如下:
<el-menu default-active="home" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
2)去掉展开收起
按钮
3)浏览器默认margin,padding的优化
我们直接在App组建的Style中对样式进行修改。
因为最后编译的时候那些网页结构样式什么的实际都会汇总到App组件中来。
注意:style标签不要使用scoped,否则就会只因为作用在当前组件样式,而无法改变我们规定的样式
4)去掉滚动条
首先我们要明白为什么会出现滚动条?大多数情况是因为容器的内容大过了容器的体积,我们分析页面可以发现这个滚动条是因为el-menu的右边界有1px突出来了:
我们把这个值设为0就可以发现滚动条消失:
接下来我们进行修改:
5)菜单栏上方标题的优化
这个地方我们选择使用less样式来解决这个问题
我们主要使用的是less的嵌套特性,与css变化不是很大。
我们要使用less少不了两个东西:
- less的依赖
- less的解析器
安装代码(适用于本项目的版本):
- npm i [email protected]
- npm i [email protected]
然后使用less语法进行修改:
<style lang="less" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-menu {
border-right:solid 0px #e6e6e6;
h3 {
text-align: center;
font-size: 16px;
color: #ffffff;
font-weight: 400;
}
}
</style>
6)菜单栏长度的优化
我们直接使用height=100vh
即可,这里的100vh代表占满页面的高度
菜单点击跳转功能有两种方法:
第一种实现方法我们只需要一行代码就可以解决!
我们从Element-UI官方文档注意到Menu Attribute下有一个router属性:
它以index作为路由进行跳转,恰好我们是使用数据中的name属性作为index,而我们配置路由的时候正好与name属性相契合:
我们在菜单上绑定点击事件并向回调函数传入数据对象,再利用这些数据对象完成路由的跳转。
jumpto方法:
jumpTo(item){
if (this.$route.path !== item.path && !(this.$route.path === "/home" && item.path === "/")){
this.$router.push(item.path)
}
}
这个jumpto方法就解决了点击相同路由时会爆红的问题,其中的逻辑主要有如下两条:
/
,而当前的路由为/home
则不跳转(也就是下面要说的路由重定向的情况)最后就是路由的重定向问题,我们发现在点击首页栏的时候地址栏显示的是:
http://localhost:8080/#/
而我们点击主页的时候想要显示home组件,所以我们要重定向路由,我们借助redirect来实现:
如果这里路由的多级关系正不清楚,可以看几个嵌套路由的案例马上就能明白。
我们完成这个只需要如下三步:
步骤一:引入左边的按钮、文字
我们发现最后一排的按钮符合我们的基本预想,中间是可以有一个图片的。
我们把代码粘过来,然后做一些修改:
<el-button icon="el-icon-menu" size="mini">el-button>
三处修改:
步骤二:引入右边的下拉框
在Element-UI中找到下拉菜单栏:
这个下拉菜单就符合我们的要求,我们只需要把他的展开项换成我们的头像即可:
修改之前:
<el-dropdown>
<span class="el-dropdown-link">
下拉菜单<i class="el-icon-arrow-down el-icon--right">i>
span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>黄金糕el-dropdown-item>
<el-dropdown-item>狮子头el-dropdown-item>
<el-dropdown-item>螺蛳粉el-dropdown-item>
<el-dropdown-item disabled>双皮奶el-dropdown-item>
<el-dropdown-item divided>蚵仔煎el-dropdown-item>
el-dropdown-menu>
el-dropdown>
修改之后:
<el-dropdown class="dropdown r-part">
<span class="el-dropdown-link">
<img src="../assets/user.png" alt="">
span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心el-dropdown-item>
<el-dropdown-item>退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
步骤三:更改背景颜色,并完成布局
这里我们使用弹性布局
如果你还不熟悉弹性布局,点击复习:
Flex 布局语法教程
space-between:两端对齐,项目之间的间隔都相等。
但是要注意:我们如果直接使用的话,我们的首页两个字会跑到中间去,所以我们可以选择用一个盒子将首页和我们的按钮装到一块,这样就可以解决这个问题。
整体代码如下:‘
CommenHeader.vue:
<template>
<div class="header-container">
<div class="l-part">
<el-button icon="el-icon-menu" size="mini">el-button>
<span>首页span>
div>
<el-dropdown class="dropdown r-part">
<span class="el-dropdown-link">
<img src="../assets/user.png" alt="">
span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心el-dropdown-item>
<el-dropdown-item>退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
div>
template>
<script>
export default {
name: "CommonHeader"
}
script>
<style lang="less" scoped>
.header-container {
.l-part {
font-size: 14px;
span {
color: #ffffff;
margin-left: 10px;
}
}
background-color: #333;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0px 20px;
.dropdown {
img {
height: 40px;
width: 40px;
border-radius: 50%;
}
}
}
style>
Yarn是什么?
“Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如官方文档中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。”这句话让我想起了使用npm时的坑了:
npm install
的时候巨慢。特别是新的项目拉下来要等半天,删除node_modules,重新install的时候依旧如此。"5.0.3",
"~5.0.3",
"^5.0.3"
“5.0.3”表示安装指定的5.0.3版本,“~5.0.3”表示安装5.0.X中最新的版本,“^5.0.3”表示安装5.X.X中最新的版本。这就麻烦了,常常会出现同一个项目,有的同事是OK的,有的同事会由于安装的版本不一致出现bug。
带着这些坑,我开始了解Yarn的优势及其解决的问题。
Yarn的优点?
技巧一:
我们可以直接在控制台中进行样式的调试,等满意之后我们再去项目中进行修改:
技巧二:
我们想要获取网页上的元素信息的时候,可以直接在样式或者计算样式中找到:
技巧三:
我们在对结构附加样式的时候,不需要去分析自己的结构然后思考加在哪里,我们可以直接借助开发者工具,点击元素根据显示的class或者id来进行添加。
如果你使用了Element-UI框架也可以使用,你通过工具得到的class可能在编译器中显示没有或未使用,但是当网页编译完成之后,这些框架中的组件提供的样式也会变成原生的html元素,所以最终你的样式还是会奏效。
如果要这样的话,样式标签最好不要加scoped,否则会失效