Vue 是一套用于构建用户界面的渐进式框架,渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等特性。
Vue 的核心库只关注视图层,易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:管理)或既有项目整合。
用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用
LESS
MVVM是一种软件架构模式,源自于经典的MVC模式,它的方式是以事件驱动编程。
它的核心就是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。
ViewModel封装出来的数据模型包括视图的状态和行为两部分
视图的状态和行为都封装在了ViewModel里面,这样的封装使得ViewModel可以完整的去描述View层
Vue完全解耦了View层和Model层,这个解耦至关重要,它是前后端分离方案实施的重要一环。
Vue.js就是一个MVVM的实现者,它的核心就是实现了DOM监听与数据绑定
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
//Model:数据
data: {
message: "qwe,vue!"
}
})
}
script>
head>
<body>
<div id="app">
{
{message}}
div>
这里可以在控制台直接输入vm.message来修改值,中间是可以省略data的,在这个操作中,并没有主动操作DOM,页面的内容就产生了变化,这就是借助了Vue的数据绑定功能实现的,MVVM模式要求ViewModel层使用观察者模式来实现数据的监听与绑定,以做到数据与视图的快速响应。
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute,所以我们可以用 v-bind
v-bind简写:
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
//Model:数据
data: {
message: "qwe,vue!",
}
})
}
script>
head>
<body>
<div id="app">
<span v-bind:title="message">测试title悬停事件span>
div>
body>
html>
v-bind被称为指令。指令带有前缀v-,以表示他们是Vue提供的特殊特性,这里的意思就是说,将这个元素节点的title特性和Vue实例的message属性保持一致
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
//Model:数据
data: {
flag: true,
type: "A"
}
})
}
script>
head>
<body>
<div id="app">
<span v-if="flag">真span>
<span v-else>假span>
<span v-if="type==='A'">AAAspan>
<span v-else-if="type==='B'">BBBspan>
<span v-else>CCCspan>
div>
body>
html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
//Model:数据
data: {
items:[
{
message:'bootstrap'},
{
message:'vue'},
]
}
})
}
script>
head>
<body>
<div id="app">
<li v-for="item in items">{
{item.message}}li>
<hr/>
<li v-for="(item, index) in items">{
{index}}-{
{item.message}}li>
div>
body>
html>
v-on
简写@
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
data: {
message:"methods test"
},
//方法必须定义在Vue的methods对象中
methods:{
show:function () {
alert(this.message)
}
}
})
}
script>
head>
<body>
<div id="app">
<button v-on:click="show">click mebutton>
div>
body>
html>
Vue.js是一个MVVM框架,既数据双向绑定,既当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化,这也算是Vue.js的精髓了。
可以用v-model指令在表单、
注意:v-model会忽略所有表单元素的value、checked、selected特性的初始值,会将Vue实例的数据作为数据来源。所以我们应该通过JavaScript在组件的data选项中声明初始值!
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
data: {
message:'',
sex:'',
selected:''
},
})
}
script>
head>
<body>
<div id="app">
输入的文本:<input type="text" v-model="message">{
{message}}
<br/>
性别:<input type="radio" name="sex" value="男" v-model="sex">男
<input type="radio" name="sex" value="女" v-model="sex">女
<span>选中了:{
{sex}}span>
<br/>
<select v-model="selected">
<option value="">--请选择--option>
<option>Aoption>
<option>Boption>
<option>Coption>
select>
<span>选中了:{
{selected}}span>
div>
body>
html>
组件就是可复用的Vue实例,说白了就是一组可以重复使用的模板,跟JSTL的自定义标签等框架类似。通常一个应用会以一棵嵌套的组件树的形式来组织
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
/**
* 定义一个Vue组件component
* indi 组件的名字
* props 用来接收数据的参数
* template 模板
*/
Vue.component("indi", {
props: ['i'],
template: '{
{i}} '
})
vm = new Vue({
el: "#app",
data: {
items: ["Java", "Linux", "Vue"]
}
})
}
script>
head>
<body>
<div id="app">
<indi v-for="item in items" v-bind:i="item">indi>
div>
body>
html>
Axios是一个开源的用在浏览器端和NodeJS的异步通信框架,它的主要作用就是实现AJAX异步通信。
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
[v-clock]{
display: none;
}
style>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#vue",
//data()方法与属性data不同
data() {
return {
//请求的返回参数格式必须和JSON中的格式一样
info: {
name: null,
address: {
street: null,
city: null,
country: null
},
url:null
}
}
},
//钩子函数:可以在程序执行时插入到中间执行
//链式编程,ES6新特性
mounted() {
axios.get('data.json').then(response => (
this.info = response.data
))
}
})
}
script>
head>
<body>
<div id="vue" v-clock>
{
{info.name}}
<br/>
{
{info.address.street}}
<br/>
<a v-bind:href="info.links[0].url">click mea>
div>
body>
html>
简单点来说,计算出来的结果,保存在属性中,内存中运行,可以想象为缓存。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
vm = new Vue({
el: "#app",
//Model:数据
data: {
message: "qwe,vue!"
},
methods:{
currentTime1:function () {
return Date.now();
}
},
//计算属性,methods优先级高于computed,不建议重名
computed:{
currentTime2:function () {
this.message;
return Date.now();
}
}
})
}
script>
head>
<body>
<div id="app">
{
{currentTime1()}}
{
{currentTime2}}
div>
body>
html>
计算属性的主要特性就是为了将不经常发生变化的计算结果进行缓存,只有当其内部数据发生变化的时候,才会重新计算
在Vue中使用
元素作为承载分发内容的出口,称之为插槽,可以应用在组合组件的场景中
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
Vue.component("todo",
{
template:'\
\
\
\
\
'
});
Vue.component("todo-title",{
props:['title'],
template:'{
{title}}
'
});
Vue.component("todo-list",{
props:['todoItem'],
template:'{
{todoItem}} '
});
vm = new Vue({
el: "#app",
data:{
todoTitle:'待办列表',
todoList:['Java','Linux','Python']
}
})
}
script>
head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :title="todoTitle">todo-title>
<todo-list slot="todo-list" v-for="item in todoList" :todo-item="item">todo-list>
todo>
div>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11">script>
<script>
var vm;
window.onload = function () {
Vue.component("todo",
{
template:'\
\
\
\
\
'
});
Vue.component("todo-title",{
props:['title'],
template:'{
{title}}
'
});
//组件
Vue.component("todo-list",{
props:['todoItem','index'],
template:'{
{index}}------{
{todoItem}} ',
methods:{
//只能绑定当前组件的方法
remove:function (index) {
//自定义事件分发
this.$emit('remove',index)
}
}
});
//Vue实例
vm = new Vue({
el: "#app",
data:{
todoTitle:'待办列表',
todoList:['Java','Linux','Python']
},
methods:{
removeItem:function (index) {
//一次只删除一个元素
this.todoList.splice(index,1);
}
}
})
}
script>
head>
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :title="todoTitle">todo-title>
<todo-list slot="todo-list" v-for="(item,index) in todoList" :todo-item="item" :index="index" @remove="removeItem(index)" :key="index">todo-list>
todo>
div>
body>
html>
vue-cli是官方提供的一个脚手架,用于快速生成一个vue的项目模板
config目录下的index.js可以修改端口号
1. 安装Node.js
2. 安装Node.js淘宝镜像加速器(cnpm)
npm install cnpm -g
3. 安装vue-cli
cnpm install vue-cli -g
4. 查看是否安装成功
vue list
5. 创建一个项目,建立一个空文件夹,命令行跳转到目录,项目名myvue
vue init webpack myvue
6. 两个回车,输入一个作者名字,之后一路选择no
7. 初始化
cd myvue
npm install
8. 运行
npm run dev
本质上,webpack是一个现代JavaScript应用程序的静态模块打包器,它会递归的构建一个依赖关系图
EcmaScript6标准增加了JavaScript语言层面的模块体系定义,其核心思想就是尽量静态化,使编译时就能确定模块的依赖关系,以及输入和输出的变量,而以往的CommondJS和AMD模块,都只能在运行时确定这些东西。
优点:
缺点:
WebPack是一个模块化加载的兼容打包工具,它能把各种资源都当做模块化处理
切换到项目目录
npm install webpack -g
npm install webpack-cli -g
//暴露一个方法
exports.sayHi = function () {
document.write("ES6
");
}
var hello = require("./hello");
hello.sayHi();
module.exports = {
entry: './modules/main.js',
output: {
filename: "./js/bundle.js"
}
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="dist/js/bundle.js">script>
head>
<body>
body>
html>
说明:
# 参数 --watch 修改js之后,将自动打包,用于监听变化
webpack --watch
Vue Router 是 Vue.js官方的路由管理器
npm install vue-router --save-dev
<template>
<h1>内容页h1>
template>
<script>
export default {
name: "Content"
}
script>
<style scoped>
style>
<template>
<h1>首页h1>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
创建router文件夹,用来存放路由
在router文件夹中创建index.js,用来配置路由
import Vue from 'vue';
import VueRouter from 'vue-router'
import Content from '../components/Content'
import Mainn from '../components/Main'
//安装路由
Vue.use(VueRouter);
//配置导出路由
export default new VueRouter({
routes:[
{
//路由路径
path:'/content',
name:'content',
//跳转的组件
component:Content
},
{
//路由路径
path:'/main',
name:'main',
//跳转的组件
component:Mainn
}
]
})
import Vue from 'vue'
import App from './App'
import router from './router' //自动扫描里面的路由配置,此处命名必须使用router
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: {
App },
template: ' '
})
<template>
<div id="app">
<router-link to="/main">首页router-link>
<router-link to="/content">内容页router-link>
<router-view>router-view>
div>
template>
<script>
export default {
name: 'App'
}
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>
npm run dev
vue init webpack hello_vue
# 进入工程目录
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
"sass-loader": "^7.3.1",
在 views 目录下创建一个名为 Main.vue 的视图组件;主要用于登录后展示登录成功的跳转效果;
<template>
<div>
首页
div>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
在 views 目录下创建一个名为 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="dialogVisible"
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>
在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件
import Vue from 'vue'
import Router from 'vue-router'
import Login from "../views/Login"
import Main from '../views/Main'
Vue.use(Router);
export default new Router({
routes: [
{
// 登录页
path: '/login',
name: 'Login',
component: Login
},
{
// 首页
path: '/main',
name: 'Main',
component: Main
}
]
});
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
// 导入 ElementUI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 安装路由
Vue.use(router)
Vue.use(ElementUI)
new Vue({
el: '#app',
// 启用路由
router,
// 启用 ElementUI
render: h => h(App)
})
App.vue
<template>
<div id="app">
<router-view>router-view>
div>
template>
<script>
export default {
name: 'App',
}
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>
路由嵌套又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。同样的,URL中各段动态路径也按某种结果对应嵌套的各层组件
List.vue
<template>
<div style="float: left;">
<h1>用户列表h1>
div>
template>
<script>
export default {
name: "UserList"
}
script>
<style scoped>
style>
Profile.vue
<template>
<div style="float: left;">
<h1>个人信息h1>
div>
template>
<script>
export default {
name: "UserProfile"
}
script>
<style scoped>
style>
Main.vue
<template>
<div>
<el-container>
<el-aside width="200px">
<el-menu :default-openeds="['1']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-caret-right">i>用户管理template>
<el-menu-item-group>
<el-menu-item index="1-1">
<router-link to="/user/profile">个人信息router-link>
el-menu-item>
<el-menu-item index="1-2">
<router-link to="/user/list">用户列表router-link>
el-menu-item>
el-menu-item-group>
el-submenu>
<el-submenu index="2">
<template slot="title"><i class="el-icon-caret-right">i>内容管理template>
<el-menu-item-group>
<el-menu-item index="2-1">分类管理el-menu-item>
<el-menu-item index="2-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-menu>
el-dropdown>
el-header>
<el-main>
<router-view />
el-main>
el-container>
el-container>
div>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped lang="scss">
.el-header {
background-color: #B3C0D1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
style>
index.js
import UserList from '../views/user/List'
import UserProfile from '../views/user/Profile'
export default new Router({
routes: [
{
path: '/main',
name: 'Main',
component: Main,
children: [
{
path: '/user/profile', name: 'UserProfile', component: UserProfile},
{
path: '/user/list', name: 'UserList', component: UserList}
]
},
]
})
index.js
// ...
export default new Router({
routes: [
{
path: '/main',
name: 'Main',
component: Main,
children: [
{
path: '/user/profile/:id', name: 'UserProfile', component: UserProfile},
{
path: '/user/list', name: UserList, component: UserList}
]
}
]
})
Main.vue
<router-link :to="{name:'UserProfile',params:{id: 1}}">个人信息router-link>
Profile.vue
<template>
<div style="float: left;">
<h1>个人信息h1>
<h1>{
{$route.params.id}}h1>
div>
template>
props解耦
Profile.vue
<script>
export default {
props: ['id'],
name: "UserProfile"
}
script>
index.js
export default new Router({
routes: [
{
path: '/main',
name: 'Main',
component: Main,
children: [
//修改了这里
{
path: '/user/profile/:id', name: 'UserProfile', component: UserProfile, props: true},
{
path: '/user/list', name: UserList, component: UserList}
]
}
]
})
登录用户之后,在main页面右上角显示用户名
Login.vue
methods: {
onSubmit(formName) {
// 为表单绑定验证功能
this.$refs[formName].validate((valid) => {
if (valid) {
// 在这里添加参数
this.$router.push("/main/"+this.form.username);
} else {
this.dialogVisible = true;
return false;
}
});
}
}
index.js
routes: [
{
path: '/main/:name',
name: 'Main',
component: Main,
children: [
{
path: '/user/profile/:id', name: 'UserProfile', component: UserProfile, props: true},
{
path: '/user/list', name: UserList, component: UserList}
],
props: true
}
Main.vue
<el-header style="text-align: right; font-size: 12px">
<span>{
{name}}span>
el-header>
<script>
export default {
props: ['name'],
name: "Main"
}
script>
修改index.js
添加一个新的路由
{
path:'/home',
redirect:'/main'
}
修改Profile.vue
在前端使用
<el-menu-item index="1-3">
<router-link to="/home">回到首页router-link>
el-menu-item>
修改index.js
{
path:'/home/:name',
name: 'Home',
redirect:'/main/:name',
props: true
}
修改Profile.vue
<el-menu-item index="1-3">
<router-link :to="{name:'Home',params:{name: 'admin'}}">回到首页router-link>
el-menu-item>
路由模式有两种
修改路由配置
index.js
export default new Router({
mode:'history'
})
处理 404 需要创建一个名为 NotFound.vue
的视图组件
类似拦截器的作用
beforeRouteEnter
:在进入路由前执行
beforeRouteLeave
:在离开路由前执行
<script>
export default {
props: ['id'],
name: "UserProfile",
//在进入路由前执行
beforeRouteEnter: (to, from, next) => {
console.log('进入路由之前');
next();
},
//在路由离开前执行
beforeRouteLeave: (to, from, next) => {
console.log('离开路由之前');
next();
}
}
script>
参数说明
next()
跳入下一个页面next(’/path’)
改变路由的跳转方向,使其跳到另一个路由next(false)
返回原来的页面next((vm)=>{})
仅在 beforeRouteEnter
中可用,vm
是组件实例安装Axios
cnpm install axios -s
cnpm install --save vue-axios
main.js
引用Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
准备数据
只有static
目录下的文件可以被访问到
// 静态数据存放的位置
static /mock/data.json
profile.vue
在 beforeRouteEnter
中执行异步请求
<script>
export default {
props: ['id'],
name: "UserProfile",
//在进入路由前执行
beforeRouteEnter: (to, from, next) => {
console.log('进入路由之前');
next((vm)=>{
//进入路由之前执行getData()
vm.getData();
});
},
//在路由离开前执行
beforeRouteLeave: (to, from, next) => {
console.log('离开路由之前');
next();
},methods:{
getData:function () {
this.axios({
method:'get',
url:'http://localhost:8081/static/mock/data.json'
}).then(function (response) {
console.log(response)
})
}
}
}
script>