Vue2.x - 从项目搭建到开发实用属性及方法

344 阅读2分钟

简介

本文将为您介绍开发vue2.x相关常用知识。没了就这么简单粗暴!

-未推编辑完全(因作者也还在整理,所以此文章会陆陆续续补全。后面会加上源码解析)
-有时间会再度发布vue3.x开发相关知识(包括vite)
-此文章类似笔记,是作者开发vue项目整理的知识点,做个分享
  1. - 项目搭建 -
  2. - 谷歌插件 -
  3. - 内部指令 -
  4. - 自定指令 -
  5. - 生命周期 -
  6. - 常见属性 -
  7. - 父子交互 -
  8. - ref与slot -
  9. - 动态路由 -
  10. - 结束话语 -

项目搭建

- 运行指令 -
1.npm install webpack -g    ---安装webpack环境 - 使用vueCli需要webpack-dev-server的支持
2.npm i -g vue-cli     ---安装vue的脚手架 (⚠️用了vue3需要npm install -g @vue/cli-init桥接工具)
3.vue init webpack xxxx     ---构建vue项目
- 项目构建解释 -
// Project name (xxxx):     ---项目名称,直接回车,按照括号中默认名字(起名用小写)
// Project description (A Vue.js project):     ---项目描述,也可直接点击回车,使用默认名字
// Author     ---作者
// Vue build     ---vue的构建 - 第一个是运行+编译器 - 第二个是仅限运行时
// Install vue-router? (Y/n)     ---是否安装vue-router(yes/no)
// Use ESLint to lint your code? (Y/n)     ---是否使用ESLint管理代码(yes/no)
// Pick an ESLint preset (Use arrow keys)     ---代码风格(百度他选择的名字或者括号的地址)
// Setup unit tests with Karma + Mocha? (Y/n)     ---是否安装单元测试(yes/no)
// Pick a test runner     ---选择单元测试工具
// Setup e2e tests with Nightwatch(Y/n)?     ---是否安装e2e测试(yes/no)
// Should we run `npm install` for you after the project has been created? (recommended)     --想通过npm下载还是

谷歌插件

- vue的谷歌插件 -
// vue自推荐git地址(去把项目弄下来) vue插件git地址
// 进到该项目跑 yarn install
// 环境安装完全后就进行打包 yarn run build
// 打包完后谷歌打开/-开发者模式-/然后进到/-拓展程序-/点击/-加载已解压的拓展程序-/
// 按该路径选取文件 vue-devtools/packages/shell-chrome/
// 最后一步确认即可
- 题外-sass -
 1.先npm安装stylus和stylus-loader。
 2.sass依赖包 配置环境下
  - npm install --save-dev sass-loader
  - npm install --save-dev node-sass
 3.配置条件 在build文件夹下的webpack.base.conf.js
  - module: {
  -    rules: [
  -        {
  -            test: /\.sass$/,
  -            loaders: ['style', 'css', 'sass']
  -        }
  -    ]
  - }
 4.修改vue组件中的style标签/添加
  - <style lang="scss">

内部指令

<template>
   <div>
      <!-- 1.v-if - 判断是否将该元素插入dom树 -->
      <div v-if="!vIf">页面插入及显示该元素 - 此页面显示该条元素</div>
      <div v-if="vIf">页面将不会有该div元素 - 此页面不显示该条元素</div>
      <!-- 2.v-else-if - 判断是否将该元素插入dom树 -->
      <div v-else-if="!(!vIf)">页面将不会有该div元素 - 此页面不显示该条元素</div>
      <!-- 3.v-eles - 与if(){}else if(){}else{}同理  -->
      <div v-else>需要上一个兄弟元素绑定v-if/v-else-if - 此页面显示该条元素</div>
      <!-- 4.v-show - 页面会挂载该节点元素 -->
      <div v-show="vShow">不管是否为真都会将该元素插入页面,只是控制了显示与隐藏(display) - 此页面显示该条元素</div>
      <!-- 5.v-model - 双向绑定 - 让视图与控制数据互通 -->
      <input type="text" v-model="vModel">
      <!-- 6.v-once - 只显示第一次渲染的值 - 后面更改不会更换html -->
      <div v-once>{{vModel}}</div>
      <!-- 7.v-on - 时间监听 - 可简化为@ - 如 @click=“xxxxx” -->
      <div v-on:click="vOn">点我触发查看双向绑定的值</div>
      <!-- 8.v-bind - 将“冒号内的值”提升为变量 - 可简化为: - 如 :class=“xxxxx” -->
      <div v-bind:class="vBind"> </div>
      <!-- 9.v-for - 循环 - item是当前循环体,index是当前循环下标 - VFor是循环数据 -->
      <div v-for="(item, index) in VFor" :key="index">{{item.name}}</div>
      <!-- 10.v-text - 用来显/打印示文本/变量内容 - 123将被替换 -->
      <div v-text="vText">123</div>
      <!-- 11.v-html - 用来直接把html结构code直接存进数据库。再调出使用 -->
      <div v-html="vHtmls"></div>
      <!-- 12.v-cloak - 防止页面挂载内容还未处理完成显示{{}}大括号,等代码加载完出来再显示 -->
      <div v-cloak>{{vBind}}</div>
      <!-- 13.v-pre - 不编译vue方法 - 上面所提到的都失效,包括大括号 -->
      <div v-pre v-text="vText">{{123}}</div>
   </div>
</template>

<script>
export default {
  name: 'Bao',
  data () {
    return {
      vIf: false,
      vShow: true,
      vModel: '',
      vBind: 'className',
      vText: '我有一只小毛驴,我从来都不骑~',
      vHtmls: `<div>12${1 + 2}<span style="color:red">567</span></div>`, // ``是字符串模版
      VFor: [{name: '值1'}, {name: '值2'}]
    }
  },
  methods: {
    vOn () {
      console.log('监听触发-双向绑定的输入值为:' + this.vModel)
    }
  }
}
</script>

自定指令

<template>
 <div>
     <div v-baobao="backFunc"></div>
 </div>
</template>

<script>
export default {
  name: 'Bao',
  data () { return { } },
  methods: {
    backFunc (data) {
      console.log('触发监听回调:' + data)
    }
  },
  // 自定义挂载属性 - 当组件挂载时候执行
  directives: {
    baobao: {
      // bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
      // inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
      // update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
      // componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
      // unbind:只调用一次,指令与元素解绑时调用。
      inserted (el, binding, vnode) {
        el.innerHTML = '不念过去,不惧将来,不思未来'
        // 接收的值请看下面讲解
        // 除了 el 之外,其它参数都应该是只读的
        el.addEventListener('click', () => {
          binding.value && binding.value('传值啦啦啦啦啦啦啦')
        })
      }
      // 来源-百度
      // el:指令所绑定的元素,可以用来直接操作 DOM 。
      // binding:一个对象,包含以下属性:
      // - name:指令名,不包括 v- 前缀。
      // - value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
      // - oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
      // - expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
      // - arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
      // - modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
      // vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
      // oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

      // ---------- 分割线 ----- 也可以在main.js在new Vue,创建并挂载自定义函数如下 -----
      // Vue.directive('baobao', {
      //   inserted (el, binding) {
      //     el.addEventListener('click', () => {
      //       binding.value && binding.value()
      //     })
      //   }
      // })
    }
  }
}
</script>

生命周期

<template>
 <div ref="div" v-text="msg" />
</template>

<script>
export default {
  name: 'Bao',
  data () {
    return {
      msg: '1秒后即将触发'
    }
  },
  /*  创建前 - 进场  */
  beforeCreate () {
    // 在实例初始化之后,数据观测和事件配置之前被调用(-new Vue)
    // el与data并未初始化,因此无法访问methods\data\computed等上的方法和数据
    console.log('beforeCreate,此时拿不到data内的数据!', this.msg)
  },
  /*  创建后 - 构建data数据后  */
  created () {
    // 在observData(-开始监控data)和InitEvents(-vue内部初始化事件)后执行的第一个钩子
    // 已经配置数据观测(-watch)与属性(-event)与方法(-methods),data数据也已初始完成
    // 未有el
    console.log('created,此时Dom数还没渲染挂载!', this.msg)
  },
  /*  挂载前 - 即将挂载dom树  */
  beforeMount () {
    // 在页面编译模版(-把data内的数据或模版生成html)后执行的钩子
    console.log('beforeMount,此时Dom数还是没有渲染挂载~')
  },
  /*  挂载后 - dom树挂载完成后  */
  mounted () {
    // 用上面已经编译好的编译模版替换el属性指向的dom树对象或者选择对应的html标签里面的内容
    let tiem = setTimeout(() => {
      this.msg = '我将要改变数据'
      console.log('mounted,此时dom树已挂载好,可获取页面节点内容', this.$refs.div.innerHTML)
      this.$nextTick(() => { console.log('nextTick,相当于在页面设置了个回调,等dom树更新后在触发', this.$refs.div.innerHTML) })
      clearTimeout(tiem)
    }, 1000)
  },
  /* 更新前 - 准备更新dom树  */
  beforeUpdate () {
    // 发生在虚拟DOM重新渲染和打补丁之前,可以再此拦截默认渲染数据,不会触发附加地重渲染过程
    console.log('beforeUpdate,即将更新页面数据', this.msg)
    this.msg = '嘿嘿嘿嘿嘿'
  },
  /*  更新后 - 页面已经被刷新  */
  updated () {
    // 页面更新后的回调钩子
    console.log('beforeUpdate,页面已经进项更新', this.msg)
  },
  /*  销毁前 - 即将销毁离开  */
  beforeDestroy () {
    console.log('销毁前')
  },
  /*  销毁后 - 已经销毁离开  */
  destroyed () {
    console.log('销毁后')
  }
}
</script>

常见属性

<template>
 <div >
    <h1 v-text="showTitle"  />
    <button @click="bao" v-text="'点我'" />
    <div>
      <p>输入1到10</p>
      <input  type="text" v-model="num">
      <!-- num是过滤的参数 - |是过滤符号 - baoxixi是过滤方法 -->
      <h3 >{{ num | baoxixi(baoAttr) }}</h3>
    </div>
 </div>
</template>

<script>
export default {
  name: 'Bao',
  data () {
    return {
      oldTitle: '变动前',
      num: '1',
      baoAttr: [
        { num: 1, title: '啦啦啦1' },
        { num: 2, title: '啦啦啦2' },
        { num: 3, title: '啦啦啦3' },
        { num: 4, title: '啦啦啦4' },
        { num: 5, title: '啦啦啦5' },
        { num: 6, title: '啦啦啦6' },
        { num: 7, title: '啦啦啦7' },
        { num: 8, title: '啦啦啦8' },
        { num: 9, title: '啦啦啦9' },
        { num: 10, title: '啦啦啦10' }
      ]
    }
  },
  // 计算属性 - 监听 - 当该函数里当依赖值变动时触发并返回
  computed: {
    // computer当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性。
    // 需要注意的是,就算在data中没有直接声明出要计算的变量,也可以直接在computed中写入。
    showTitle () {
      let data = this.oldTitle + ',嘻嘻'
      return data
    }
  },
  // 属性监听 - 及监听data里面或props值的变动 - 可监听数组_链式表达
  watch: {
    // watch和computed很相似,watch用于观察和监听页面上的vue实例,当然在大部分情况下我们都会使用computed,但如果要在数据变化的同时进行异步操作或者是比较大的开销,那么watch为最佳选择。watch为一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。
    // 如果在data中没有相应的属性的话,是不能watch的,这点和computed不一样。
    'oldTitle': function (newVal, oldVal) {
      console.log(newVal, oldVal)
    }
  },
  // 过滤器
  filters: {
    // 过滤可用于类似值集显示
    baoxixi (num, attr) {
      let data = attr.filter(item => { return item.num === +num })
      let title = data.length ? data[0].title : '未过滤出来,不过宝还是帅'
      return title
    }
  },
  // 自定义函数体 - vue页面中存放方法的地方
  methods: {
    // methods方法,跟前面的都不一样,我们通常在这里面写入方法,只要调用就会重新执行一次,相应的有一些触发条件,在某些时候methods和computed看不出来具体的差别,但是一旦在运算量比较复杂的页面中,就会体现出不一样。
    // 需要注意的是,computed是具有缓存的,这就意味着只要计算属性的依赖没有进行相应的数据更新,那么computed会直接从缓存中获取值,多次访问都会返回之前的计算结果。
    bao () {
      this.oldTitle = '变动后'
    },
    backshows () {
      console.log('directives也可以回调方法')
    }
  },
  // 自定义挂载属性 - 当组件挂载时候执行
  directives: {
    //  自定义挂载属性本章上部分已讲
  },
  // v-model接收 - 下面传父子交互会讲
  model: {
    // v-model值的操作
  },
}
</script>

父子交互

<!-- 父组件 -->
<template>
 <div>
   <p>父-双向绑定的值:<span v-text="baoModel" /></p>
   <!-- childBao - 组件已全局挂载 - 在main.js - Vue.component('childBao', childBao) -->
   <childBao v-model="baoModel" :baoData="baoData" @childBaoBackClick="baoClick" :disabled='false' />
 </div>
</template>

<script>
export default {
  name: 'Bao',
  data () {
    return {
      // 父组件绑定的值
      baoModel: '18',
      // 给子组件提供的数据
      baoData: [
        { name: '小朋友', key: 18 },
        { name: '宝宝', key: 28 },
        { name: '宝贝', key: 38 }
      ]
    }
  },
  watch: {
    // 监听值变动
    baoModel () { console.log('监听触发了变动') }
  },
  methods: {
    // 子组件触发并emit返回触发
    baoClick (title, data) {
      alert(`这里是父组件方法-括号内输出子组件传回来内容( ${title + data} )`)
    }
  }
}
</script>
<!-- 子组件 -->
<template>
  <div>
      <select v-model="childBaoModel">
          <option
            v-for="(item,index) in baoData"
            :key="index"
            :value="item.key"
            v-text="item.name"
            :disabled="disabled"
          />
      </select>
  </div>
</template>

<script>
export default {
  name: 'childBao',
  data () {
    return {
      // 子组件绑定的值
      childBaoModel: this.baoModel
    }
  },
  // v-model接收
  model: {
    // prop - 使用b-model传来的值 - 需要在props声明接收
    prop: 'baoModel',
    // event - 你将要更新来源的值 - $emit反回去
    event: 'upBaoModel'
  },
  // 父传子接收声明
  props: {
    // 父v-model值
    baoModel: {
      type: [String, Number], // type接受值的类型
      default: '' // 如果没有传 - default就为默认值
    },
    // 下拉数据
    baoData: {
      type: Array,
      default: () => {
        return [] // 数组与对象需要return
      }
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    // 监听父传子的v-model值的变动
    baoModel (value) {
      this.childBaoModel = value
    },
    // 监听子绑定值的变动
    childBaoModel (value) {
      // 更新父v-model的值
      this.$emit('upBaoModel', value)
      // emit返回触发父组件定义好的方法
      this.$emit('childBaoBackClick', '我是子组件往父组件传的值:', value)
    }
  }
}
</script>

ref与slot

动态路由

结束话语

[- 结束话语 -](#bao10)