0

一些简单的 Vue.js 笔记

 1 year ago
source link: https://blog.kelu.org/tech/2022/05/07/vuejs.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
vue.jpg

前端不是我的主业,不过太久不用,捡起来每次都觉得头疼,还是稍微做点笔记吧。

首先是官方文档:https://cn.vuejs.org/v2/guide/,虽然目前到3版本了,还是先了解下v2版本的知识,并不复杂。

一、基本方法

基本就是官网内容。

  1.  <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
        
     <div id="app">
          
     </div>
        
     var app = new Vue({
       el: '#app',
       data: {
         message: 'Hello Vue!'
       }
     })
    
    image-20220510110633818
  2. 数据绑定、css绑定、事件绑定和语法糖

    • v-bind:value=<expression> 单项绑定,语法糖 :value=<expression>
    • v-model:value=<expression> 双向绑定(只用表单),语法糖 v-model=`
    • v-bind:class=xxx ,语法糖 :class=<str>
    • v-on:click.stop=<expression> 事件绑定,语法糖 @click.stop=<expression>
      • .stop
      • .prevent
  3. func 里this指针指向的是vm

    computed不吃性能,尽量用它

     var vm = new Vue({
       el: '#example',
       data: {
         message: 'Hello'
       },
          
       computed: {
         // 计算属性的 getter
         reversedMessage: function () {
           // `this` 指向 vm 实例
           return this.message.split('').reverse().join('')
         }
       },
          
       watch: {
         // 如果 `question` 发生改变,这个函数就会运行
         question: function (newQuestion, oldQuestion) {
           this.answer = 'Waiting for you to stop typing...'
           this.debouncedGetAnswer()
         }
       },
          
       created: function () {
         this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
       },
          
       methods: {
         getAnswer: function () {
         }
      },
         
      mounted(){
         
      }
     })
    

    由vue管理的method,要以普通方式定义。

    否则应该用箭头函数,例如:

    getAnswer: function (()=>{})
    

    此时它的this为window。

    另外,指令directive相关的 this 都是 window

  4. 循环语句和条件语句

     <ul id="example-1">
       <li v-for="item in items" :key="item.message">
            
       </li>
     </ul>
        
     <ul id="example-2">
       <li v-for="(item, index) in items">
          -  - 
       </li>
     </ul>
        
     <div v-for="(value, name, index) in object">
       . : 
     </div>
    
     <div v-if="type === 'A'"></div>
     <div v-else-if="type === 'B'"></div>
     <div v-else-if="type === 'C'"></div>
     <div v-else></div>
    
  5. Vue 无法监控数组内容的改变

    https://cn.vuejs.org/v2/guide/list.html#数组更新检测

    对象因为有setter和getter,修改model可以监控到,view也会变动。

    但直接操作数组不奏效,因为数组没有这两个方法,引发view变动则需要调用如下方法:

    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
  6. 过滤器,用于一些常见的文本格式化

  7. 生命周期

    一旦 data 数据变化就会重新解析模版。

    • create

    • mounted做初始化,把初始DOM放入页面时,仅调用一次。

    • update
    • destroy
  8. 组件

    • <template>
      </template>
            
      <script>
      import ComponentA from './ComponentA'
      import ComponentC from './ComponentC'
            
      export default {
        name: ''
        data(){
        },
        components: {
          ComponentA,
          ComponentC
        },
        // ...
      }
      </script>
            
      <style>
      </style>
            
      或者
            
      const vc = Vue.extend({ })
      
    • new Vue({
        el: '#app',
        components: {
          'component-a': ComponentA,
          'component-b': ComponentB
        }
      })
      
    • <div id="app">
        <component-a></component-a>
        <component-b></component-b>
        <component-c></component-c>
      </div> 
      
  9. 原型对象prototype

    实例的隐式原型属性 __prototype__ 永远指向类(父类)的原型对象

    image-20220508152632174

二、脚手架

  1. npm install -g @vue/cli
    vue --version
    vue create hello-world
    
  2. render

    image-20220509105413880

    vue.runtime.xxx.js 是运行版的vue,没有模版解析器,不能使用template配置项。

  3. vue ref,vue用于获取元素,用来代替以前通过id获取元素的办法。

  4. 数据传递prop

    相当于后端中一个类class实例的只读属性,。

    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // or any other constructor
    }
    
  5. 混入 (mixin)

    有点类似于后端的基类和子类,mixin属于基类的方法,多个子类都可以使用基类的方法。

    var vm = new Vue({
      mixins: [mixin],
      methods: {
         ...
      }
    })
    

    可以全局混入,也可以局部混入。

    Vue.mixin({
      xxx: xxx
    })
    
  6. 插件

    // 调用 `MyPlugin.install(Vue)`
    Vue.use(MyPlugin)
    
  7. scope

    解决style类名相同,引入顺序不同,导致冲突的问题。

    <style scoped>
    </style>
    

    不要在App里使用scoped

三、开发步骤(入门)

官网的一些内容和后端思维是互通的,比如状态提升之类的,不要害怕,见人说人话,见鬼说鬼话。

  1. 拆分静态组件,按功能点拆分

  2. 静态组件,不考虑交互

    1. 把html整个塞到app里
    2. 把一个组件的html剪切后立马写占位符,然后塞到组件里。
    3. 把样式也拆了,塞到组件,style加个scoped。
  3. 数据交互设计

    类似于后端,设计数据库和model。

    组件通信的几种方式:

    1. 通过 props 存储数据,数据存在App上。

      1. 父组件定义data,通过props传给子组件(子要在props里接收)
      2. 父组件定义method,通过props传给另一个子组件
      3. 注意子组件的v-model不要改props

      相当于内存存变量。

    2. 自定义事件

      子组件给父组件传数据用。

      在父组件中给子组件绑定自定义事件,事件回调在父组件。(父给子传函数,要求子返回数据)

    3. 全局事件总线

      定义一个所有组件的子组件vc(也可以直接用vm)挂在prototype上,然后使用事件触发。相当于后端的redis。多读单写

    4. 消息订阅&发布

      全局事件总线和消息订阅其实差不多的效果。多读单写

    5. 浏览器localstorage,相当于后端的数据库DB。

  4. 不同功能的增删查改+统计信息变动

    1. 增删,事件event。
  1. 自定义事件

    this.$emit('myEvent')
       
    <my-component v-on:my-event="doSomething"></my-component>
       
    this.$off('myEvent')
    this.$off(['myEvent','xxx'])
    this.$off()
    

    也适用于子给父组件传输数据。

    image-20220509163051261

    自定义事件由父组件运行,props方式由子组件运行。

    还可以通过ref绑定自定义事件。

    image-20220509163610694
  2. 全局事件总线

    定义一个所有组件的子组件vc,然后赋值给prototype。

    image-20220510115509466

    把vm当成所有组件的子组件,这样子?真是奇妙。

    image-20220510120130524
    image-20220511165656535
  3. 消息订阅&发布

    $ npm -i pubsub.js
       
    import pubsub from 'pubsub-js'
       
       
    pubsub.publish('hello',666)
    pubsub.subscribe('hello',function(msgName,data){ })
    pubsub.subscribe('hello',(msgName,data)=>{ })
    
  4. nextTick

  5. 动画/过渡

    其实就是封装了一个 transition 标签。

    <transition name"xxx" appear></transition>
       
    .xxx-enter-active{
    animation: kelu 1s linear;
    }
    .xxx-leave-active{}
       
    @keyframs kelu {
    	from{
    		transform: xxx
    	}
    	to{}
    }
    
    image-20220510163037015

    第三方动画:Animate.css:http://animate.style

  6. axios请求,

    cors(后端解决),代理服务器(前端解决)

    module.exports = {
      devServer: {
        proxy: 'http://localhost:4000'
      }
    }
       
    module.exports = {
      devServer: {
        proxy: {
          '/api': {
            target: '<url>',
            ws: true,
            changeOrigin: true
          },
          '/foo': {
            target: '<other_url>'
          }
        }
      }
    }
       
    # https://github.com/chimurai/http-proxy-middleware#proxycontext-config
    
    image-20220511144557437
    image-20220511145140405
  7. 插槽

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
       
    <base-layout>
      <template v-slot:header>
        <h1>Here might be a page title</h1>
      </template>
       
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
       
      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>
    </base-layout>
    
  8. vuex

    npm i vuex
       
    import Vuex from 'vuex'
    Vue.use(Vuex)
    
    vuex
    import { createApp } from 'vue'
    import { createStore } from 'vuex'
       
    // 创建一个新的 store 实例
    const store = createStore({
      state () {
        return {
          count: 0
        }
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
       
    const app = createApp({ /* 根组件 */ })
       
    // 将 store 实例作为插件安装
    app.use(store)
    

    dispatch -> commit ->

    vc -> Action(ctx,value) -> mutation(state,value)

    dispatch可以跳过,直接commit就行了。

    mapState

    // 在单独构建的版本中辅助函数为 Vuex.mapState
    import { mapState } from 'vuex'
       
    export default {
      // ...
      computed: mapState({
        // 箭头函数可使代码更简练
        count: state => state.count,
       
        // 传字符串参数 'count' 等同于 `state => state.count`
        countAlias: 'count',
       
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
      })
    }
    
    image-20220512135239999
  9. 路由

    npm i vue-router@3
       
    import Vue from 'vue'
    import VueRouter from 'vue-router'
       
    Vue.use(VueRouter)
    
    <router-view></router-view>
    # 一级路由
    
    const routes = [
      {
        path: '/user/:id',
        component: User,
        children: [
          {
            path: 'profile',
            component: UserProfile,
          },
          {
            path: 'posts',
            component: UserPosts,
          },
        ],
      },
    ]
    
      • query参数

      • params参数

      • props(对象/函数/布尔)

        image-20220512160434852

        解构赋值,连续解构赋值:

        image-20220512160650919
        image-20220512160544087
    • 路由历史记录

      声明式 编程式
      <router-link :to="..." replace> router.replace(...)
      <router-link :to="..."> router.push(...)

      路由缓存:

        <keep-alive :include="['xx','yy']">
          <router-view></router-view>
        </keep-alive>
      

      路由组件新增了两个生命周期

      • activated
      • deactivated
    • 数据存在meta里,

      前置路由守卫,主要做鉴权

      // GOOD
      router.beforeEach((to, from, next) => {
        if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
        else next()
      })
      

      后置路由守卫作用,一般就是修改页面内容之类的。

  1. 字面量赋值

    image-20220511154311040

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK