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的思想
- 是一个数据驱动的应用
- 是MVVM的践行者
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已经挂载
//当组件在 <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.如何使用组件
- 定义:
- Vue.component(),
- sfc(Vue单文件组件)Single-FileComponent
- components选项里直接定义tempalte
- components 引用对应的
let comp={ template:"<div>嘻嘻嘻<div>"}
- 分类:有状态组件,functional,abstract
- 通信:
props,$emit()/$on(),provide/inject,$children/$parent/$root/$attrs/$listeners(强依赖,不利于重构,一旦父子关系变化) - 内容分发:,