Vue.js作为目前最热门最具前景的前端框架之一,帮助我们快速构建并开发前端项目。 本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程。
本节导航
Vue CLI
Vue CLI 是官方提供快速搭建Vue项目的脚手架工具
安装
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
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 = 2
             this.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>
 
 <div
   class="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)
 
 // 注册多个filter
 Object.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.js
 import BaseButton from './BaseButton.vue'
 Vue.component('BaseButton', BaseButton)父->子组件通讯
单向数据流,从父到子传递
父级 prop 的更新会向下流动到子组件中,子组件中不能直接修改props
// 父组件
 <components :id="112233" user-id="12321312"></components>  // 类型区别
 
 // 子组件
 props: {
     id: Number,
     userId: { type: String, default: '' }
 }子->父组件通讯
- 一个弹窗组件,点击确定后需要重新请求父组件的列表,自定义事件
// 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.js
 import 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.push
 router.replace
 router.backmeta
权限管理,页面个性化配置,设置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 添加token
         return config
     },
     (error) => {
         console.error(error)
         return Promise.reject(error)
     }
 )
 request.interceptors.response.use(
 (response) => {
         // 判断数据是否正常返回
         return response
     },
     (error) => {
         // 500
         return 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-item
    label="年龄"
    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号'
      }]
    }
  }
} 
         苏公网安备 32050502001014号
苏公网安备 32050502001014号