美文网首页
【美团网项目】2.Vue基础知识

【美团网项目】2.Vue基础知识

作者: irenb | 来源:发表于2020-07-22 17:53 被阅读0次

    知识点

    • 环境搭建(如何快速搭建 Vue 环境 / 创建一个 Vue 项目)
    • 模板语法
    • 计算属性
    • 类与样式
    • 条件&列表渲染
    • 事件处理
    • 深入了解组件
    • 路由基础(单页面应用会涉及到路由,如何配置路由)
    • Vuex基础(跨组件通信、状态保护都依赖于 Vuex)

    环境搭建

    搭建环境有很多种方式,这里我们采用最快速最便捷的脚手架(构建工具 vue-cli)方式,这个脚手架是 vue 官方提供的。

    • vue-cli@3(vue 脚手架,当前版本是3,是 vue 的一个构建工具)
    • vue@2.5(vue 语法,当前使用的是2.5版本)

    vue 脚手架指的是 vue-cli,它是一个专门为单页面应用快速搭建繁杂的脚手架,它可以轻松的创建新的应用程序而且可用于自动生成 vue 和 webpack 的项目模板。

    1. 安装 vue-cli 构建工具(-g 表示全局安装)

    $ npm install -g @vue/cli
    # 或
    $ yarn global add @vue/cli
    
    # 查看安装的版本
    $ vue -V
    

    2. 创建一个 Vue 项目:使用 vue-cli 脚手架快速创建

    # 基于交互式命令行的方式创建新版 vue 项目
    $ vue create vue-demo
    # 或
    # 基于图形化界面的方式创建新版 vue 项目
    $ vue ui
    

    【补充说明】:使用 npm install -g @vue/cli 命令进行安装,如果在Mac上报如下错误:

    # MacOS,安装npm全局包提示没有写入权限:
    npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules
    

    解决方法:
    修改npm包所安装目录的权限:sudo chown -R $USER /usr/local 然后输入密码就可以了
    查看目录是否已切换权限:ls -l /usr/local

    3. 编译、运行 vue 项目

    # 进入项目目录
    $ cd vue-demo
    # 编译项目
    $ npm run serve
    
    • 编译成功如下:
     DONE  Compiled successfully in 2878ms                         4:00:54 ├F10: PM┤
    
      App running at:
      - Local:   http://localhost:8080/ 
      - Network: http://192.168.1.121:8080/
    
      Note that the development build is not optimized.
      To create a production build, run npm run build.
    

    复制上面的网址到浏览器即可预览项目运行的效果~

    模板语法

    • 插值(文本赋值)
    <!-- 1.【纯文本赋值】插值表达式 -->
    <span>{{ msg }}</span>
    <!-- 2.【纯文本赋值】使用 v-text 指令 -->
    <span v-text="msg"></span>
    <!-- 3.【一次性赋值】当数据改变时,插值处的内容不会更新 -->
    <span v-once>{{ msg }}</span>
    <!-- 4.【富文本赋值】使用 v-html 指令:可以输出带 HTML 标签的文本 -->
    <span v-html="msg">内容</span>
    

    关于v-html:你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。

    • 绑定属性指令 v-bind:属性名
    <input type="button" value="按钮" v-bind:title="mytitle">
    <!-- "v-bind:" 可以缩写成 ":" -->
    <input type="button" value="按钮" :title="mytitle">
    
    • 绑定事件指令 v-on:事件名
    <input type="button" value="按钮" v-on:click="show">
    <!-- "v-on:" 可以缩写成 "@" -->
    <input type="button" value="按钮" @click="show">
    

    计算属性

    • 对于任何复杂逻辑,你都应当使用计算属性,可以解决响应式依赖问题。
    • 应用场景:具有依赖关系的数据监听。
    <div class="demo1">
      <p>{{ message }}</p>
      <!-- message 发生改变时,reversedMessage会更新 -->
      <p>翻转字符串: "{{ reversedMessage }}"</p>
    </div>
    
    <div class="demo2">{{ fullName }}</div>
    
    var vm = new Vue({
      el: '#app',
      data: {
        message: 'Hello',
        firstName: 'Foo',
        lastName: 'Bar'
      },
      // 计算属性
      computed: {
        // 计算属性的 getter
        reversedMessage: function () {
          // `this` 指向 vm 实例
          return this.message.split('').reverse().join('')
        },
        fullName: function () {
          return this.firstName + ' ' + this.lastName
        }
      }
    })
    

    类与样式

    • 动态切换样式
    <!-- 一般用法 -->
    <h1 class="red thin">我是一个很长很长的标题!!!</h1>
    
    <!-- Vue中用法:使用数组 -->
    <h1 v-bind:class="['red', 'thin']">我是一个很长很长的标题!!!</h1>
    <h1 :class="['red', 'thin', isActive ? 'active' : '']">我是一个很长很长的标题!!!</h1>
    <h1 :class="['red', 'thin', {'active': isActive}]">我是一个很长很长的标题!!!</h1>
    
    <!-- Vue中用法:直接使用对象 -->
    <h1 :class="{red: true, thin: true, active: isActive}">我是一个很长很长的标题!!!</h1>
    
    <!-- 绑定一个返回对象的计算属性。这是一个常用且强大的模式 -->
    <h1 :class="classObject">我是一个很长很长的标题!!!</h1>
    
    data: {
      isActive: true,
      error: null
    },
    computed: {
      // 计算属性:当 isActive 或者 hasError 变化时,class 列表将相应地更新。
      classObject: function () {
        return {
          active: this.isActive && !this.error,
          'text-danger': this.error && this.error.type === 'fatal'
        }
      }
    }
    

    条件&列表渲染

    • 条件渲染 v-if
    <!-- v-if 的特点:每次都会重新删除或创建元素 -->
    <!-- v-show 的特点:每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式 -->
    <h1 v-if="flag">这是用v-if控制的元素</h1>
    <h1 v-show="flag">这是用v-show控制的元素</h1>
    
    • 列表渲染 v-for
    <!-- 遍历数组:list 是数据源数据,item 是数组的每一项(item也可以用其它名称,如:obj),key 跟踪每个节点的唯一性 -->
    <p v-for="item in list" :key="item.id">{{ item }}</p>
    <p v-for="(item, i) in list" :key="item.id">索引值:{{ i }} , 每一项的值:{{ item.name }}</p>
    

    事件处理

    <!-- v-on 指令:后面可以直接跟JS表达式 -->
    <button v-on:click="counter += 1">Add 1</button>
    <!-- v-on 指令:后面可以跟方法名 -->
    <button v-on:click="show"></button>
    <!-- v-on 指令:后面可以跟方法名 + 传参 -->
    <button v-on:click="show('hello')"></button>
    
    <!-- $event:传入原始的 DOM 事件,即原生事件对象-->
    <button v-on:click="show('hello', $event)"></button>
    
    <!-- v-on: 可以缩写成 @,后面可以加【事件修饰符】(.stop 阻止事件冒泡) -->
    <button @click.stop="show('hello')"></button>
    <!-- 监听“Enter键”抬起事件(即输入框键盘回车事件)【按键修饰符】 -->
    <input type="text" v-model="name" @keyup.enter="nameEnter">
    

    深入了解组件

    组件:模板(必须的,且仅有一个根节点) + script + 样式(如:HelloWorld.vue

    <template>
      <div class="hello">
        <h1>{{ msg }}</h1>
        <div v-html="msg1"></div>
      </div>
    </template>
    
    <script>
    
    export default {
      /*
        name 相当于一个全局 ID;
        name 非必选项,可以不写;
        写了可以提供更好的调试信息(官方文档有)。
       */
      name: "HelloWorld",
    
      // 组件传参入口,接收外部传入的参数
      props: {
        msg: String,
      },
    
      /*
        data: {
          msg1: "aaa"
        }
      */
    
      // 组件中的data属性必须是函数,这里不能使用data对象。原因是这里有多实例共享data的问题,使用函数让每个组件实例各自维护自己的data(独立的拷贝),互不影响。
      data() {
        return {
          msg1: '<span style="color:red">子组件富文本</span>',
        }
      },
    
      methods: {
        show() {
          console.log('show方法');
        }
      }
    };
    </script>
    
    <!-- 私有样式:添加“scoped”属性来限制CSS只适用于此组件内部-->
    <style scoped>
    h1 {
      margin: 40px 0 0;
    }
    </style>
    
    • props:组件之间的参数传递(父组件向子组件传参,单向的)
    <script>
    export default {
      name: 'HelloWorld',
    
      // 组件传参入口,接收外部(父组件)传入的参数
      // props: ['age'],
      props: {
        age: Number
      },
    
      data() {
        return {
          name: '张三'
        }
      }
    }
    </script>
    
    • slot:插槽在组件抽象设计中的应用。我们在定义组件时,可以在组件中放一个插槽,插槽在将来可以放任意的不确定的子组件(即可以通过插槽动态往组件中添加内容),从而提高组件的灵活性和复用性。
    <!-- 1.定义组件-->
    <template>
      <div class="hello">
        <!-- 在头部添加插槽 -->
        <slot name='header'></slot>
        <h1>子组件主体内容</h1>
        <!-- 在尾部添加插槽 -->
        <slot name='footer'></slot>
      </div>
    </template>
    
    ... ...
    
    <!-- 2.使用组件-->
    <template>
      <div id="app">
        <HelloWorld :age='myAge'>
          <h3 slot='header'>自定义头部内容</h3>
          <h3 slot='footer'>自定义尾部内容</h3>
        </HelloWorld>
      </div>
    </template>
    
    • 自定义事件:父子组件的通信方式(可以解决子组件向父组件传递参数)
    <!-- 自定义事件1:组件内部的事件定义 -->
    <!-- <button type='button' name='button' @click='handleMsg'>发送到父组件</button> -->
    <!-- 【子组件中】自定义事件2:组件外部的事件定义(子组件将消息发送到父组件,可以携带参数) -->
    <button type='button' name='button' @click='$emit("handleMsg", 36)'>发送到父组件</button>
    
    <!-- 【父组件中】通过自定义事件(@handleMsg),接收子组件发送的消息 -->
    <!-- 在这里可以通过 $event 获取传过来的值(即这里 $event 等于 36);在 clickHandle 函数中可以通过形参获取传过来的值 -->
    <HelloWorld :age='myAge' @handleMsg='clickHandle' />
    

    export 的作用,与 export default 的区别:

    一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用 export 关键字输出该变量。

    export 的作用:向外暴露对象。export命令对外输出了指定名字的变量(变量也可以是函数或类)。

    exportexport default 的区别:

    //【export 的使用】:在一个模块中,export、import可以有多个(都需要加大括号),import时要注意变量名(可以取别名)与export时保持一致。
    // profile.js
    var name = 'zhangsan';
    var age = 28;
    var func = function() {};
    export {name, age, func};
    
    // 对应的导入方式
    import { name } from './profile.js';
    // 可以使用as关键字,将输入的变量重命名。
    import { myName as name } from './profile.js';
    // 导入多个
    import { name, age, func } from './profile.js';
    
    
    //【export default 的使用】:在一个模块中,export default、import仅有一个(都不需要加大括号),import时变量名可以取任意名字。
    // profile.js
    var name = 'zhangsan';
    export default name;
    
    // 对应的导入方式
    import customName from './profile.js';
    

    路由基础

    vue-router的实现原理:路由不同的页面也就是加载不同的组件。

    路由的三个基本概念:

    • route:一条路由,如:{ path: '/', component: PageA }
    • routes:一组路由,如:[{ path: '/', component: PageA }, { path: '/pageb', component: PageB }]
    • router:管理路由,一个机制,想当于一个管理者。
    • 客户端中的路由:dom元素显示或隐藏,基于hash和基于HTML5 history api。

    vue-router中的路由基于以上4点实现:在vue中我们所有的内容都是组件化的,所有只需要把路径和组件对应起来,然后在组件中把页面渲染出来就可以了。

    安装 vue-router:

    $ npm install vue-router
    

    页面实现:
    在vue-router中,由两个标签<router-view>和<router-link>来对应点击和显示部分;<router-link> 就是定义页面中点击的部分,<router-view> 定义显示部分,就是在点击后匹配的内容显示在什么地方;<router-link>还有一个非常重要的属性to,定义点击之后跳到哪里去。

    路由的使用:在src目录下再新建一个 router.js 定义 router

    /// -------------------- router.js --------------------
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    // 1. 导入(路由)组件
    import PageA from './pages/a.vue'
    import PageB from './pages/b.vue'
    
    // 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter),把 VueRouter 加进来,才能进行实例化
    Vue.use(VueRouter);
    
    // 2. 定义路由(每个路径映射一个组件)
    // 首次进入页面的时候,页面没有内容,因为首次进入页面,它的路径是'/',我们并没有给这个路径做相应的配置,我们要把这个路径指向PageA,用redirect来定义重定向:
    const routes = [
        {
            path: "/pagea",
            component: PageA
        },
        {
            path: "/pageb",
            component: PageB
        },
        {
            path: '/',
            redirect: '/pagea'
        }
    ];
    
    // 3.路由的实例化(最后再将路由的实例和app实例关联)
    const router = new VueRouter({
        routes // (缩写) 相当于 routes: routes
    });
    
    export default router;
    

    4.把 router 实例注入到vue根实例中,开始使用

    import Vue from 'vue'
    import App from './App.vue'
    
    // 引入路由
    import router from "./router.js"
    new Vue({
      el: '#app',
      router,  // 注入到根实例中
      render: h => h(App)
    })
    

    5.最后要在 App.vue 中 添加 <router-view></router-view> (将路由匹配到的组件渲染到页面中去)

    <template>
      <div class="app">
        <header>
          <!-- 路由的切换:router-link 定义点击导航后到哪个路径下 -->
          <router-link to='/pagea'>进入A页面</router-link>
          <router-link to='/pageb'>进入B页面</router-link>
        </header>
        <!-- 对应的组件内容渲染到router-view中 -->
        <router-view></router-view>   
      </div>
    </template>
    
    <script>
    export default {
    }
    </script>
    

    补充:this.$router.push("pagea") 也可以实现路由跳转。

    执行过程:当用户点击 router-link 标签时,会去寻找它的 to 属性, 它的 to 属性和 js 中配置的路径{ path: '/pagea', component:PageA} path 一一对应,从而找到了匹配的组件, 最后把组件渲染到 <router-view> 标签所在的地方。所有的这些实现才是基于hash 实现的。

    执行流程:项目加载的过程是index.html -> main.js -> app.vue -> index.js -> xxx.vue,如果main.js里面有钩子,会先走钩子。

    Vuex基础

    vuex是专门用来管理vue.js应用程序中状态(这里所说的状态指的是vue组件中data里面的属性)的一个插件。他的作用是将应用中的所有状态都放在一起,集中式来管理。

    把组件的共享状态抽取出来,以一个全局单例模式管理。任何组件都能获取状态或者触发行为。

    Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

    组件之间的传值:

    • 父组件传子组件:通过子组件的 props 属性
    • 子组件传父组件:通过自定义事件发送消息,传递参数
    • 跨组件传递数据:多个组件之间公用一份数据

    安装 Vuex

    $ npm install vuex
    

    VueX中的核心内容:
    在VueX对象中,其实不止有 state,还有用来操作 state 中数据的方法集,以及当我们需要对 state 中的数据需要加工的方法集等等成员。

    成员列表:

    • state 存放状态
    • getters 加工state成员给外界
    • mutations state成员操作
    • actions 异步操作
    • modules 模块化状态管理
    /// -------------------- store.js --------------------
    import Vue from 'vue'
    import Vuex from 'vuex';
    
    // 加载插件
    Vue.use(Vuex);
    
    // 1.定义 state (数据部分,相当于组件中的data;数据变化后,会重新渲染到组件中)
    const state = {
        count: 1
    }
    
    // 2.定义 mutations,在内部对数据进行操作(即修改state中的数据)
    const mutations = {
        // 执行这个函数的时候对 count 加 1
        increment(state) {
            state.count++;
        },
        // 执行这个函数的时候对 count 减 1
        decrement(state) {
            state.count--;
        }
    }
    
    // 3.定义 actions (actions 是用来接收 vue组件 中的用户行为 dispatch,进一步去触发要做的 commit,通过 commit 来告诉 mutations 要执行哪个操作做数据修改)
    const actions = {
        increment: ({ commit }) => {
            // 参数是 mutations 中的函数名
            commit('increment');
        },
        decrement: ({ commit }) => {
            commit('decrement');
        }
    }
    
    const store = new Vuex.Store({
        state,       // 存放状态
        // getters,  // state的计算属性(加工state成员给外界)
        mutations,   // 更改state中状态的逻辑,同步操作(state成员操作)
        actions      // 提交mutation,异步操作
        // mudules   // 将store模块化
    })
    
    // es6模块导出
    export default store;
    
    
    // 4.注入到 Vue 根实例中
    /*
        new Vue({
            store,      // 在根节点注入 store
            render: h => h(App),    // 渲染 App.vue 页面,作为启动页
        }).$mount('#app')
    */
    

    5.在组件中读取或操作 vuex(store.js)中的数据

    <!---------------------------- HelloWorld.vue ---------------------------->
    <template>
      <div class="hello">
        <!-- 读取 vuex(store.js)中的数据 -->
        vuex {{ $store.state.count }}
        <button type="button" @click="increment">增加</button>
        <button type="button" @click="decrement">删减</button>
      </div>
    </template>
    
    <script>
    
    import { mapActions } from 'vuex';
    
    export default {
      // 在组件中分发 Action (关联方法):组件中调用 vuex(store.js)中定义的方法
      // 组件内 increment()函数 映射为 $store.dispatch('increment')
      // 组件内 decrement()函数 映射为 $store.dispatch('decrement')
      methods: mapActions(['increment', 'decrement'])
    }
    </script>
    
    <style scoped>
    </style>
    

    相关文章

      网友评论

          本文标题:【美团网项目】2.Vue基础知识

          本文链接:https://www.haomeiwen.com/subject/exutlktx.html