(获取本节完整代码 GitHub/chizijijiadami/hand-to-hand)
1、软件准备
● Visual Studio Code官网
● git官网
● npm官网
(1)以上软件一路默认安装好后,在vscode中打开一个文件夹作为项目目录(File>Open Folder,选择一个文件夹),这里选择D盘下新建的一个projects空文件夹,选择确定后如下图:
(2)点击Terminal或者按【Ctrl+Shift+`】快捷键,打开vscode终端命令行,如下图:
(3)全局安装yarn命令管理工具,在命令行中输入以下命令:
npm install yarn -g
注意:npm执行中若遇“禁止运行脚本”问题,见文章 解决:vscode中npm运行时报“禁止运行脚本”
(4) 安装vue开发脚手架vue-cli
yarn add @vue/cli -g
安装完成后,输入“vue --version”验证一下,如下图:
注意:我们这里用yarn命令开发,习惯用npm的,见文章 yarn和npm常用开发命令对比
(5)新建一个项目“vue create website”(website为自定义项目名),一路默认按Enter
浏览器中输入http://localhost:8080/访问页面,至此一个简单的web项目构建好了,接下来进行下一步,路由设置。
2、路由vue-router ( vue-router官网 )
● 安装vue-router,vscode中方便开发,可以先【Terminal->Split Terminal】分离控制台,不想分离,要结束启动中的项目,在控制台中按【ctrl+c】停止项目,然后安装,再启动等
yarn add vue-router -S
package.json
"dependencies": {
"core-js": "^3.6.4",
"vue": "^2.6.11",
+ "vue-router": "^3.1.6"
}
● 编写页面,新建src>pages>Index>index.vue
pages>Index>index.vue,【关联:export、export default 和 import 用法详解,这一篇就够了】
<template>
<div>Index-index</div>
</template>
<script>
export default {
name:"IndexIndex"
}
</script>
● 写好接下来就该访问了,新建src>router>index.js
router>index.js,【关联:js的 new 运算符详解】
import Vue from 'vue'
import Router from 'vue-router'
import Index from '../pages/Index/index.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'/index',
component:Index
}
]
})
mian.js 中引入路由文件
import Vue from 'vue'
import App from './App.vue'
+ import router from './router'
Vue.config.productionTip = false
new Vue({
+ router,
render: h => h(App),
}).$mount('#app')
App.vue 添加路由渲染组件,删除示例代码
<template>
<div id="app">
- <img alt="Vue logo" src="./assets/logo.png">
- <HelloWorld msg="Welcome to Your Vue.js App"/>
+ <router-view></router-view> //代表将在这里加载你的页面
</div>
</template>
<script>
- import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
- components: {
- HelloWorld
- }
}
</script>
浏览器输入http://localhost:8080/#/index访问。
很容易发现默认路径http://localhost:8080/#/访问不到内容了,这时候要在路由文件中添加默认访问页配置,此时访问http://localhost:8080/#/会自动重定向到redirect中设置的路径。
router>index.js
routes:[
+ {
+ path:'',
+ redirect:'/index'
+ },
{
path:'/index',
component:Index
}
]
输入未定义的路由,发现返回空白,此时应该设置一个404页面提示,404状态代表此页面不存在。
新建页面,pages>ErrorPages>404.vue
pages>ErrorPages>404.vue
<template>
<div>您访问的页面不存在</div>
</template>
router>index.js
import Vue from 'vue'
import Router from 'vue-router'
import Index from '../pages/Index/index.vue'
+ import Error404 from '../pages/ErrorPages/404.vue'
Vue.use(Router)
export default new Router({
routes:[
{
path:'',
redirect:'/index'
},
{
path:'/index',
component:Index
},
+ {
+ path:'/404',
+ component:Error404
+ },
+ {
+ path:'*',
+ redirect:'/404'
+ }
]
})
现在访问未定义的路由,发现都跳转到新编写的404页面了
3、更多开发配置详解
(1)添加其他页面
新建列表页
pages>List>index.vue
<template>
<div>
<p>List-index</p>
</div>
</template>
<script>
export default {
name:"ListIndex"
}
</script>
<style>
p{
background-color: aqua;
}
</style>
router>index.js
import Index from '../pages/Index/index.vue'
+ import List from '../pages/List/index.vue'
import Error404 from '../pages/ErrorPages/404.vue'
{
path:'/index',
component:Index
},
+ {
+ path:'/list',
+ component:List
+ },
{
path:'/404',
component:Error404
},
App.vue
<template>
<div id="app">
+ <header>
+ <nav><router-link to="/index">index</router-link><router-link to="/list">list</router-link></nav>
+ </header>
<router-view></router-view>
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
+ a{
+ margin: 0 10px;
+ }
</style>
分别访问 /index,/list 如下图可见App.vue中是页面公共部分, <header> 标签中导航<router-lint>会被渲染成<a>标签。:添加其他页面也是同样的步骤,编写页面>设置路由>使用。
随着开发进行,页面越来越多,router/index.js中要导入的模板可能就是竖起摩天大楼了,增删都不方便,为了体验更好,下面我们就进行路由文件router/index.js中模板导入的改写,在此之前先进行项目文件路径别名设置。
添加文件,项目根路径下添加 vue.config.js
vue.config.js
const path=require('path')
const resolve=dir=>path.resolve(__dirname,dir)
module.exports={
chainWebpack:config=>{
config.resolve.alias
.set("@",resolve('src'))
}
}
router>index.js
import Vue from 'vue'
import Router from 'vue-router'
- import Index from '../pages/Index/index.vue'
- import List from '../pages/List/index.vue'
- import Error404 from '../pages/ErrorPages/404.vue'
Vue.use(Router)
+ const _import=file=>()=>import('@/pages/'+file+'.vue')
export default new Router({
routes:[
{
path:'',
redirect:'/index'
},
{
path:'/index',
- component:Index
+ component:_import('Index/index')
},
{
path:'/list',
- component:List
+ component:_import('List/index')
},
{
path:'/404',
- component:Error404
+ component:_import('ErrorPages/404')
},
{
path:'*',
redirect:'/404'
}
]
})
改完以后各种访问试一下,都是正常的。其实就是把逐个导入,改成了用函数实现即时导入的形式。
有人问,如果列表页List中还需要子页面怎么设置,这就是嵌套路由了,接着看。
(2)嵌套路由
添加子页面
pages>List>index.vue
<template>
<div>
<p>List-index</p>
+ <h1><router-link to="/list/detail">Detail</router-link><router-link to="/list/feature">Feature</router-link></h1>
+ <router-view></router-view>
</div>
</template>
pages>List>Detail>index.vue
<template>
<div>List-Detail</div>
</template>
pages>List>Feature>index.vue
<template>
<div>List-Feature</div>
</template>
router>index.js
{
path: '/list',
component: _import('List/index'),
+ children: [
+ {
+ path: 'detail',
+ component: _import('List/Detail/index')
+ },
+ {
+ path: 'feature',
+ component: _import('List/Feature/index')
+ }
+ ]
},
切换查看效果,除了样子像tab标签页,浏览器地址栏路由也是切换的,那么如果我们并不想要嵌套路由,只是一个tab切换,应该怎么做呢?
(3) tab标签页切换页
page>List>index.vue
<template>
<div>
<p>List-index</p>
- <h1><router-link to="/list/detail">Detail</router-link><router-link to="feature">Feature</router-link></h1>
- <router-view></router-view>
+ <ul><li @click="changeTab('detail')">detail</li><li @click="changeTab('feature')">feature</li></ul>
+ <div v-show="tab=='detail'" class="detail">detail-tab</div>
+ <div v-show="tab=='feature'" class="feature">feature-tab</div>
</div>
</template>
<script>
export default {
name:"ListIndex",
+ data(){
+ return {
+ tab:'detail'
+ }
+ },
+ methods:{
+ changeTab(tab){
+ this.tab=tab
+ }
+ }
}
</script>
这样就是tab标签页切换效果了,此处的v-show与v-if的区别就是,用户频繁切换用v-show比较好,详见官方解释v-if vs v-show。
如果有多个tab标签,并且每个标签都有不少内容,很容易造成List>index.vue页面过于臃肿,那么此时我们就需要提到组件了。
(4)组件
● 新建引入
这里我们用之前的pages>List>Detail>index.vue和pages>List>Feature>index.vue两个,也可以自己新建。
pages>List>index.vue
<template>
<div>
<p>List-index</p>
<ul><li @click="changeTab('detail')">detail</li><li @click="changeTab('feature')">feature</li></ul>
- <div v-show="tab=='detail'" class="detail">detail-tab</div>
- <div v-show="tab=='feature'" class="featur">feature-tab</div>
+ <div v-show="tab=='detail'" class="detail">
+ <detail></detail> //C、使用
+ </div>
+ <div v-show="tab=='feature'" class="feature">
+ <feature></feature>
+ </div>
</div>
</template>
<script>
+ import Detail from './Detail/index.vue' //A、引入要用组件
+ import Feature from './Feature/index.vue'
export default {
name:"ListIndex",
+ components:{
+ Detail, //B、注册
+ Feature
+ },
data(){
return {
tab:'detail'
}
},
methods:{
changeTab(tab){
this.tab=tab
}
}
}
</script>
步骤就是新建vue模板页>页面中import引入>components中注册>页面中使用,单纯的使用就是以上的A、B、C三步走。
● 传值——父传子
父组件通过设置绑定子组件的属性传值到子组件中,子组件中中props属性接收
pages>List>index.vue
<div v-show="tab=='detail'" class="detail">
- <detail></detail>
+ <detail :deliveryValue="toChildren" :toChildrenObj="toChildrenObj" :toChildrenArr="toChildrenArr"></detail>
</div>
data(){
return {
tab:'detail',
+ toChildren:'传给子组件咯',
+ toChildrenObj:{
+ name:'test',
+ age:12
+ },
+ toChildrenArr:[
+ {item:'1'},
+ {item:'2'}
+ ]
}
},
pages>List>Detail>index.vue
<template>
- <div>List-Detail</div>
+ <div>
+ <div>List-Detail</div>
+ <p>{{deliveryValue}}</p>
+ <p>{{toChildrenObj}}</p>
+ <p>{{toChildrenArr}}</p>
+ </div>
</template>
+ <script>
+ export default {
+ props:['deliveryValue','toChildrenObj','toChildrenArr']
+ }
+ </script>
子组件中用来接收的值名就是父组件中绑定时“:”后面的属性名。父子组件传值用名可以一样,但是在子组件 props 中接收过的值相当于是声明,是不可以在子组件的data中再次声明的,子组件中如果下面这么写:
props:['deliveryValue','toChildrenObj','toChildrenArr'],
data(){
return {
deliveryValue:'123', 报错,不可以
test:{
deliveryValue:"123" 正常,可以
}
}
}
更多见官网通过-Prop-向子组件传递数据
还有个样式问题,发现在 List/Detail/index.vue 中的 <p> 标签样式背景色是 List/index.vue 中设置生效的,原来在<style>中设置的样式是在全局生效的,若想只在此模板中生效需要加 “scoped”,如下:
pages>List>index.vue
- <style>
+ <style scoped>
p{
background-color: aqua;
}
</style>
保存观察浏览器,发现只有List/index.vue中的<p>标签背景色改变了,那么想在List/index.vue中设置子组件中<p>标签的样式就需要另写一个<style>标签不加 scoped ,还有一个方法如下:
<style scoped>
p{
background-color: aqua;
}
+ .detail >>> p{ 或者将>>>替换成 /deep/ 也行
+ background-color: red;
+ }
</style>
● 传值——子传父
page>List>index.vue
<div v-show="tab=='feature'" class="feature">
- <feature></feature>
+ <feature @changeTab="changeTab"></feature>
</div>
pages>List>Feature>index.vue
- <div> List-Feature</div>
+ <div>
+ List-Feature
+ <button @click="$emit('changeTab','detail')">切换到 Detail tab</button>
+ </div>
可以看到传事件与传值除了“:”换成“@”其他形式是一样,只不过在子组件中触发的时候不要接收,直接用 $emit(name,[]param]) 去触发就好了。
(5)资源引入
● 图片引入
新建src>assets>images文件夹,放一张图片进去,在src>pages>Index>index.vue中引入, ~@ 指代根路径src。
src>pages>Index>index.vue
<template>
- <div>Index-index</div>
+ <div>
+ <p>Index-index</p>
+ <img src="~@/assets/images/jerry.png" alt="" srcset="">
+ </div>
</template>
关于 svg 图片批量导入的问题,我们在后续的稳重后台模板开发中说明。
● 样式引入
新建src>assets>styles文件夹,再新建两个样式文件,随意写些样式文件,在main.js中引入
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
+ import './assets/styles/reset.css'
+ import './assets/styles/style.css'
还可以在组件页面中引入,新建 src>assets>styles>component.css,
src>assets>styles>component.css
p.index-p{
color: red;
}
src>pages>Index>index.vue
<template>
<div>
- <p>Index-index</p>
+ <p class="index-p">Index-index</p>
<img src="~@/assets/images/jerry.png" alt="" srcset="">
</div>
</template>
<script>
export default {
name:"IndexIndex"
}
</script>
+ <style>
+ @import '~@/assets/styles/component.css'
+ </style>
为了方便样式书写,这里推荐结合css的预处理器stylus编写项目,详见拓展 vue实践1.1 企业官网——prerender-spa-plugin预渲染 第2部分结合stylus开发使用说明。
4、打包部署
(1)基本打包,如下图, yarn build 进行打包。完成后发现,根目录下多了 dist 文件夹,进去访问 index.html 文件,发现浏览器中一片空白,这是因为打包时未设置资源的访问路径。
vue.config.js
const path=require('path')
const resolve=dir=>path.resolve(__dirname,dir)
module.exports={
+ publicPath:'./',
chainWebpack:config=>{
config.resolve.alias
.set("@",resolve('src'))
}
}
重新打包 yarn build 访问,一切正常。把dist文件夹发给后端,部署服务器就可以了。至此,基本的开发打包步骤已完成,下面进行一些开发打包基本配置的说明。
(2)打包基本配置
开发、测试和生产环境
大多时候我们在开发、测试和生产这三个场景中有同一个变量需要不同值的需求,这时候我们可以建立三个对应的环境文件去解决。
开发 .env.development
// 开发 环境配置
// 变量必须以VUE_APP开头,会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中
//代码中可以通过 process.env.VUE_APP_BASE_API 访问
// NODE_ENV 和 BASE_URL 是两个特殊变量,在代码中始终可用
NODE_ENV = 'development'
VUE_APP_BASE_API = 'http://192.168.0.1'
测试 .env.testing
// 测试 环境配置
// 变量必须以VUE_APP开头,会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中
//代码中可以通过 process.env.VUE_APP_BASE_API 访问
// NODE_ENV 和 BASE_URL 是两个特殊变量,在代码中始终可用
NODE_ENV = 'testing'
VUE_APP_BASE_API = 'http://192.168.0.200'
生产 .env.production
// 生产 环境配置
// 变量必须以VUE_APP开头,会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中
//代码中可以通过 process.env.VUE_APP_BASE_API 访问
// NODE_ENV 和 BASE_URL 是两个特殊变量,在代码中始终可用
NODE_ENV = 'production'
VUE_APP_BASE_API = 'http://192.168.0.100'
变量的使用在项目中用 process.env 可以取到,在启动或者打包中使用到不同配置,则需要改写package.json文件,package.json 文件中scripts 内就是 yarn 可以运行的命令,修改完package.json文件后,需要重新启动项目生效,此时 yarn serve 命令就是运行的 vue-cli-service serve --mode development。
package.json
"scripts": {
- "serve": "vue-cli-service serve",
- "build": "vue-cli-service build",
+ "serve": "vue-cli-service serve --mode development",
+ "serve-pro": "vue-cli-service serve --mode production",
+ "serve-test": "vue-cli-service serve --mode testing",
+ "build": "vue-cli-service build --mode production",
+ "build-dev": "vue-cli-service build --mode development",
+ "build-test": "vue-cli-service build --mode testing",
"lint": "vue-cli-service lint"
},
在src>pages>Index>index.vue中试一下
src>pages>Index>index.vue
export default {
name:"IndexIndex",
+ created(){
+ console.log(process.env.VUE_APP_BASE_API,'输出VUE_APP_BASE_API');
+ }
}
在浏览器中按【F12】可以看到控制台中看到,自定义的变量可以正常取用。
● yarn lint
上面改写时,发现package.json文件scripts中有 lint 这个命令,这是js代码检测工具EsLint的使用,一般在代码提交前使用此命令来检查错误、规范代码等,具体内容见 ESLint中文官网。
● 生产环境去console
项目开发中我们常常用控制台 console 输出各种数据,如果发布到生产环境不太好,但是每次发布删掉又很麻烦,那么我们可以这么设置。
安装去console插件 babel-plugin-transform-remove-console
yarn add babel-plugin-transform-remove-console -D
babel.config.js
+ const plugins = ["@vue/babel-plugin-transform-vue-jsx"]
+ // 生产环境移除console
+ if(process.env.NODE_ENV === 'production') {
+ plugins.push("transform-remove-console")
+ }
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
+ plugins:plugins
}
以生产环境模式运行一下,发现控制台空空如也。
yarn serve-pro
(3)拓展——自己搭建后端服务器,进行项目部署
● 安装
这里我们用致力于让天下没有难配的服务器环境phpStudy集成环境 phpStudy官网,可以进行傻瓜式的搭建。下载解压,点击安装文件安装
● 访问,不修改端口的话,直接启动访问就行
因为80端口经常被占用这里我们修改一下默认配置,注意不冲突不修改也行
修改确认后,启动后,在下方网站列表里可以看到这个服务器,点击管理,选择打开网站
发现显示无法访问,那是因为我们修改过访问端口,在地址栏里加入我们自己修改的端口就行,这是默认的页面。
● 打包发布
项目中打包 yarn build,发现生成了dist文件夹,这就是我们可以发布的网站内容了
yarn build
phpStudy网站>管理>打开根目录,删除WWW下的文件,将我们dist文件中的文件放进去,刷新浏览器访问,就访问到我们的网站了。
通常这一步是由后端操作,作为对自己有要求的前端,我们希望前端自己主动掌握这些基本的后端知识。
至此,我们完成了网站的开发到发布的所有步骤。
状态管理,权限管理,多页,CSS预处理,SSR等我们后续介绍。
感谢阅读,喜欢的话点个赞吧:)
更多内容请关注后续文章。。。
二、vue+ElementUI开发后台管理模板—布局
三、vue+ElementUI开发后台管理模板—功能、资源、全局组件
四、vue+ElementUI开发后台管理模板—方法指令、接口数据
五、vue+ElementUI开发后台管理模板—精确到按钮的权限控制