Vue
0、前言
概念:一款渐进式 JavaScript 框架、所谓渐进式就是逐步实现新特性的意思、如实现模块化开发、路由、状态管理新特性。其特点是综合了Angular(模块化)和 React (虚拟DOM)的优点
注:Vue处理DOM、Axios处理前端通信框架、类似于AJAX与服务器进行交互、也可使用原生的jQuery的ajax进行通信。
0.1、UI框架
- Ant-Design:阿里巴巴出品,基于React
- ElementUI、iview、ice:饿了么出品,基于 Vue 的 UI 框架
- Bootstrap:Twitter推出的用于前端开发的开源工具包
- AmazeUI:HTML5跨屏前端框架(常用)
0.2、JavaScript构建工具
- Babel:JS编译工具、主要用于浏览器不支持的ES新特性、比如用于编译 TypeScript
- WebPack:模块打包器、主要作用是打包、压缩、合并及按序加载
0.3、ElementUI
- vue-element-admin(掌握)
0.4、MVVM
异步通信为主、Model、View、ViewModel
0.5、Vue开发
基于NodesJs,实际开发采用 vue-cli 脚手架,vue-router 路由(页面跳转),vuex做状态管理(类似于cookie),Vue UI 界面一般使用 ElementUI或者ICE。
1、第一个vue
vue分为三层、View、ViewModel(连接视图和数据的中间件)、Model(模型层,表示js中的对象)
双向数据绑定:ViewModel可以监听Model里面的对象,如果里面对象值发生改变,能够立即反馈到View层并显示。
即、如果在浏览器的控制台中输入vm.message="1111"
那么页面上的hello,vue会变成1111且不需要刷新页面。
好处:解耦了前端与后端,且可以在模型层中模拟后端的数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"hello,vue!"
}
});
</script>
</body>
</html>
2、v-bind
作用:相当于代替了{{}}
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"hello,vue!"
}
});
</script>
3、v-if、v-else、v-else-if
<body>
<div id="app">
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
type: 'A'
}
});
</script>
</body>
4、v-for
<body>
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}--{{index}}
</li>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
items: [
{message:'邹某1'},
{message:'邹某2'},
{message:'邹某3'}
]
}
});
</script>
</body>
5、事件绑定:v-on:click
1、click是按钮点击事件、可在https://www.jquery123.com/
jQuery中文文档中查看相应的事件
<body>
<div id="app">
<button v-on:click="sayHi">点击</button>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message: "1111"
},
methods: {
// 方法必须绑定在 Vue 的 methods 对象中,v-on:事件
sayHi: function (){
alert(this.message);
}
}
});
</script>
</body>
6、表单的双向绑定
含义:如在输入框中输入数据,此数据会实时赋值给已绑定的变量
注意:v-model 会忽略所有表单元素的 value 、checked、selected、特性的初始值而始终将Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
6.1、文本框绑定
<body>
<div id="app">
单行文本:<input type="text" v-model="message" value="hello"/>{{message}}
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message: ""
},
});
</script>
</body>
6.2、下拉框绑定
注:在苹果系统中如果v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。这会使第一项无法被选中,因为此情况下,ios不会触发change
事件,所以我们需要给下拉框指定初始值(disabled)并将初始值置空(让用户无法选择此项)
<body>
<div id="app">
下拉框:
<select v-model="message">
<option value="" disabled>--请选择--</option>
<option>--A--</option>
<option>--B--</option>
<option>--C--</option>
</select>
<span>value:{{message}}</span>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message: ""
},
});
</script>
</body>
7、组件(即标签)
**props:[‘z’]**参数传递
template: '<li>{{z}}</li>'
:自定义标签
el:"#app"
:绑定标签的id
data: {items: ["java","Linux","前端"]}
: 数据域
data(){return{}}
:数据方法,里面存放与数据有关的方法,return是返回值方法
methods: {}
:存放方法的地方
computed: {}
:存放计算属性的地方
可以任意创建标签(即组件),让标签映射在vue中。
通过 Vue.component
创建组件zou后、我们想遍历输出items中的值,可以利用v-for
设置在组件 zou 中,然后将组件 zou 与变量 z 绑定、通过 props 可以获取到 z 的值,即每一个遍历出来的 item 的值都传给了z ,然后获取z 的值 放入我们设置好的 template组件中。
<body>
<div id="app">
<zou v-for="item in items" v-bind:z="item"></zou>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
Vue.component("zou",{
props: ['z'],
template: '<li>{{z}}</li>'
});
var vm = new Vue({
el:"#app",
data: {
items: ["java","Linux","前端"]
}
});
</script>
</body>
8、Axios异步通信
是一个开源的可以用在浏览器端和NodeJS的异步通信框架 ,它的主要作用就是实现AJAX异步通信,其功能特点如下:
-
从浏览器中创建
XMLHttpRequests
-
从 node.js 创建 http 请求
-
支持 Promise API [JS中链式编程]
-
拦截请求和响应
-
转换请求数据和响应数据
-
取消请求
-
自动转换 JSON 数据
-
客户端支持防御 XSRF (跨站请求伪造)
中文文档:http://www.axios-js.com
一般开发采用json格式,所以我们模拟一段json数据
{
"name": "zou",
"url": "https://blog.csdn.net/qq_43483251?orderby=ViewCount",
"address": {
"street": "含光门",
"city": "2",
"country": "1"
}
}
需要添加在线的或者下载
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
代码:
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--v-clock:解决闪烁问题-->
<!--在v-clock绑定的标签上执行,如果未加载完则一直显示白板,直到加载完成-->
<style>
[v-clock]{
display: none;
}
</style>
</head>
<body>
<div id="app" v-clock>
<div>{{info.name}}</div>
<div>{{info.address.street}}</div>
<a v-bind:href="info.url">点我</a>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
// data是属性,下面这个是方法,可以接受异步通信的返回值,要ES6.0才行,5.1报错
data(){
return{
// 请求的返回值参数合适、必须和json字符串一样
info:{
name: null,
address: {
street: null,
city: null,
country: null
},
url: null
}
}
},
// 在vue生命周期内的钩子函数
mounted(){
// 链式编程、ES6新特性
// 从文件data.json中取出值放入response中然后通过response.data赋值给this.info
axios.get('../data.json').then(response=>(this.info=response.data));
}
});
</script>
</body>
9、计算属性
computed
1、第一次调用 currencyTime02
它会运行,并返回结果,但是第二次调用且里面数据未发生变化时,是直接在内存中获取值。即,运行第一次后会将运行结果存放在内存中,如果在第二次调用前,方法中的数据未被更改,则直接从内存中取出值进行返回(相当于缓存概念),如果数据发送过改变,则会重新运行方法并返回和再次存储结果。
2、methods
的调用只能是以方法的形式:{{currencyTime01()}}
3、computed
的调用只能以变量的形式:{{currencyTime02}}
<body>
<div id="app">
<p>1: {{currencyTime01()}}</p>
<p>2: {{currencyTime02}}</p>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data: {
message: "zou"
},
// 使用方法方式且有返回值
methods: {
currencyTime01: function () {
return Date.now() // 获得当前时间戳
}
},
// 使用计算属性的方式、俩方式中的方法名不能相同、重名之后只会调用methods的
computed: {
currencyTime02: function () {
this.message;
return Date.now();
}
}
});
</script>
</body>
第一次结果:
第二次结果:即手动改变 currencyTime02
中的 message
值再调用两个方法
第三次,不改变任何数据只是重新调用两方法
可以看到(看右边的控制台输出),第一个方法重新获取了时间戳、第二个方法是返回的原来时间戳
10 、插槽
定义:利用类似占位符的效果,暂时占据一个位置,这个位置可之后编写一段内容后替换此占位符,一定程度上可以有复用的效果
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items>
</todo>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
// slot 插槽
Vue.component("todo",{
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component("todo-title",{
props: ['title'],
template: '<div>{{title}}</div>'
});
Vue.component("todo-items",{
props: ['item'],
template: '<li>{{item}}</li>'
});
var vm = new Vue({
el:"#app",
data: {
title: "zou",
todoItems: ["1","2","3"]
}
});
</script>
</body>
11、自定义事件内容分发
(此下内容是上面内容的引申)当我们需要删除上面列表中的1 2 3时,因为作用域问题,即想要删除的数据与插槽定义的地方不一样,所以定义插槽的地方不能直接拿到数据并删除,所以我们需要将数据与todo
标签双向绑定,且将删除按钮作为 v-on
的参数形成另一种按钮绑定事件 v-on:remove
即 remove 相当于 click 。后面的
removeItems(index)
相当于当点击删除按钮时,删除按钮自身通过双向绑定机制通知 v-on:remove
标签,然后标签 调用 removeItems(index)
方法用来达到删除的目的,而上述删除按钮反馈给标签的代码是 this.$emit('remove',index)
:自定义事件分发
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item="item" :index="index" v-on:remove="removeItems(index)"></todo-items>
</todo>
</div>
<!--1、导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script>
// slot 插槽
Vue.component("todo",{
template: '<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component("todo-title",{
props: ['title'],
template: '<div>{{title}}</div>'
});
Vue.component("todo-items",{
props: ['item','index'],
template: '<li>{{item}}---{{index}}<button @click="remove">删除</button> </li>',
methods: {
remove: function (index) {
// this.$emit 自定义事件分发
// 这个remove是绑定上面的 removeItems(index),当按钮被点击,此方法被触发,因为有双向响应机制,
// 所以上面的remove会知道并通知下面的 removeItems 方法并运行下面的方法以达到删除目的
this.$emit('remove',index)
}
}
});
var vm = new Vue({
el:"#app",
data: {
title: "zou",
todoItems: ["11","21","31"]
},
methods: {
removeItems: function (index) {
console.log("删除了: "+ this.todoItems[index])
this.todoItems.splice(index,1) // 删除数组中第index索引后的 1 个数(从此索引开始删除)
}
}
});
</script>
</body>
12、vue-cli
官方提供的一个脚手架,用于快速生成一个 vue 的项目模板
脚手架:已经写好了目录结构和基础代码。
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
12.1、需要的环境
- Node.js:http://nodejs.cn/download/
- Git : https://git-scm.com/downloads
- 镜像 :https://npm.taobao.org/mirrors/git-for-windows/
确认nodejs安装成功
-
cmd下输入
node -v
,会打印版本号 -
npm -v
npm 一个软件包管理工具,和Linux下的apt软件按钮差不多
安装 Node.js 淘宝镜像加速器(cnpm)
# -g 全局安装
npm install cnpm -g
# 可使用如下语句解决 npm 速度慢问题
npm install --registry = https://registry.npm.taobao.org
(一)npm国内淘宝npm镜像的使用
1.临时使用 npm --registry https://registry.npm.taobao.org install express
2.持久使用 npm config set registry https://registry.npm.taobao.org
3.检查配置是否成功 npm config get registry
4.通过cnpm使用 npm install -g cnpm --registry=https://registry.npm.taobao.org
安装路径:C:\Users\邹飞鸣\AppData\Roaming\npm
安装vue-cli
cnpm install vue-cli -g
# 测试
# 查看有哪些模板、通常44使用 webpack
vue list
执行上述两步后的截图
12.2、第一个vue-cli应用程序
1、选择一个文件夹E:\vue代码
2、管理员运行cmd、cd 到上面目录下、执行:
# myvue 是项目名字、下面是创建一个webpack类型的脚手架
vue init webpack myvue
vue build standalone
:表示运行时编译
3、初始化并运行
cd myvue # 进入目录
npm install # 下载依赖
npm run dev # 运行项目
ctrl+c #退出
- build:构建目录、一些打包工具
- config:里面的
index.js
有启动后项目运行的网址和端口号,可修改 - node_modules:存放依赖
- src:编写代码的地方
- static:静态资源存放处、只有放入此处才能访问到
- index.html:程序入口,里面东西一般不需要改变
- package.json:打包需要构建的版本,无则打包失败
13、webpack学习
一个现代JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归的构建一个依赖关系图(dependency graph),其中包含应用程序需要的每一个模块,然后将所有模块打包成一个或多个 bundle
13.1、安装Webpack
WebPack 是一款模块加载器兼打包工具,它能把各种资源,如JS ,JSX、,ES6、SASS、LESS、图片等都作为模块来处理和使用
安装
npm install webpack -g
npm install webpack-cli -g
测试
webpack -v
创建 webpack.config.js
配置文件
- entry :入口文件,指定 WebPack 用哪个文件作为项目的入口
- output:输出,指定 WebPack 把处理完的文件放置到指定路径
- module:模块,用于处理各种类型的文件
- plugins:插件,如:热更新、代码重用等
- resolve:设置路径指向
- watch:监听,用于设置文件改动后直接打包
使用webpack
1、创建项目、idea创建或者手动创建文件夹并用idea打开
2、创建一个名为 modules 的目录,用于放置 JS 模块等资源文件
3、在 modules 下创建模块文件,如 hello.js,用于编写 JS 模块相关代码
// 暴露一个方法:sayHi
exports.sayHi = function () {
document.write("<h1>邹飞鸣</h1>")
}
4、在 modules 下创建 main.js 的入口文件,用于打包时设置 entry 属性
// require 导入一个模块
var hello = require("./hello");// 接收hello.js文件暴露的方法,相当于一个类的对象引用变量
hello.sayHi();
5、在项目目录下创建 webpack.config.js 配置文件,使用 webpack 命令打包
module.exports = {
entry: './modules/main.js', // 程序入口即要打包的地方
output: {
filename: "./js/bundle.js" // 程序出口,即将打包后的文件存放的地方
}
}
6、在命令行执行打包命令(有可能需要管理员模式)
此时在项目根目录下会生成文件夹 dist 文件夹下的 bundle.js 就是打包后的文件
7、在根目录定义 index.html 文件,里面只使用 script
标签引入 bundle.js 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--将打包后的文件引入,这也是为什么模块化开发只需要一个简单的index界面原因-->
<script src="dist/js/bundle.js"></script>
</body>
</html>
8、浏览器运行
注:可在命令行执行 webpack --watch
进行热部署,即一直监听你有没有改变代码,改变了就自动重新打包
14、Vue Router(路由)
是 Vue.js 官方路由管理器,与 Vue.js 深度集成,让构件单页面应用变的易如反掌。功能如下:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过滤系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
作用:在单页面下不通过网页跳转进行网页内容变更(有点像内嵌网页)
如:轮播图的实现,一定时间后换一页,但是网页又不能跳转,我们就可以使用路由功能,通过路径自动展示需要的图片
14.1、安装
直接下载 / CDN
https://unpkg.com/vue-router@4
Unpkg.com基于 npm 的 CDN。上面的链接将提供指向 npm 上的最新链接。你也可以通过像https://unpkg.com/[email protected]/dist/vue-router.global.js
这样的 URL 来使用某个版本的版本或标签。
npm
npm install vue-router@4
注:上面是最新版下载方法,会与旧版不兼容
步骤:
基于第一个 vue-cli 进行测试学习,先查看node_modules 文件夹中是否存在 vue-router
vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev
报错信息:
npm错误!代码解析
npm错误!ERESOLVE无法解析依赖关系树
...
注:如果上述命令报错可尝试如下命令:
npm install vue-router --legacy-peer-deps
如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:
import Vue from 'vue'
import VueRouter from 'vue-router'
// 显示声明使用VueRouter
Vue.use(VueRouter);
14.2、使用:
以一个简单的例子展示,一个单页面,点击不同文字,在此页面内展现文字代表的 网页 ,且网页不发生跳转行为。
项目结构:箭头指向的才是需要的文件,node_modules中存放依赖文件
1、定义 index.heml 即网页入口文件,一般的vue项目,这个文件是不变的。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>myvue</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
2、定义 index.html
文件的 div 标签对应 id 的 vue 文件 app.vue
、这里面用来写第一个页面
<template>
<div id="app">
<!--点击文字会通过to标签的值去找相应的映射地址,元素文件一般在 router文件下的index.js文件中-->
<router-link to="/main">首页</router-link>
<router-link to="/Content">内容页</router-link>
<!--显示跳转页的内容-->
<router-view></router-view>
</div>
</template>
<script>
// 对外面暴露一个接口,外面可通过App这个名字使用此网页
export default {
name: 'App',
comments: {
}
}
</script>
<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;
}
</style>
3、写 App.vue 对应的 js 文件:main.js
里面存放 关于App.vue的一些vue信息
import Vue from 'vue'
import App from './App'
import router from './router' // 自动扫描里面的路由配置
Vue.config.productionTip = false
new Vue({
el: '#app',
// 配置路由
router,
components: { App },
template: '<App/>'
})
4、编写 首页 和 内容页 的内容
首页:Main.vue
<template>
<h1>首页</h1>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
内容页:Content.vue
<template>
<h1>内容页</h1>
</template>
<script>
export default {
name: "Content"
}
</script>
<style scoped>
</style>
5、编写路由信息的映射,index.js
// 一般存放路由信息,router文件夹下也是存放路由的相关文件
import Vue from 'vue';
//import * as VueRouter from 'vue-router',这是版本4的写法,下面的是3的写法
import VueRouter from 'vue-router';
import Content from "../components/Content";
import Main from "../components/Main";
// 安装路由
Vue.use(VueRouter);
// 配置导出路由
export default new VueRouter({
routes: [
{
// 路由路径
path: '/content',
// 跳转的组件
component: Content
},
{
// 路由路径
path: '/main',
// 跳转的组件
component: Main
}
]
});
效果:
注:此时可能出现的错误,
错误信息:
"export 'default' (imported as 'VueRouter') was not found in 'vue-router'
可能情况:
第一种cli4和cli3不太一样 需要引用相对应的使用的东西,
第二种是vue-router版本太高,
这种情况一般是运行npm install vue-router --save-dev 后启动报错,这是因为安装的时候默认安装最新版本可能与其他插件不兼容,重新安装旧版本即可
解决方法:
命令:cnpm install vue-router@+版本号 --save-dev
实例:cnpm install [email protected] --save-dev
15、实例
结合 ElementUI
组件库
15.1、Element使用
注:将Element的代码复制粘贴过来后需要将html的内容放在<template ></template>
里面才能用
安装
npm 安装
推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
npm i element-ui -S
CDN
目前可以通过 unpkg.com/element-ui 获取到最新版本的资源,在页面上引入 js 和 css 文件即可开始使用。
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
引入 Element(针对npm安装)
完整引入
1、在引入 Element 时,可以传入一个全局配置对象。该对象目前支持 size
与 zIndex
字段。size
用于改变组件的默认尺寸,zIndex
设置弹框的初始 z-index(默认值:2000)。
在 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(Element, { size: 'small', zIndex: 3000 });
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
以上代码便完成了 Element 的引入。需要注意的是,样式文件需要单独引入。
15.2、完整建立VUE项目步骤
1、创建名为 hello-vue 的工程 ,选择一个文件夹 在文件夹对应的路径下运行命令行命令vue init webpack hello-vue
2、之后手动安装依赖,可选择自动安装。
// 如果npm出错可以用cnpm
// 进入工程目录
cd hello-vue
// 安装 vue-router
npm install vue-router --save-dev
// 安装 element-ui
npm i element-ui -S
// 安装依赖
npm install
// 安装 SASS 加载器
cnpm install sass-loader node-sass --save-dev
// 启动测试
npm run dev
npm命令解释:
npm install moduleName
:安装模块到项目目录下npm install -g moduleName
:-g 的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看npm config prefix 的位置npm install -save moduleName
: --save 的意思是将模块安装到项目目录下,并在 package 文件的 dependencies 节点写入依赖,-S 为该命令的缩写npm install -save-dev moduleName
: --save-dev 的意思是将模块安装到项目目录下,并在 package 文件的 devDependencies 节点写入依赖,-D为该命令缩写。
只要不出现错误就不管,警告没事!**
访问 http://localhost:8080/
显示页面,说明创建成功
3、使用idea打开项目并删除多余文件与新建必要文件
如:删除logo文件,
4、创建首页视图:Main.vue
<template>
<h1>首页</h1>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
5、创建登陆视图:Login.vue(有瑕疵)
<template>
<div>
<el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
<h3 class="login-title">欢迎登录</h3>
<el-form-item label="账号" prop="username">
<el-input type="text" placeholder="请输入账号" v-model="form.username"/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" placeholder="请输入密码" v-model="form.password"/>
</el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
</el-form-item>
</el-form>
<el-dialog title="温馨提示" :visible.sync="dialogVisiable" width="30%" :before-close="handleClose">
<span>请输入账号和密码</span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Login",
data(){
return{
form:{
username:'',
password:''
},
//表单验证,需要在 el-form-item 元素中增加prop属性
rules:{
username:[
{required:true,message:"账号不可为空",trigger:"blur"}
],
password:[
{required:true,message:"密码不可为空",trigger:"blur"}
]
},
//对话框显示和隐藏
dialogVisible:false
}
},
methods:{
onSubmit(formName){
//为表单绑定验证功能
this.$refs[formName].validate((valid)=>{
if(valid){
//使用vue-router路由到指定界面,该方式称为编程式导航
this.$router.push('/main');
}else{
this.dialogVisible=true;
return false;
}
});
}
}
}
</script>
<style lang="scss" scoped>
.login-box{
border:1px solid #DCDFE6;
width: 350px;
margin:180px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
.login-title{
text-align:center;
margin: 0 auto 40px auto;
color: #303133;
}
</style>
6、编写路由映射文件:index.js
//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
routes: [
{
//登录页
path: '/main',
component: Main
},
//首页
{
path: '/login',
component: Login
},
]
})
7、mian.js
import Vue from 'vue'
import App from './App'
import router from './router'
//
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.use(router);
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
router,
render: h => h(App) // ElementUI需要的
})
8、App.vue
<template>
<div id="app">
<router-link to="/main">首页</router-link>
<router-link to="/login">登陆</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
9、index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>hello-vue</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
10、项目框架
11、运行截图
Vue.use():注册全局插件的意思
也就是为什么vue文件没有类似 import 的引用还能使用一些东西。
问题:
1、关于我们引用element组件时,在任何js文件中都行,只要最后通过Vue.use(ElementUI);
进行全局插件注册即可全局使用
2、关于为什么App.vue中内容能在index.html中显示问题。
1、index.html中 div 的 id 与 main.js 中的 el 参数进行绑定,又因为 App 暴露了自身,所以main.js可以通过components组件获取App内容。(大致,待完善)
16、路由嵌套
即在路由中添加子路由,因为路由类似内嵌网页,所以子路由可理解为在嵌套的网页中嵌套网页。
在上面项目基础上更改:箭头指向的都是有更改的
项目结构
注:路由也需要改,未指出。
Main.vue
<template >
<el-container class="login-box" style="height: 500px;width: 1000px; border: 1px solid #eee;">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>用户设置</template>
<el-menu-item-group>
<el-menu-item index="1-1" ><router-link to="/user/userName">用户名字</router-link></el-menu-item>
<el-menu-item index="1-2"><router-link to="/user/userOperation">用户操作</router-link></el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>系统设置</template>
<el-menu-item-group>
<el-menu-item index="2-1"><router-link to="/userOperation">系统音量</router-link></el-menu-item>
<el-menu-item index="2-2">系统字体</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-submenu index="3">
<template slot="title"><i class="el-icon-setting"></i>小板凳</template>
<el-menu-item-group>
<el-menu-item index="3-1">小大板凳</el-menu-item>
<el-menu-item index="3-2">大小板凳</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-aside>
<el-container >
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<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-menu>
</el-dropdown>
<span>邹飞鸣</span>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<style>
.el-header {
background-color: #3795f3;
color: #333;
line-height: 60px;
}
.login-box{
border:1px solid #DCDFE6;
margin: 100px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
</style>
<script>
export default {
name: "Main"
};
</script>
index.js
//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
// 导入用户操作组件
import userName from "../views/userviews/userName";
import userOperation from "../views/userviews/userOperation";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
routes: [
{
//首页
path: '/main',
component: Main,
// 设置孩子路由的关键字
children: [
{path: '/user/userName',component:userName},
{path: '/user/userOperation',component:userOperation}
]
},
{ //登录页
path: '/login',
component: Login
}
,
{
path: '/userOperation',
component:userOperation
}
]
})
userName.vue
<template>
<h1>名字设置</h1>
</template>
<script>
export default {
name: "userName"
}
</script>
<style scoped>
</style>
userOperation.vue
<template>
<h1>用户操作</h1>
</template>
<script>
export default {
name: "userOperation"
}
</script>
<style scoped>
</style>
**效果:**点击用户名字后显示的效果,可以看到是在组件的里面显示组件,如果不使用子路由那么页面将只显示名字设置这四个字(原来的首页,登陆按钮是不变的)
17、路由传参
即在使用路由转发时可以携带参数,有几种携带参数的方法,以下代码均由上面代码修改而来
17.1、耦合度较高的方法
我们需要修改三处地方,分别对应,路由转发时要携带的参数,路由信息修改,显示参数需要修改的文件。
我们以传递用户名字为例:
第一步:修改首页文件(Main.vue)中关于用户名字的 to 属性参数
注:变量名最好不能和vue中类似于关键字的东西重名,如最好不起 name 作为参数的变量名,会有冲突。
原来的:
<!--<el-menu-item index="1-1" ><router-link to="/user/userName/">用户名字</router-link></el-menu-item>-->
现在的:name:参数为路由中的name参数名,params:是我们要传递参数的一个集合,Name:我们传递参数的变量名
<el-menu-item index="1-1" ><router-link :to="{name:'userName',params:{Name:'邹飞鸣'}}">用户名字</router-link></el-menu-item>
第二步:修改路由信息(index.js)
原来的:
{path: '/user/userName',component:userName},
// 将上面更改为下面的以达到路由跳转时传递参数、我们在 <router-link> 标签中的 to 参数的值一定是 下面的 name 值。
现在的:
{path: '/user/userName/:Name',component:userName,name:'userName'},
第三步:在 userName.vue 文件中修改为:
注:所有的变量一定不能在根标签下,下面的 <template>
就类似于根标签,一定在外面加一层标签,不然会出错
<template>
<div>
<h1>名字设置</h1>
{{ $route.params.Name }}
</div>
</template>
第四步:效果
17.2、解耦的写法(标准)
第一步:修改首页文件(Main.vue)中关于用户操作的 to 属性参数
原来的:
<!--<el-menu-item index="1-2"><router-link to="/user/userOperation">用户操作</router-link></el-menu-item>-->
现在的:
<el-menu-item index="1-2"><router-link :to="{name:'userOperation',params:{id:1}}">用户操作</router-link></el-menu-item>
第二步:修改路由信息(index.js)
原来的:
{path: '/user/userOperation/',component:userOperation}
现在的:我们要将props开启
{path: '/user/userOperation/:id',component:userOperation,name:'userOperation',props: true}
第三步:在 userOperation.vue 文件中修改为:
<template>
<div>
<h1>用户操作</h1>
{{id}}
</div>
</template>
<script>
export default {
name: "userOperation",
props:['id']
}
</script>
第四步:效果
17.3、完整代码
注:只展示被修改过的文件的完整代码,其余未修改的文件上一个板块有
index.js
//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
// 导入用户操作组件
import userName from "../views/userviews/userName";
import userOperation from "../views/userviews/userOperation";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
routes: [
{
//首页
path: '/main',
component: Main,
// 设置孩子路由的关键字
children: [
//{path: '/user/userName',component:userName},
// 将上面更改为下面的以达到路由跳转时传递参数、我们在 <router-link> 标签中的 to 参数的值一定是 下面的 name 值。
{path: '/user/userName/:Name',component:userName,name:'userName'},
//{path: '/user/userOperation/',component:userOperation}
{path: '/user/userOperation/:id',component:userOperation,name:'userOperation',props: true}
]
},
{ //登录页
path: '/login',
component: Login
}
,
{
path: '/userOperation',
component:userOperation
}
]
})
Main.vue
<template >
<el-container class="login-box" style="height: 500px;width: 1000px; border: 1px solid #eee;">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>用户设置</template>
<el-menu-item-group>
<!--<el-menu-item index="1-1" ><router-link to="/user/userName/">用户名字</router-link></el-menu-item>-->
<el-menu-item index="1-1" ><router-link :to="{name:'userName',params:{Name:'邹飞鸣'}}">用户名字</router-link></el-menu-item>
<!--<el-menu-item index="1-2"><router-link to="/user/userOperation">用户操作</router-link></el-menu-item>-->
<el-menu-item index="1-2"><router-link :to="{name:'userOperation',params:{id:1}}">用户操作</router-link></el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>系统设置</template>
<el-menu-item-group>
<el-menu-item index="2-1"><router-link to="/userOperation">系统音量</router-link></el-menu-item>
<el-menu-item index="2-2">系统字体</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-submenu index="3">
<template slot="title"><i class="el-icon-setting"></i>小板凳</template>
<el-menu-item-group>
<el-menu-item index="3-1">小大板凳</el-menu-item>
<el-menu-item index="3-2">大小板凳</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-aside>
<el-container >
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<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-menu>
</el-dropdown>
<span>邹飞鸣</span>
</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<style>
.el-header {
background-color: #3795f3;
color: #333;
line-height: 60px;
}
.login-box{
border:1px solid #DCDFE6;
margin: 100px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
</style>
<script>
export default {
name: "Main"
};
</script>
userName.vue
<template>
<div>
<h1>名字设置</h1>
{{ $route.params.Name }}
</div>
</template>
<script>
export default {
name: "userName"
}
</script>
<style scoped>
</style>
userOperation.vue
<template>
<div>
<h1>用户操作</h1>
{{id}}
</div>
</template>
<script>
export default {
name: "userOperation",
props:['id']
}
</script>
<style scoped>
</style>
18、重定向
什么叫重定向:就是你跳转地址 A 它会自动帮你跳转到 B ,作用:如果某个旧网页废弃,但还有用户访问,就会造成404,为了避免,我们可使用重定向跳转到我们想要跳转的页面。
因为是 vue 所以这里的跳转不是请求服务器然后跳转的,因为 vue 是单页面应用,所以跳转就是更换了一个组件而言,并没有发送真正意义上的跳转,
步骤:
1、编写路由在原来路由上添加:
//访问 /a,重定向到 :/userOperation
{ path: '/a', redirect: '/userOperation' }
2、启动项目后访问 http://localhost:8080/#/a
此时会看到访问的地址最终变成 http://localhost:8080/#/userOperation
不好截图,就不截图了。
19、路由模式
路由模式有两种:
- hash:路径带 # ,如 http://localhost/#/login (默认是这种模式)
- history:路径不带 # 符号,
可修改路由配置以达到无 # 。
export default new Router({
mode: 'history',
routes: []
});
20、处理404
用户访问的地址如果没有,那么我们可以统一跳转的一个页面来表示404
步骤:
1、新建一个vue文件,用来显示404的界面
2、配置路由,让所有访问不到的页面就走上面这个文件
注:这里只展示路由配置信息
path: '*', // * 号代表,只要要跳转的地址在路由中找不到,就跳转到这个文件
component:NotFound // 这里NotFound就是我们创建的404页面文件
21、路由钩子与异步请求
beforeRouteEnter
:进入路由前执行
beforRouteLeave
:离开路由前执行
代码:
<script>
export default {
name: "userOperation",
props:['id'],
beforeRouteEnter:(to,from,next)=>{
console.log("进入路由之前");
next();
},
beforeRouteLeave:(to,from,next)=>{
console.log("进入路由之后");
next();
}
}
</script>
参数说明:
- to:路由将要跳转的路径信息
- from:路径跳转前的路径信息
- next:路由的控制参数
- next() :跳入下一个页面
- next(‘/path’)改变路由的跳转方向,使其跳到另一个路由
- next(false) :返回原来的页面
- next((vm)=>{}) 仅在 beforeRouterEnter 中可用,vm 是组件实例
在钩子函数中使用异步请求
1、安装 Axios cnpm install axios -s
npm install --save vue-axios
2、main.js
引用 Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
3、准备数据:只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
// 静态数据存放的位置
static/mock/data.json
// 静态数据的数据
{
"name": "zou",
"url": "https://blog.csdn.net/qq_43483251?orderby=ViewCount",
"address": {
"street": "含光门",
"city": "2",
"country": "1"
}
}
4、在 userOperation.vue 文件中编写
<template>
<div>
<h1>用户操作</h1>
{{id}}
</div>
</template>
<script>
export default {
name: "userOperation",
props:['id'],
beforeRouteEnter:(to,from,next)=>{
console.log("进入路由之前");
next(vm => {
vm.getData();//进入路由之前执行getData
});
},
beforeRouteLeave:(to,from,next)=>{
console.log("进入路由之后");
next();
},
methods: {
getData: function (){
this.axios({
method: 'get',
url:'http://localhost:8080/static/mock/data.json'
}).then(function (response){
console.log(response)
})
}
}
}
</script>
<style scoped>
</style>
5、配置路由信息,路由信息和上面一样不需要变更。所以此处不多写一遍
6、点击用户操作时显示: