Vue.js作为目前最热门最具前景的前端框架之一,帮助我们快速构建并开发前端项目。 本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程。
本节导航
Vue CLI安装创建项目启动打包环境变量
Vue生命周期Data模板语法复杂业务组件常用库
Element安装配置栅格系统Form 表单Table 表格
Vue CLI
Vue CLI 是官方提供快速搭建Vue项目的脚手架工具
零配置开发
基于 webpack 构建
可扩展
安装
npm install -g @vue/cli
创建项目
vue create hello-world
Vue CLI v4.5.10
? Please pick a preset:233 ([Vue 2] router, vuex, dart-sass, babel, pwa, eslint, unit-mocha)
test ([Vue 2] router, vuex, dart-sass, babel, pwa, eslint, unit-mocha)
> Default ([Vue 2] babel, eslint)Default (Vue 3 Preview) ([Vue 3] babel, eslint)Manually select features
选择 Vue 2 默认配置,也支持定义配置,
node_modules
public // 静态文件
src
|------- assets // 资源模块,图片等...
|------- components // 组件
|------- views // (默认没有),一般会放页面组件
|------- App.vue // 根组件
|------- main.js // 初始化 Vue 以及配置
babel.config.js // babel 配置
package.json // 项目信息,npm 脚本,包版本信息
启动
cd hello-world
npm run serve
打包
npm run build
打包后的文件会放在项目根目录的dist文件。可以进入dist 启动一个 http-server 快速验证打包后的内容
环境变量
一般用来区分 开发环境 测试环境 正式环境的配置信息
.env
.env.[mode]
// .env.development
NODE_ENV=development
VUE_APP_UC=https://ucdev.meb.im/
// package.json
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}
// zu'jian
console.log(process.env.VUE_APP_UC)
只有 NODE_ENV,BASE_URL 和以 VUE_APP_ 开头的变量,会被加载到 process.env. 对象中
Vue
目前正式版本是 Vue2.0,3.0还在beta版本,
生命周期
只介绍一下 5 个使用率非常高生命周期函数
- created 获取 $route 参数
- mounted 获取 原生DOM 和 组件实例
- beforeDestroy 销毁定时器
- activated 使用 keep-alive 时 提供的生命周期函数
- deactivated 使用 keep-alive 时 提供的生命周期函数
activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated
完整生命周期beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed
Data
组件中 data 必须是个 函数 并且 需要return 一个对象 JavaScript 中对象是引用类型,如果data是一个对象, 一个页面组件又使用2个相同的组件, A 修改了 data 就会影响 b 的data
{
data() {
return {
hello: '',
arr: [1, 2, 3]
}
},
methods: {
updateData() {
// 值类型更新数据this.hello = 'ni hao'
},
updateObj1() {
const newObj = { ...this.obj }
newObj.id = 2this.obj = newObj
},
updateObj2() {
const newObj = Object.assign({}, this.obj, { id: 2 })
this.obj = newObj
},
updateObj3() {
// 适用于数组this.$set(this.obj, 'id', 2)
},
updateArr1() {
this.arr.push(4)
},
updateArr2() {
this.$set(this.obj, 3, 3)
}
}
}
因为 Vue 修改了数组原型方法, 在原有方法包裹了异常, 使用直接使用数组方法,便可以会触发视图更新
push() pop() shift() unshift() splice() sort() reverse()
模板语法
Vue 的模板语法,和后端模板基本大同小异,底层其实是把模板编译成虚拟 DOM 渲染函数
{{ msg }}
{{ ok ? 'YES' : 'NO' }} // 表达式
{{ todo(ok) }} // 渲染函数的返回值
<div v-html="rawHtml"></div> // 渲染原生HTML
<p v-if="seen">现在你看到我了</p>
<p v-show="seen">现在你看到我了</p>
<ul><li v-for="item in items" >{{ item.name }}</li></ul>
<divclass="static"v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
<div :class="[activeClass, errorClass]"></div>
<h1>{{ blogTitle }}</h1>
function render(createElement) {
return createElement('h1', this.blogTitle)
}
复杂业务
对于比较复杂的业务逻辑,光靠模板语法的话,会把模板写得非常复杂和难以维护
<button v-if="isLogin && userType === 1 && hasLog">日志</button>
<div v-if="logBtnVisible">日志</div>
{
computed: {
logBtnVisible() {
return this.isLogin && this.userType === 1 && this.hasLog
}
}
}
filter
本质是一个函数,可以不用局限于filter
<span>{{isEnable| text}}</span>
{
filters: {
text(val) {
return val ? '激活' : '未激活'
}
}
}
// main.js
Vue.filter(key, fn)
// 注册多个filterObject.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
watch
<button @click="handleShowDialog">弹窗</button>
<div v-show="visible" class="dialog"></div>
{
watch: {
visible(val) {
if (val) {
this.resetForm() // 重置表单
}
}
},
method: {
handleShowDialog() {
// this.resetForm() this.visible = true
}
}
}
组件
<base-button action-type="share" />
<BaseButton actionType="share" />
import BaseButton from './BaseButton.vue'
{
components: { BaseButton }
}
JavaScirpt 中命名规范是 小驼峰,但是在Vue中组件的模板,命名规范推荐使用(字母全小写且必须包含一个连字符),遵循 W3C 规范中的自定义组件名,
全局注册组件
// main.jsimport BaseButton from './BaseButton.vue'
Vue.component('BaseButton', BaseButton)
父->子组件通讯
单向数据流,从父到子传递
父级 prop 的更新会向下流动到子组件中,子组件中不能直接修改props
// 父组件
<components :id="112233" user-id="12321312"></components> // 类型区别
// 子组件
props: {
id: Number,
userId: { type: String, default: '' }
}
String
Number
Boolean
Array
Object
Date
Function
Symbol
子->父组件通讯
- 一个弹窗组件,点击确定后需要重新请求父组件的列表,自定义事件
// alert.vue 组件
<button @click="$emit('submit')">确定</button>
// list.vue 列表
<alert @submit="getList"></alert>
ref/$refs
用于活动 子组件实例 或者 原生DOM,父组件就有了控制子组件的能力
<child ref="child"></child><input ref="input"></input>
{
mounted() {
console.log(this.$refs.child) // 可以调用子组件所有方法this.$refs.input.focus() // 操作 DOM
}
}
常用库
Vue Router
Vue Router 是 Vue.js 官方的路由管理器
// router.jsimport Vue from 'vue'import Router from 'vue-router'import Home from '../view/Home'
Vue.use(Router)
const router = new Router({
routes: [
{ path: '/home', name: 'home', component: Home }
]
})
// App.vue
<div id="app">
<img alt="Vue logo" src="./assets/logo.png"><router-view></router-view></div>
路由跳转
// 组件
<router-link to="/foo">Go to Foo</router-link><router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link
// 方法
router.pushrouter.replacerouter.back
meta
权限管理,页面个性化配置,设置title
{path: 'bar',component: Bar,meta: { requiresAuth: true }}
this.$route.meta
子路由
// router.js
{
path: '/child-View',
name: 'childView',
component: ChildView,
redirect: '/child-view/child1', // 自动重定向children: [
{ path: 'child1', component: Child1 },
{ path: 'child2', component: Child2 }
]
}
// ChildView
<div>
<h1>ChildView</h1><router-view></router-view></div>
$router/$route
route是路由信息对象,里面主要包含路由的一些基本信息,包括name、meta、path、hash、query、params、fullPath、matched、redirectedFrom
router是VueRouter的实例,包含了一些路由的跳转方法,钩子函数
axios
直接使用
axios.get('/user', {
params: {
id: 12345
}
})
axios.post('/user', { id: 123445 })
// utils/request.js
import axios from 'axios'
const request = axios.create({
baseURL: 'https://www.xxx.com/api',
timeout: 1000,
headers: { 'X-Custom-Header': 'foobar' }
})request.interceptors.request.use(
(config) => {
// 往header 添加tokenreturn config
},
(error) => {
console.error(error)
return Promise.reject(error)
}
)
request.interceptors.response.use(
(response) => {
// 判断数据是否正常返回return response
},
(error) => {
// 500return Promise.reject(error)
}
)
export default request
// main.js// Vue 实例的原型上, 习惯加上$符号
Vue.prototype.$request = request
// 组件this.$request.get('/aa/bb', {})
.then(res => {
console.log('res', res)
})
.catch(error => {
console.error('error', error)
})
// or 同步写法(只是写法, 还是异步的)
;(async () => {
try {
const res = await this.$request.get('/aa/bb')
} catch (e) {
console.error('error', error)
}
})()
Element
安装
npm i element-ui -S
配置
全局配置,该组件可以直接使用 Element 所有组件,不必单独引入
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
局部引用
<el-button></el-button>
import { Button as ElButton } from 'element-ui'
{
components: { ElButton }
}
栅格系统
将页面固定分成几栏,进行页面的布局设计,使布局规范简洁有规则。
Element 分成 24 栏
<el-row :gutter="20"><el-col :span="6"><div class="grid-content bg-purple-dark"></div></el-col>
<el-col :span="6"><div class="grid-content bg-purple-dark"></div></el-col>
<el-col :span="6"><div class="grid-content bg-purple-dark"></div></el-col>
<el-col :span="6"><div class="grid-content bg-purple-dark"></div></el-col>
</el-row>
Form 表单
<el-form :model="numberValidateForm" ref="form" label-width="100px" class="demo-ruleForm">
<el-form-itemlabel="年龄"prop="age":rules="rules"
><el-input type="age" v-model.number="numberValidateForm.age" autocomplete="off"></el-input></el-form-item><el-form-item><el-button type="primary" @click="submitForm('numberValidateForm')">提交</el-button><el-button @click="resetForm('numberValidateForm')">重置</el-button></el-form-item>
</el-form>
export default {
data() {
return {
numberValidateForm: {
age: ''
},
rules: {
age: [
{ required: true, message: '年龄不能为空'},
{ type: 'number', message: '年龄必须为数字值'}
]
}
};
},
methods: {
submitForm(formName) {
this.$refs.form.validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs.form.resetFields();
}
}
}
Table 表格
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
export default {
data() {
return {
tableData: [{
date: '2016-05-02',
name: 'hello1',
address: '四川成都春熙路街道xxx号'
}, {
date: '2016-05-04',
name: 'hello2',
address: '四川成都春熙路街道xxx号'
}, {
date: '2016-05-01',
name: 'hello3',
address: '四川成都春熙路街道xxx号'
}, {
date: '2016-05-03',
name: 'hello4',
address: '四川成都春熙路街道xxx号'
}]
}
}
}