vue 基础学习

389 阅读6分钟

1.vue调试

vscode 调试 Debugger for Chrome

{
"version": "0.2.0", 
"configurations": [ 
{ 

"name": "Launch localhost",
"type": "chrome", 
"request": "launch", 
"url": "http://localhost/index.html", 
"webRoot": "${workspaceFolder}/wwwroot" 
},

{ 
"name": "Launch index.html", 
"type": "chrome", 
"request": "launch", 
"file": "${workspaceFolder}/index.html" 
}, 
]

2.vue 插件

安装vetur和vue vscode snippets

可以使用 v开头的快捷命令。

3.脚手架

npm i -g @vue/cli

npm install -g @vue/cli-service-global
vue serve ./Hello.vue

使用插件  
vue add router //安装vue-router

4.vue的思想

  1. 是一个数据驱动的应用
  2. 是MVVM的践行者 image.png

vm:连接数据与视图层的中间层,避免用户直接操作dom

mvvm的三大要素:

  • 响应式:1.数据驱动:修改数据时候,通过vm的data绑定实现响应式视图层刷新。2.同时视图通过vm添加dom监听刷新数据层。
  • 模版引擎:模版引擎编写与解析
  • 渲染:如何把模版转换成html:1.模版转化成渲染函数,2.渲染函数生成虚拟dom,虚拟dom最终渲染成正式dom 通过VM层 实现 数据层与视图层之间

5.常用语法

// 5.插值文本
//mustache 语法-插值,双大阔号
<h1>{{title}}</h1>
标签属性
<h2 v-bind:title="title">...</h2>
//或者
<h2 :title="title">...</h2>

//6.插值文本
//v-for 指令需要使用 item in items
<ul><li v-for="c in courses" :key="c">{{c}}</li> </ul>


//表单输入绑定
v-model 绑定  <input> 、 <textarea> 及 <select>,双向绑定
 v-model 本质上是语法糖
 
事件绑定
v-on 绑定   
//添加修饰符的键盘事件
<input v-model="course" type="text" v-on:keydown.enter="addCourse"/>

<button v-on:click="addCourse">新增课程</button>
//或者
<button @click="addCourse">新增课程</button>

//样式处理 class 类的方式
<li v-for="c in courses" :class="{active: (selectedCourse === c)}">{{c}}</li>
//样式处理 class 数组的方式
<li v-for="c in courses" :class="['a','b','c']">{{c}}</li>

//样式处理 style 驼峰式定义对象
<li v-for="c in courses" :style="{backgroundColor:(selectedCourse === c)?'#ddd':'transparent'}">{{c}}</li>
//样式处理 style 系统自带样式分隔符,用单引号 'background-color'
<li v-for="c in courses" :style="{'background-color':(selectedCourse === c)?'#ddd':'transparent'}">{{c}}</li>
//样式处理 style 数组方式
<li v-for="c in courses" :style="[baseStyles,overridingStyles]" >  {{c}}</li>
 data: {
            baseStyles: {
                color: 'green',
                fontSize: '30px'
            },
            overridingStyles: {
                'font-weight': 'bold'
            }
        }
 

6.计算属性与监听器

//computed 

<p>课程总数:{{totalCount}}</p>
computed: {
    totlal(){
        return this.courses.length + '门'
    }
}

//watch简写
watch: {
    courses(newVal,oldVal){
            this.totalCount = newVal.length + '门'
        }
}
//带选项的watch
watch: {
    courses:{
        immediate:true,
        handler(newVal,oldVal){
            this.totalCount = newVal.length + '门'
        }
    }
}
//

计算属性与监听器对比 1.computed:

  • 1是计算值
  • 2计算属性有缓存,是把关联的信息定义出新的对象做集合。是多个数据B,C,D依赖一个A,其中一个数据B变化会导致A重新计算 2.watch:
  • 1是观察动作
  • 2.watch监听没有缓存,监听的是具体相关的对象信息,如果监听对象嵌套很多层也会一起响应监听,适合一个值A影响多个B,C,D的关系
  • 3.一般适合,在输入框不停录入的异步请求,可以加防抖实现变化后请求的效果。

7.v-if和v-show 区别

v-if 元素是懒加载,条件不满足不会在页面显示
v-show 通过display控制是否显示,元素总是存在页面。

8.模版语法实现

1.vue通过模版编译成虚拟dom的渲染函数,结合响应式系统,vue能够比较出重新渲染多少个组件,并把dom操作减少到最低。

//通过打印 查看生成的方法
console.log(app.$options.render)

(function anonymous( ) { with(this){return _c('div',{attrs:{"id":"app"}},[_c('h2',{attrs: {"title":title}},[_v("\n "+_s(title)+"\n ")]),_v(" "),_c('input',{directives:[{name:"model",rawName:"v-model",value: (course),expression:"course"}],attrs:{"type":"text"},domProps:{"value": (course)},on:{"keydown":function($event) {if(!$event.type.indexOf('key')&&_k($event.keyCode,"enter",13,$event.key,"Enter" ))return null;return addCourse($event)},"input":function($event) {if($event.target.composing)return;course=$event.target.value}}}),_v(" "),_c('button',{on:{"click":addCourse}},[_v("xxxx")]),_v(" "),(courses.length == 0)?_c('p',[_v("xxxx")]):_e(),_v(" "),_c('ul',_l((courses),function(c){return _c('li',{class:{active: (selectedCourse === c)},on:{"click":function($event){selectedCourse = c}}}, [_v(_s(c))])}),0)])} })

//可以直接使用render函数渲染
const app = new Vue({ // 引入上面的render函数,则不需要定义<div id="app"></div>里面的内容,
    render() { with (this) { return ... } }
})
自定义的render() 等价于  app.$options.render 根据<div id="app"></div>生成的render()

结论:vue通过他的编译器,把模板的内容编译成渲染函数,当数据发生变化的时候,再次执行渲染函数,通过新旧dom对比得出需要的dom操作。

9.生命周期

定义:vue在被创建的时候,都要经过一系列的初始化过程,需要设置数据监听,模版编译,将实例挂载到dom,并在数据变化的时候更新dom。称为vue实例的生命周期。

  • 异步请求 使用 cretead 和 mounted 都可以。钩子函数 网络请求场景,在实际场景中挂载的速度很快,区别不大。
  • created 组件实例已经创建未挂载,所以也是可以发起网络请求,缺点不能操作dom
  • mounted 组件实例+挂载,也可以发起网络请求,优点可以操作dom,$el已经挂载

image.png


//当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

var vm = new Vue({
    el: "#container",
    data: {
        test : 'hello world'
    },
    beforeCreate: function(){//组件实例都还没实例化,只适合于插件的简单初始化
        console.log(this);
        showData('创建vue实例前',this);
    },
    created: function(){//已经初始化,适合做异步操作
        showData('创建vue实例后',this);
    },
    beforeMount:function(){//未渲染和更新,未创建dom
        showData('挂载到dom前',this);
    },
    mounted: function(){//dom已经创建,可以访问dom
        showData('挂载到dom后',this);
    },
    beforeUpdate:function(){//可以获取更新前数据
        showData('数据变化更新前',this);
    },
    updated:function(){//所有状态都是最新
        showData('数据变化更新后',this);
    },
    beforeDestroy:function(){//实例还在,适合定时器,订阅销毁
        showData('vue实例销毁前',this);
    },
    destroyed:function(){//实例不在,也可以做定时器销毁
        showData('vue实例销毁后',this);
    }
    //前提使用keeplive
    activated:function(){
        showData('vue实例被唤醒',this);
    }
    deactivated:function(){
        showData('vue实例休眠',this);
    }
});

10.组件化

组件是可复用的 Vue 实例,带有一个名字 Vue.component(name, options)可用于注册组件。

自定义事件及其监听 当子组件需要和父级组件进行通信,可以派发并监听自定义事件。

<!--父组件使用 -->
<course-add @add-course="addCourse"></course-add>

<!--子组件告诉父组件 -->
methods: { 
    addCourse() { // 发送自定义事件通知父组件  
        this.$emit('add-course', val)  // 注意事件名称定义时不要有大写字母出现
    } },

组件实现v-model v-model:本质上是语法糖,自实现需要同时处理@input和:value

<!-- 自定义组件支持v-model需要实现内部input的:value和@input --> 
<course-add v-model="course" @add-course="addCourse"></course-add> 
<script>
Vue.component('course-add', {  
    props: ['value'], // 接收父组件传递value
    template: 
    ` <div>
        <!-- 需要实现input的:value和@input --> 
        <input :value="value" @input="onInput" 
        @keydown.enter="addCourse"/> 
        <button v-on:click="addCourse">新增课程</button> 
      </div> 
    `,
    methods: { 
        addCourse() { 
            // 派发事件不再需要传递数据 
            this.$emit('add-course')
            },
        onInput(e) { 
            this.$emit('input', e.target.value)
        } 
    }, 
})

const app = new Vue({ 
    data: { 
        course: '', // 还原course 
    },
    methods: { 
        addCourse() {// 还原addCourse 
            this.courses.push(this.course); 
            this.course = ''; 
        }
    } 
}) 
</script> 

11. is用于解决语意化场景

//
 <ul>
  <my-component></my-component>
  <my-component></my-component>
</ul>
//html可能会报错
<ul>
  <li is='my-component'></li>
</ul>
// <li is='my-component'></li>其实就相当于<my-component></my-component>

12.插槽:内容分发

通过使用vue提供的 元素可以给组件传递内容 通过占位符

<!-- 为了保持单向数据流,只能改变父组件内容  -->
<!--定义  -->
Vue.component('message', { 
props: ['show'], 
template: ` 
<div class="message-box" v-if="show"> 
    <strong><slot name="title"></slot></strong> 
     <span @click="$emit('close',false)">X</span>
</div> 
` 
})
<!--使用 -->
data(){
    return {
        show:false,
    }
}
<message :show="show" @close="show=$event" >
    <template v-slot:title>恭喜</template>
</message>

<!--写法2  :show.sync 对应@update:show= -->
<!--定义  -->
Vue.component('message', { 
props: ['show'], 
template: ` 
<div class="message-box" v-if="show"> 
    <strong><slot name="title"></slot></strong> 
    <slot></slot> 
     <span @click="$emit('update:show',false)">X</span>
</div> 
` 
})
<!--使用 -->
<message :show.sync="show">
    <template v-slot:title>恭喜</template>
    <template>新增课程成功!</template> 
</message>

13.Vue中的作用域插槽

希望在外部父组件上 就可以操作显示在插槽里的数据
const sonCom = {
      template: `
      <div>
        <slot name="son" :user="user">子组件数据:{{user.firstName}}</slot>
      </div>
      `,
      data() {
        return {
          user: {
            firstName: '三',
            lastName: '张'
          }
        }
      }
    }
    //父组件调用子组件时,假设不想展示firstName了,想展示lastName,按照下面这样写是不行的。
   <div id="app">
        <son-com>{{user.lastName}}</son-com>
  </div>
  
  //正确的方式 通过作用域方式
   <div id="app">
    <son-com v-slot:son="scope">{{scope.user.lastName}}</son-com>
  </div>
  //Vue是单向数据流。传递给子组件的数据,若要修改,应在父组件中处理。而我们通过作用域插槽,正好可以在父组件中修改数据,方便安全。

14.Vue组件化的理解

  • 组件化是Vue的精髓,Vue应用就是由一个个组件构成的。
  • Vue的组件化涉及到的内容非常多,当面试时被问到:谈一下你对Vue组件化的理解。这时候有可能无从下手,可以从以下几点进行阐述:
  • 定义:组件是可复用的 Vue 实例,准确讲它们是VueComponent的实例,继承自Vue。
  • 优点:从上面案例可以看出组件化可以增加代码的复用性、可维护性和可测试性。
  • 使用场景:什么时候使用组件?以下分类可作为参考:
  • 通用组件:实现最基本的功能,具有通用性、复用性,例如按钮组件、输入框组件、布局组件等。
  • 业务组件:它们完成具体业务,具有一定的复用性,例如登录组件、轮播图组件。
  • 页面组件:组织应用各部分独立内容,需要时在不同页面组件间切换,例如列表页、详情页组件

15.如何使用组件

  • 定义:
  1. Vue.component(),
  2. sfc(Vue单文件组件)Single-FileComponent
  3. components选项里直接定义tempalte
  4. components 引用对应的 let comp={ template:"<div>嘻嘻嘻<div>"}
  • 分类:有状态组件,functional,abstract
  • 通信:props,$emit()/$on(),provide/inject,$children/$parent/$root/$attrs/$listeners(强依赖,不利于重构,一旦父子关系变化)
  • 内容分发:,