VUE 快速入门 —— 零碎知识
VUE 快速入门
作者 尤雨溪
Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
原则:关注点分离(Separation of concerns,SOC)
特点:MVVM模式、虚拟DOM操作
网络通信:axios (通俗的即ajax,只支持ES6)
页面跳转:vue-router
状态管理:vuex
Vue-UI:ice.work、layUI等
一、初始Vue
使用idea开发工具
安装插件:vue.js
生命周期
1、MVVM
MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
- 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
- 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
- 可测试。界面素来是比较难于测试的,测试可以针对ViewModel来写。
2、vue基本语法
v-开头的是vue里面的命令
-
v-cloak
:在数据加载之前都会将该元素进行隐藏,直至数据加载完之后,该属性会消失。能够解决插值表达式的闪烁问题。 -
v-text
:会覆盖标签内的原本内容。没有 插值表达式形式添加数据的闪烁问题。注意:插值表达式只会替换自己的占位符换成对应数据,而v-text被解析之后会将标签内的数据全部给覆盖掉。
-
v-html
:会覆盖标签内的原本内容。会把数据内容当成html去解析。 -
v-bind
:可简写成英文的冒号‘:’。是Vue中,提供绑定属性的指令,会将绑定属性的内容解析成js的表达式去执行,可写成合法的表达式。数据单向绑定M->V -
v-on
:可简写成英文的冒号‘@’。事件绑定机制 -
v-model
:可实现数据的双向绑定 M <-> V,只能运用于表单中 -
v-for
:顺序遍历,可遍历普通数组(item,i)、对象数组(item,i)、对象(val,key,i)、数字迭代(从1开始)遍历的时候必须绑定一个key属性,以标识唯一身份 -
v-if
:当值为false时,元素被彻底删除;为true时元素则被创建(有较高的性能消耗) -
v-else-if
:与v-if/v-else搭配使用 -
v-else
:与v-if搭配使用 -
v-show
:当值为false时,元素增加样式display:none;为true时改变样式,使元素被重新显示(有较高的初始渲染消耗) -
ref
:将该标签绑定起来 ref='name',在vue中可以通过 this.$refs.name 可以获取到那个为name的标签
3、组件 component
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app" v-cloak>
<!--定义了一个名为hero的组件,模板为'<li>{{option}}</li>'
props是该组件的属性,只为该组件使用,通过v-for遍历出来的item与属性绑定
可进行数据传输通信
-->
<hero v-for="item in items" v-bind:option="item"></hero>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
Vue.component("hero",{
props: ['option'],
template: '<li>{{option.name}} {{option.age}} {{option.sex}}</li>'
});
var vm = new Vue({
el:"#app",
data:{
items: [
{name:"heroC",age:21,sex:"男"},
{name:"yikeX",age:21,sex:"女"}
]
}
});
</script>
</body>
</html>
4、网络通信 axios
只支持 ES6
特性:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
使用:
{
"name": "heroC",
"url": "www.baidu.com",
"page": 1,
"isNonProfit": true,
"address": {
"street": "西三环路",
"city": "成都",
"country": "中国"
},
"links": [
{
"name": "bilibili",
"url": "https://www.bilibili.com/"
},
{
"name": "翻译",
"url": "https://fanyi.baidu.com"
}
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
[v-cloak]{
display: none;
}
</style>
<body>
<div id="app" v-cloak>
<a :href="info.links[0].url">bilibili</a>
</div>
<script src="https://cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data(){
return{
// info接收ajax请求返回的数据
info:null
}
},
// mounted 在vue生命周期中可以用于ajax请求的钩子函数 axios只支持ES6
mounted(){
// 将响应过来的数据返回到data函数的info中
axios.get('../data.json').then(response=>(this.info = response.data));
}
});
</script>
</body>
</html>
5、计算属性 computed
<div id="app" v-cloak>
<h3>{{currentTime1()}}</h3>
<h3>{{currentTime2}}</h3>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"hello,Vue!"
},
methods:{
/*currentTime1 是一个方法,即使不刷新页面,时间戳也会在后台刷新*/
currentTime1: function () {
return Date.now();
}
},
/*计算属性,将第一次加载的数据缓存在currentTime2中,不刷新页面数据就不会改变*/
computed:{
/*currentTime2 是一个属性,在一个加载完整的页面中,如果该属性的方法发生变化,那么数据也会更新一次*/
currentTime2: function () {
return Date.now();
}
}
});
</script>
在浏览器后台调用方法与计算属性的结果:

可知,计算属性是一个缓存的作用,第一次加载的数据是多少该属性就一直缓存的多少。而方法,调用一次就执行一次。
计算属性的作用就是将不经常发生变化的计算结果进行缓存,以节约系统开销。
6、插槽 slot
<style>
[v-cloak]{
display: none;
}
</style>
<body>
<div id="app" v-cloak>
<todo>
<!--todo-title组件与插槽stitle绑定,并将app中的title属性与该组件的属性绑定-->
<todo-title slot="stitle" :todotitle="title"></todo-title>
<!--todo-item组件与插槽sitem绑定,并将app中的items属性遍历的每一项与该组件的属性绑定-->
<todo-item slot="sitem" v-for="item in items" :todoitem="item"></todo-item>
</todo>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
Vue.component("todo",{
template: '<div>\
<slot name="stitle"></slot>\
<ul>\
<slot name="sitem"></slot>\
</ul>\
</div>'
});
Vue.component("todo-title",{
props: ['todotitle'],
template: '<div>{{todotitle}}</div>'
});
Vue.component("todo-item",{
props: ['todoitem'],
template: '<li>{{todoitem}}</li>'
});
var vm = new Vue({
el:"#app",
data: {
title: 'heroC',
items: [
'真好',
'真厉害',
'真棒'
]
}
});
</script>
</body>

7、自定义事件 this.$emit()

点击删除按钮,可删除该元素
this.$emit('自定义事件名',参数)
<div id="app" v-cloak>
<todo>
<todo-title slot="stitle" :todotitle="title"></todo-title>
<!--绑定索引,将vm实例中的removeIndex方法,绑定该组件自定义的removeon方法,
因此,就可以是实现该组件使用vm实例的方法了-->
<todo-item slot="sitem" v-for="(item,index) in items" :todoitem="item"
:index="index" @removeon="removeIndex"></todo-item>
</todo>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
Vue.component("todo",{
template: '<div>\
<slot name="stitle"></slot>\
<ul>\
<slot name="sitem"></slot>\
</ul>\
</div>'
});
Vue.component("todo-title",{
props: ['todotitle'],
template: '<div>{{todotitle}}</div>'
});
Vue.component("todo-item",{
props: ['todoitem','index'],
template: '<li>{{todoitem}} <button @click="remove">删除</button></li>',
methods: {
remove: function (index) {
// 事件分发 this.$emit('自定义事件名',参数)
this.$emit('removeon',index);
}
}
});
var vm = new Vue({
el:"#app",
data: {
title: 'heroC',
items: [
'真好',
'真厉害',
'真棒'
]
},
methods: {
removeIndex(index){
this.items.splice(index,1);
}
}
});
</script>
二、Vue-cli
1、安装vue-cli
安装nodejs 搭建环境
安装nodejs,cmd运行node -v
和npm -v
观察有没有版本信息,如果有版本信息,说明环境搭建好了
在cmd控制窗口安装:
安装cnpm,国内的镜像下载命令,npm install cnpm -g
全局安装cnpm
安装路径:C:\Users\Administrator\AppData\Roaming\npm
安装vue-cli
cnpm install vue-cli -g
安装完成 vue list
vue list
可检查是否安装成功
2、第一个Vue-cli项目
- 在自己的项目文件夹下,通过cmd控制窗口,初始化一个项目
vue init webpack <项目名>
- 初始化项目
npm install
初始化项目之后,在该项目下会多一个node_modules文件夹
-
以管理员身份使用idea打开项目
-
vue项目打包发布
npm run dev
三、webpack
可将ES6规范的代码打包编译成ES5规范的代码。
- 使用
webpack
就可以将项目打包了webpack --watch
可监听更改的文件,然后自动打包
四、vue-router 路由
安装vue-router
npm install vue-router --save-dev
路由模式
页面跳转案例
main.js 全项目的入口
import Vue from 'vue'
import App from './App'
// 导入router文件夹下的js文件,该文件夹下如果以index.js命名,会自动识别,如果没有以index.js命名,需要指定导入的是哪个js
import Router from './router'
Vue.config.productionTip = false;
new Vue({
el: '#app',
// router 配置路由的属性
router: Router,
components: { App },
template: '<App/>'
})
App.vue 主页
<template>
<div id="app">
<h1>heroC</h1>
<!--router-link 类似a标签,是router专用-->
<router-link to="/main">首页</router-link>
<router-link to="/content">内容页</router-link>
<!--router-view 作用是将router-link 路径绑定的组件展示到router-view中-->
<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>
Main.vue
<template>
<h2>首页</h2>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
Content.vue
<template>
<h2>内容页</h2>
</template>
<script>
export default {
name: "Content"
}
</script>
<!--scoped 表示style只在该组件中有效-->
<style scoped>
</style>
router文件夹下的index.js
import VueRouter from "vue-router";
import Vue from "vue";
import Content from "../components/Content";
import Main from "../components/Main";
// 显示声明使用路由
Vue.use(VueRouter);
// 将路由配置暴露出去
export default new VueRouter({
mode: 'history',
routes: [
{
// 跳转Content组件的映射路径 '/content'
path: '/content',
name: 'content',
component: Content
},
{
path: '/main',
component: Main
}
]
})
点击首页,会自动跳转到绑定路径的首页组件
五、Element UI
1、创建项目完整项目....
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
要注意sass版本号:
"sass-loader": "^7.0.3",
"node-sass": "^4.13.1",
2、404 页面
<template>
<h1>404, 你的页面走丢了...</h1>
</template>
<script>
export default {
name: "NotFound"
}
</script>
<style scoped>
</style>
import VueRouter from "vue-router";
import Vue from "vue";
import Content from "../components/Content";
import Main from "../components/Main";
import NotFound from "../components/NotFound";
// 显示声明使用路由
Vue.use(VueRouter);
// 将路由配置暴露出去
export default new VueRouter({
routes: [
{
path: '/content',
name: 'content', // 给路径取名字,可代替路径使用
component: Content
},
{
path: '/main',
component: Main
},
{
// 不匹配的路径走*,NotFound组件,404
path: '*',
component: NotFound
}
]
})
3、路由钩子函数
在通过路由进入该组件之前,会执行beforeRouteEnter,在离开这个路由之后,执行beforeRouteLeave
六、axios 接收json数据 渲染到组件中
<template>
<div>
<table>
<tr>
<th>网址</th>
<th>地址</th>
</tr>
<tr v-for="value in links">
<td>{{value.name}}</td>
<td><a :href="value.url">{{value.url}}</a></td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "Content",
data(){
return{
// info接收ajax请求返回的数据
info:null,
links: null,
}
},
beforeRouteEnter(to, from, next){
next(vm => {
vm.getData();
});
},
methods: {
getData: function () {
this.axios.get('../../static/data.json').then((response) => {
this.info = response.data;
this.links = response.data.links});
/*this.axios.post('/data',this.info).then((response) => {
console.log(response.data)});*/
}
}
}
</script>
<!--scoped 表示style只在该组件中有效-->
<style scoped>
</style>
七、前端开发中遇见的问题
登录拦截问题
登录拦截问题
const router = new VueRouter({
mode: 'history', // 设置为history,就不会在路由路径中出现#符号
routes: [
{
path: '/main',
name: 'main',
props: true,
meta:{
requireAuth: true
}, // 在需要拦截的请求中加入该meta属性,可以用于判断是否拦截该路由
component: Main
}
]
})
// 判断是否需要登录权限 以及是否登录
router.beforeEach((to, from, next) => {
if (to.matched.some(res => res.meta.requireAuth)) {// 判断是否需要登录权限
if (localStorage.getItem('username')) {// 判断是否登录
next()
} else {// 没登录则跳转到登录界面
next({
path: '/',
query: {redirect: to.fullPath}
})
}
} else {
next()
}
})
跨域请求访问问题
解决跨域问题
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
// proxyTable是解决跨域的配置
proxyTable: {
'/api':{
target:'http://127.0.0.1:8080', // 请求的地址,会在/api前面添加请求目的
changeOrigin:true, // 开启允许跨域请求
/*pathRewrite: {
'^/api': '/' //如果请求路径中本身就有/api该属性不用配置。该属性的意思是将/api替换成/
}*/
}
},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 8030, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false,
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
...
}
...
}
前端发送json数据给后端乱码问题
解决前端发送数据乱码问题
this.axios({
...
headers: {
'Content-Type': 'application/json; charset=utf-8'
} // 设置数据的格式,以避免后端接收到的json出现乱码
}
全局存储登录用户名问题
localstorage和sessionstorage的区别
localstorage(本地存储)则以文件的方式存储在本地,永久保存(不主动删除,则一直存在);
sessionstorage( 会话存储 ) ,临时保存,关掉该网站后,ssessionstorage就会被清除掉。
localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
sessionStorage.setItem("username",this.form.username);
或者
localStorage.setItem("username",this.form.username);
接收后台json数据,将其中的一项数据封装为数组
比如:
json数据通过JSON.parse转换成前端对象之后
[{
name: 'heroC',
shouru: 38000,
zhichu: 10000
},
{
name: 'yikeX',
shouru: 55000,
zhichu: 20000
}]
将每一个属性的数组归为一组:
var data = [
{
name: 'heroC',
shouru: 38000,
zhichu: 10000
},
{
name: 'yikeX',
shouru: 55000,
zhichu: 20000
}];
// 类似于lamda表达式
data.map(r => r.name);
data.map(r => r.shouru);
data.map(r => r.zhichu);
解决tomcat部署vue项目后,刷新页面问题
在tomcat的web.xml中加入该配置即可:
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
八、Echarts 、V-Charts
四川地图:
<template>
<ve-map :data="chartData" :settings="chartSettings" :extend="chartExtend"></ve-map>
</template>
<script>
export default {
data () {
this.chartSettings = {
position: 'province/sichuan'
}
this.chartExtend = {
legend:{show:false},
color: false,
backgroundColor:'#fff',
visualMap: {
min: 0,
max: 15,
text: ['High', 'Low'],
realtime: false,
calculable: true,
inRange: {
color: ['#fff','lightskyblue', 'yellow', 'orangered']
}
},
tooltip: {
trigger: 'item'
}
}
return {
chartData: {
columns: ['位置', '店铺'],
rows: [
{ '位置': '成都市', '店铺': 13 },
{ '位置': '绵阳市', '店铺': 12 },
{ '位置': '自贡市', '店铺': 0 },
{ '位置': '攀枝花市', '店铺': 0 },
{ '位置': '泸州市', '店铺': 0 },
{ '位置': '德阳市', '店铺': 0 },
{ '位置': '广元市', '店铺': 0 },
{ '位置': '遂宁市', '店铺': 0 },
{ '位置': '内江市', '店铺': 0 },
{ '位置': '乐山市', '店铺': 3 },
{ '位置': '资阳市', '店铺': 0 },
{ '位置': '宜宾市', '店铺': 2 },
{ '位置': '南充市', '店铺': 0 },
{ '位置': '达州市', '店铺': 0 },
{ '位置': '雅安市', '店铺': 0 },
{ '位置': '阿坝藏族羌族自治州', '店铺': 0 },
{ '位置': '甘孜藏族自治州', '店铺': 0 },
{ '位置': '凉山彝族自治州', '店铺': 0 },
{ '位置': '广安市', '店铺': 0 },
{ '位置': '巴中市', '店铺': 0 },
{ '位置': '眉山市', '店铺': 6 }
]
}
}
}
}
</script>