1. 首页
  2. >
  3. 前端开发
  4. >
  5. Vue

从零开始学VUE

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 个使用率非常高生命周期函数

    1. created 获取 $route 参数
    1. mounted 获取 原生DOM 和 组件实例
    1. beforeDestroy 销毁定时器
    1. activated 使用 keep-alive 时 提供的生命周期函数
    1. 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 = 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: '' }  }
  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
  • 子->父组件通讯

    1. 一个弹窗组件,点击确定后需要重新请求父组件的列表,自定义事件
    // 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.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 添加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>

    从零开始学VUE

    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号'       }]     }   } }