# Vue基础学习 **Repository Path**: wang-kangze/Vue ## Basic Information - **Project Name**: Vue基础学习 - **Description**: 学习Vue.js基础 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 6 - **Created**: 2024-03-19 - **Last Updated**: 2024-03-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Vue基础(核心) ## **初识Vue.js** * 想让Vue工作,就必须创建一个Vue实例,而且需要传入一个配置对象。 * root容器里面的代码依然符合HTML规范,只不过混入了一些特殊的Vue语法 * root容器里面的代码被称为Vue模板 * Vue实例和容器是一一对应的 * 真实开发中只有一个Vue实例,并会配合组件一起使用 * {{ XXX }}中的XXX要 写js表达式,且XXX可以自动读取到data中的所有属性 * 一旦data中的数据发生改变,那么页面中用到数据的地方也会自动更新 * 区分js表达式和js代码(语句) * 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方 * ~~~javascript (1):a (2):a+b (3):demo(1) (4):x===y ? 'a' : 'b' ~~~ * js代码(语句) * ~~~ if(){} for(){} ~~~ **** ## **导入Vue.js** ### **Vue2.js下载** * **开发者版本**:https://v2.cn.vuejs.org/js/vue.js 包含完整的警告和调试模式 * **生产者版本**:https://v2.cn.vuejs.org/js/vue.min.js 删除了警告,37.51KB min+gzip ### **Vue3.js下载** * 进去后又键保存为本地文件进行导入 * **Staticfile CDN(国内)** : https://cdn.staticfile.org/vue/3.0.5/vue.global.js * **unpkg**:https://unpkg.com/vue@next, 会保持和 npm 发布的最新的版本一致。 * **cdnjs** : https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.5/vue.global.js * **Vue导入** * ~~~html ~~~ **** ## **模板字符串** * **语法** * ~~~html

{{ message }}

~~~ * **参考代码** * ~~~html

你好,{{name}}


{{school.name}}

点击
~~~ **** ## **数据绑定** ### **单向绑定** * **语法** * ~~~html ~~~ * 用法 * ~~~html

单向绑定


~~~ ### 双向绑定 * **语法** * ~~~html ~~~ * **用法** * ~~~html

双向绑定

~~~ ### 参考代码 * ```html

单向绑定


双向绑定

``` **** ## **el与data的两种写法** ### el的写法 * **第一种** * ~~~html

{{name}}

~~~ * **第二种** * ~~~html

{{name}}

~~~ ### data的写法 * **第一种** * ~~~html

{{name}}

~~~ * **第二种** * ~~~html

{{name}}

~~~ ### 参考代码 * ```html

{{name}}

``` **** ## MVVM模型 * **M:模型(Model):对应data中的数据** * **V: 视图(View):模板** * **VM: 视图模型(ViewModel):Vue实例对象** * **data中所有属性,最后都出现在了vm身上** * **vm身上的所有属性,包括Vue原型上的所有属性,在Vue模板中都可以直接使用** * **模板字符串可以读取到vm中的所有东西 ** * **参考代码** * ~~~html

{{ name }}

{{ address }}

~~~ **** ## **数据代理** #### 回顾Object.defineProperty方法 * **enumerable 控制是否可以被枚举(遍历),默认值为false** * **writable 控制属性是否被修改,默认值为false** * **configurable 控制属性是否被删除,默认值false** * **当有人读取属性时,get(getter)就会被调用,且返回值是属性的值** * **当有人修改属性时,set(setter)就会被调用,且会收到修改的具体值** * **参考代码** * ~~~html ~~~ #### **何为数据代理** * **数据代理**:通过一个对象代理对另一个对象中属性的操作(读/写) * 参考代码 * ~~~html /* 修改obj1.x的值时,obj2.x的值等于obj1.x的值 */ ~~~ #### Vue中的数据代理 * 修改name时,调用set方法将data中的name修改,然后通过get方法重新渲染DOM * ![image-20231202191112413](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231202191112413.png) * **getter** * 当读取属性时,会执行get中的方法,获取到数据,并渲染页面 * **setter** * 当修改属性时,会执行set中的方法,将修改的数据返回出去 * ![image-20231114190405746](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231114190405746.png) **** ## **事件处理** #### **事件的基本使用** * **使用v-on:xxx 或者@xxx绑定事件,其中xxx是事件名** * **事件的回调需要配置在methods对象中,最终会在vm上** * **methods中配置的函数,不要用箭头函数,不然this就不是vm了** * **methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象** * **@click = "demo" 和 @click = "demo($event)" 效果一致,但后者可以传参** #### 事件的基本使用参考代码 * ~~~html

{{ name }}

~~~ #### **事件修饰符** * **prevent**:阻止默认事件(常用) * ~~~html 点击 ~~~ * **stop**:阻止事件冒泡(常用) * ~~~html
~~~ * **once**:事件只触发一次(常用) * ~~~html ~~~ * **capture**:使用事件的捕获模式 * ~~~html
div1
div2
~~~ * **self**:只有enent.target是当前操作的元素才触发事件 * ~~~html
~~~ * **passive**:事件的默认行为立即执行,无需等待时间回调执行完毕 * ~~~html
~~~ #### 键盘修饰符参考代码 * ~~~html

欢迎来到{{ name }}

点击
div1
div2
~~~ #### **键盘事件** * **Vue中常用的按键别名** * **回车 => enter** * **删除 => delete(捕获“删除”和退格)** * **退出 => esc** * **空格 => space** * **换行 => tap** * **上 => up** * **下 => dowm** * **左 => left** * **右 => right** * **Vue未提供别名的按键,可以使用按键的原始的key值去绑定,但是注意要转为kebab-case(短横线命名)** * **系统修饰见(用法特殊):ctrl、alt、shift、meta(win键)** * **配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才能被触发** * **配合keydowm使用:正常触发事件** * ```HTML ``` * **也可以使用keyCode去指定具体的按键(不推荐)** * **Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名** #### 键盘事件参考代码 * ~~~html

{{ name }}

~~~ **** ## **计算属性** * **只要data中的值改变,模板字符串就会重新解析** * **定义:要用的属性不存在,要通过已有属性计算得来** * **原理:底层借助了Objcet.defineproperty方法提供getter和setter** * **get函数什么时候执行?** * **初次读取时会执行一次** * **当依赖的数据发生改变时会被再次调用** * **优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便** * **备注** * **计算属性最终会出现在vm上,直接读取使用即可** * **如果计算属性要修改,那必须写set函数去响应修改,且set中要引起计算式依赖的数据发生改变** #### 参考代码 * ~~~html
姓: 名: {{ fullName }}
~~~ #### 计算属性简写 * ~~~xml fullName(){ return this.fristName +'-' + this.lastName } ~~~ **** ## **监视属性** #### 监视属性watch * 当被监视的属性变化时,回调函数自动调用,进行相关操作 * 监视的属性必须存在,才能进行监视 * watch的Handler属性会在监视的属性发生改变时会被调用 * watch的Immediate属性为true时,handler会立即调用 * 监视的两种写法 * new Vue时传入watch属性 * ~~~html

今天的天气{{ info }}


a的值是{{ numbers.a }}

~~~ * 通过vm.$watch监视 * ```VUE //第二种,没有确定的属性时写 vm.$watch('isHot',{ //Handler在isHot发生改变时会被调用。 handled(newValue,oldValue){ console.log(newValue,oldValue) }, //当Immediate等于true时使handler立即执行。 immediate:true }) ``` #### **深度监视** * Vue中的watch默认不监测对象内部值的改变(一层) * ~~~ watch:{ isHost: { handled(newValue,oldValue){ console.log(newValue,oldValue) }, immediate:true }, ~~~ * 配置deep:true可以监测对象内部值的改变(多层) * 监视多级结构中某个属性的变化 * ~~~html 'numbers.a':{ handled(newValue, oldValue) { console.log('a改变了') } }, ~~~ * 监视多级结构中所有属性的变化 * ~~~ numbers: { deep:true, handled(){ console.log('number改变了') } } ~~~ * Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以 * 使用watch时根据数据的具体结构,决定是否采用深度监视 #### **深度监视简写** ```html isHost(){ console.log("这是简写方式") } vm.$watch('isHot',function (){ console.log('ishot被监视') }) ``` #### 参考代码 * ```html

今天的天气{{ info }}

``` **** ## **watch对比computed** * computed能完成的功能,watch都可以完成 * watch能完成的任务computer不一定能完成,例如:watch可以进行异步操作 * 两个重要的原则 * 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象 * 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象 ### 参考代码 * ```html
姓: 名: {{ fullName }}
``` **** ## **样式绑定** #### class样式 * 写法::class="XXX" XXX可以是字符串、对象、数组 * 字符串写法适用于:类名不确定,要动态获取 * ~~~html
{{ name }}
~~~ * 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定 * ~~~html
{{ name }}
//样式对象 classObjer:{ fontSize: "40px", color:'red', backgroundColor:'skybule' } ~~~ * 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用 * ~~~html
{{ name }}
//样式数组 classArr:["happy","sad","normal"] ~~~ #### style样式 * :style ="{fontSize:XXX}" 其中XXX是动态值,指的是这个样式的值 * ~~~html
{{ name }}
styObj:{ fontSize: "40px", color:'red', backgroundColor:'skybule' } ~~~ * :style="[a,b]"其中a,b是样式对象 * ~~~html
{{ name }}
styArr:[ { fontSize: "40px", color:'red', backgroundColor:'skybule' }, { border:'1px solid stybule' } ] ~~~ ### 参考代码 * ~~~html Title
{{ name }}
{{ name }}
{{ name }}
{{ name }}
{{ name }}
~~~ **** ## **条件渲染** * v-if * 写法 * v-if = "表达式" * v-else-if="表达式" * v-else="表达式" * 适用于:切换频率较低的场景 * 特点:不展示的DOM元素直接被移除 * 注意:v-if可以和:v-else-if、v-else一起使用,但结构要求不能被打断 * v-show * 写法:v-show = "表达式" * 适用于:切换频率较高的场景 * 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉 * 备注:使用v-if时,元素可能无法获取到,但是使用v-show一定可以获取到 ### 参考代码 * ~~~html
当前n的值为:{{ n }}

{{ name }}

{{ name }}

{{ name }}

{{ name }}

{{ name }}

{{ name }}

{{ name }}

~~~ **** ## **列表渲染** ### 基本列表渲染 * v-for指令 * 用于展示列表数据 * 语法:v-for="(item,index) in XXX” :key="yyy" * 可遍历:数组、对象、字符串(少)、指定次数 * key是给节点一个标识,当key的值为index时,在dom渲染时会自动干掉,如果不写key,vue自动将key的值设为index,但是vue不知道哪个是唯一的主键 * 遍历数组 * ~~~
  • persons: [ {id: '001', name: 'mirage', age: '18'}, {id: '001', name: 'mirage', age: '18'} ] ~~~ * 遍历对象 * ~~~
  • car: { name: 'mirage', color: 'skybule' }, ~~~ * 遍历字符串(少) * ~~~
  • str: 'hello' ~~~ * 遍历指定次数(少) * ~~~
  • ~~~ * 参考代码 * ~~~html
    ~~~ **** ### key的原理 * **key是唯一的** * **react、vue中的key有什么作用?(key的内部原理)** * **虚拟DOM中的key的作用** * key是虚拟DOM对象的标识,当状态中的数据发生变化时,V就会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM和旧虚拟DOM的差异进行比较 * **对比规则:** * 旧虚拟DOM中找到了与新虚拟DOM相同的key * 若虚拟DOM中内容没有变,直接使用之前的真实DOM * 若虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面值之前的真实DOM * 就虚拟DOM中未找到与新虚拟DOM相同的key * 创建新的真实DOM,随后渲染到页面 * **用index作为key可能会引发的问题** * 若对数据进行:逆序添加、逆序删除等破坏顺序操作 * 会产生没有必要的真实DOM更新 ==>界面效果没有问题,但是效率低 * 如果结构中包含着输入类DOM * 产生错误的DOM跟训 ==> 界面有问题 * **开发中如何选择key** * 最好使用每条数据的唯一标识作为key,如id、手机号、身份证号、学号等唯一值 * 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的 * **图解** * ![image-20231125160428733](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231125160428733.png) * ![image-20231125160821157](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231125160821157.png) * 参考代码 * ~~~html
    ~~~ ### 列表过滤 * 使用监视属性watch和计算属性computed两种方式进行过滤 * filter进行过滤,indexOf()功能:返回字符串中匹配子串的第一个字符的下标,indexOf中空字符串为0不为-1 * watch方式 * ~~~html
    ~~~ * computed方式 * ~~~html
    ~~~ ### 列表排序 - 使用数组方法sort进行排序 - 参考代码 - ~~~html
    ~~~ ### 模拟Vue数据监视 * 使用Observer.defineProperty对Vue的数据监视进行模仿 * 参考代码 * ~~~html ~~~ ### Vue中监测数据改变的原理_对象 * ![image-20231204184939920](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231204184939920.png) * 参考代码 * ```html

    名称:{{ student.name }}

    性别:{{ student.sex }}

    年龄:{{ student.age.rage }}

    年龄:{{ student.age.sage }}

    爱好:

    {{ undefined }}

    ``` ### Vue中的set()方法 * 第一种 * ~~~ Vue.set(位置, 添加的属性, 属性的内容) ~~~ * 参考代码 * ~~~html

    名称:{{ student.name }}

    性别:{{ student.sex }}

    年龄:{{ student.age }}

    年龄:{{ student.address }}

    {{ undefined }}

    ~~~ * 第二种 * ~~~ this.$set(位置, 添加的属性, 属性的内容) ~~~ * 参考代码 * ~~~html

    名称:{{ student.name }}

    性别:{{ student.sex }}

    年龄:{{ student.age }}

    年龄:{{ student.address }}

    {{ undefined }}

    ~~~ ### Vue中监测数据改变的原理_数组 * 对于data中的数组,要修改需要调用数组的方法 * pust:往数组后添加东西 * pop:移除数组最后一个元素 * shift:在数组头添加东西 * unshift:删除数组的第一个元素 * splice:对数组的元素进行删除和增加 * sort:对数组进行排序,a-b是升序,b-a是降序 * reverse:反转数组中的元素 * filter:不会对数组进行修改,要用这个需要将过滤后的数组重新赋值给原数组 * Vue中的数组不是数组中的方法了,是数组原型中的方法 * ![image-20231204190922151](C:\Users\21592\AppData\Roaming\Typora\typora-user-images\image-20231204190922151.png) * 参考代码 * ```html

    名称:{{ student.name }}

    性别:{{ student.sex }}

    年龄:{{ student.age }}

    爱好:

    {{ undefined }}

    ``` ### 数据监视原理总结 * Vue会监视data中所有层次的数据 * ``` data: { student: { name: 'mirage', age: '19', hobby: ['唱', '跳', 'RAP'], friends: [ {name: 'Mirage', age: '18'}, {name: 'Clouds', age: '17'} ] } } ``` * 如何检测对象中的数据 * 通过setter实现监视,且要在new Vue时就传入要检测的数据 * 对象中后追加的属性,Vue不做响应式的处理 * 如需要给后添加的属性做响应式处理,请调用以下的api * Vue.set(修改的位置,名称或者索引,内容) * vm.$set(修改的位置,名称或者索引,内容) * 如何检测数组中的数据 * 通过包裹数组更新元素的方法实现,本质上做了两件事: * 调用原生对应的方法对数组进行更新 * 重新解析模板,进而更新页面 * 在Vue中更新数组一定要用如下方法 * 使用数组的api: * push() * pop() * shift() * unshift() * splice() * sort() * reverse() * Vue.set或vm.$set * 如果要使用filter这类不会对原来的数组进行修改的,需要重新赋值给这个数组 * 特别注意:Vue.set()和vm.$set()不能给vm 或 vm根数据对象添加属性 * 参考代码 * ```html

    名称:{{ student.name }}

    性别:{{ student.sex }}

    年龄:{{ student.age }}

    爱好:

    朋友

    {{ undefined }}

    ``` **** ## 表单收集 * 若: ,则v-model收集的是value值,用户输入的就是value的值 * 若: ,则v-model收集的是value值,且要给标签配置value值 * 若: * 没有配置value属性,则收集的是checkbox(勾选or未勾选 布尔值类型) * 配置了value属性: * v-model的初始值是非数组,则收集的是checkbox(勾选or未勾选 布尔值类型) * v-model的初始值是数组,那么收集的是value组成的数组 * 备注:v-model的三个修饰符 * v-model.lazy:失去焦点时收集数据 * v-model.number:输入字符串转为有效数字 * v-model.trim:输入首位空格过滤 * 参考代码 * ```html
    年龄: 性别: 男 爱好: 学习 吃饭 下拉框: 其他: 同意:
    ``` ## 过滤器 * 定义:对要显示的数据进行特定的格式化后再显示(适用于一些简单的逻辑) * 语法 * 注册过滤器Vue.filter(name,回调函数) 或 new Vue{filters:{}} * ``` //创建全局过滤器 Vue.filter('mySlice', function (value) { return value.slice(0, 4) }) ``` * ```html const vm = new Vue({ el: '#root', data: { time: 1702028420972, }, //过滤器实现 filters: { //局部过滤器 timeFormater(value, str = 'YYYY-MM-DD HH:mm:ss') { return dayjs(value).format(str) } } }) ``` * 使用过滤器:{{ xxx | 过滤器名 }} 或 v-bind:属性 = "xxx | 过滤器名" * ```html

    现在是{{ time | timeFormater }}

    现在是{{ time | timeFormater('YYYY_MM_DD') | mySlice}}

    11

    ``` * 备注: * 过滤器可以接受额外的参数(第一个值是过滤器前面的值,第二个值是过滤器中括号里面传的值) * 多个过滤器可以串联 * ```

    现在是{{ time | timeFormater('YYYY_MM_DD') | mySlice}}

    ``` * 先执行完timeFormater的过滤器,再执行mySlice的过滤器 * 并没有改变原来的数据,是产生新的对应的数据 ## 内置指令 * v-bind指令:单向绑定解析表达式,可简写为 :xxx * v-model指令:双向数据绑定 * v-for指令:遍历数组、对象、字符串 * v-on指令:绑定事件监听,可简写为@ * v-if指令:条件渲染(动态控制节点是否存在) * v-else指令:条件渲染(动态控制节点是否存在) * v-show指令:条件渲染(动态控制节点是否展示) * v-text指令:向所在的节点中渲染文本内容 * 与插值语法的区别,v-text会替换掉文本中的内容,{{xx}}则不会 * v-html指令:向指定节点中渲染包含html结构的内容 * 与插值语法区别 * v-html会替换掉节点的内容,{{xx}}则不会 * v-html会识别html结构 * 严重注意v-html有安全性的问题 * 在网站上动态渲染任意html是非常危险的,容易导致xss攻击 * 一定要在可信的内容上使用v-html,永远不要在用户提交的内容上 * v-cloak指令:(没有值) * 本质是一个特殊的属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性 * 使用css配合v-cloak属性可以解决网速慢的时候页面展现出{{ xxx }}的问题 * ```html

    {{name}}

    ``` * v-once指令: * v-once节点在初次动态渲染后,就视为静态内容 * 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能 * v-pre指令: * 跳过其所在节点的编译过程 * 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译 ## 自定义指令 * 语法总结 * 局部指令: * ~~~ new Vue({ directives:{ 指令名:配置对象 } }) ~~~ * ~~~ new Vue({ directives(){ 指令名:回调 } }) ~~~ * 全局指令: * ~~~ Vue.directive(指令名,配置对象) ~~~ * ~~~ Vue.directive(指令名,回调函数) ~~~ * 配置对象中的三个回调 * bind:指令与元素成功绑定时(一上来)调用 * inserted:指令所在元素被插入页面时调用 * updata:指令所在的模板被重新解析时调用 * 备注 * 指令定义时不加v-,但使用时要加v- * 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名 * 参考代码 * ```html Title ``` * ```html Title

    当前的n值是:

    放大10倍后的n值是:


    ``` ## 生命周期 ### 引出生命周期 * 又名:生命周期回调函数、生命周期函数、生命周期构子 * 是什么:Vue在关机时刻帮我们调用的一些特殊名称的函数 * 生命周期函数的名字不可以更改,但函数的具体内容是根据需求编写的 * 生命周期中的this指向的是vm或组件实例对象 * 参考代码 * ```html Title

    111

    ``` ### 生命周期总结 * 常用生命周期钩子 * mouted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作 * beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等 * 关于销毁Vue实例 * 销毁后借助Vue开发者工具看不到任何信息 * 销毁后自定义事件会失效,但原生Dom事件依然有效 * 一般不会再beforeDestroy操作数据,因为即使操作数据也不会触发更新流程了 * 参考代码 * ```html Title

    n的值为:{{n}}

    ``` **** # **Vue组件化编程** ## 非单文件组件 ### 基本使用 * Vue中使用组件的三大步骤 * 定义组件(创建组件) * 注册组件 * 使用组件(写组件标签) * 如何定义一个组件 * 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的options几乎一样,但也要些区别 * 区别如下 * el不要写,最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器 * data必须写成函数,避免组件被赋用时,素具存在引用关系 * 如何注册组件 * 局部注册:靠new Vue的时候窜如components选项 * 全局注册:靠Vue.components('组件名',组件) * 编写组件标签 * <组件名> * 参考代码 * ```html Title
    ``` ### 注意点 * 关于组件名: * 一个单词组成 * 第一种写法(首字母小写):school * 第二种写法(首字母大写):School * 多个单词组成 * 第一种写法(kebab-case命名):my-school * 第二种写法(CamelCase命名):MySchool(需要脚手架支持) * 备注 * 组件名劲量回避HTML中已有的元素,例如h2、H2都不行 * 可以使用name配置项指定组件在开发者工具中呈现的名字 * 关于组件标签 * 第一种写法: * 第二种写法: * 备注:不使用脚手架时会导致后续的组件无法渲染 * 一个简写方式: * const school = Vue.extend(options)可简写为: const school = options * 参考代码 * ```html Title
    ``` ### 组件的嵌套 * 参考代码 * ```html Title
    ``` ### VueComponent * 组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生产的 * 我们只需要写<组件名/>或<组件名>,Vue解析时会帮我们创建组件实例对象,即Vue帮我们执行new VueComponent(options) * 特别注意,每次调用extend时,Vue都会为我们创建一个全新的VueComponent * 关于this * 组件配置中: * data函数、methods函数、wath函数、computed函数、他们的this都是VueComponent实例对象 * new Vue(options)配置中: * data函数、methods函数、wath函数、computed函数、他们的this都是Vue实例对象 * VueComponent实例对象,以后简称vc(也可以称为组件实例对象) * Vue实例对象,以后简称vm * 参考代码 * ```html Title
    ``` ### 一个重要的内置关系 * 一个重要的内置关系:VueComponent.prototype.__ _proto_ _ _ === Vue.prototype * 为什么要有这个关系:让组件实例对象(VueComponent)能够访问到Vue原型对象上的属性、方法 ## 单文件组件 * Vue 的单文件组件 (即 *.vue 文件,英文 Single-File Component,简称 SFC) 是一种**特殊的文件格式,使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中**。 * 参考代码 * ```vue ``` * 外部文件导入 * 参考代码 * ```vue ``` **** # 使用Vue脚手架 ## 初始化脚手架 * 全局安装脚手架@vue/cil * ~~~ npm install -g @vue/cil ~~~ * **切换到需要创建项目的目录**,使用命令创建脚手架 * ~~~ cd 目录位置 ~~~ * ~~~ vue create xxx ~~~ * 启动项目 * ~~~ run npm serve ~~~ * 备注 * 如果下载慢,可以配置使用淘宝镜像 * ~~~ npm config set registy https://registry.npm.taobao.org ~~~ * 脚手架隐藏了所有webpack配置,若要查看具体的webpack配置,请执行 * ~~~vue vue inspect > output.js ~~~ ## VueCli文件解析 * .gitignore:git忽略文件,不需要上传git仓库的在这个文件里面写好 * babel.config.js:babel的配置文件 * babel:es6语法转es5语法 * babel的中文文档:https://babel.nodejs.cn/docs * package.json:包含了包名、常用短命令、包的版本 * serve:在本地启动项目 * build:生产版本,代码完成后执行的编译 * lint:代码检查(不常用) * package-lock.json:包含了包的版本信息、包的下载地址、包的node.js版本 * version:包的版本 * resolved:包的下载地址 * integrity:用来验证资源的完整性,即是否是我期望加载的资源,而不是被别人篡改了内容 * dependencies:当前包的生产依赖树 * devDependencies:当前包的生产依赖 * engines:node.js的版本 * readme.md:项目的介绍|教程 * **src**: * main.js:项目的主入口文件,在这里创建Vue实例对象 * render函数: * 在创建Vue实例的位置没有使用render函数+$mount进行挂着会导致报错 * ~~~ You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build. 翻译为: 您使用的是 Vue 的仅运行时构建,在该构建中模板编译器不可用。要么将模板预编译为render函数,要么使用包含编译器的构建。 ~~~ * 原因是导入的Vue.js不是完整版的Vue.js而是vue.runtime.esm * 使用es6语法引入Vue的方式只是引用了Vue的文件,具体引用了哪个Vue是靠Vue文件架下面的package包中module的来控制,默认dist/vue.runtime.esm.js * esm指的是在es6语法下默认的模块 * vue.runtime.esm.js默认没有模板解析器 * 完整版的VUE是vue目录下dist中的vue.js文件 * 只要render函数 * rander函数传参: * createElement:元素名、元素内容 * rander必须要有返回值 * rander简写: * render:函数名=>函数名(参数) * vue版本区别:node_modules下vue文件下dist文件 * vue.js与vue.runtime.xxx.js的区别 * vue.js是完整版本的Vue,包含:核心功能+模板解析器 * vue.runtime.xxx.js是运行版的Vue,只包含核心功能,不包含模板解析器 * 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容 * 只有在main.js中才使用rander函数 * App.vue:所有组件的父组件 * components:存放子组件的位置 * assets:存放静态资源的位置 * **public**: * favicon.ico:网页的图标位置 * index.html:项目的主文件,项目最终会运行在这个文件上 * ```html <%= htmlWebpackPlugin.options.title %>
    ``` * node_modules:第三方依赖包 * output.js:被脚手架隐藏的webpack配置项,里面包含了VueCli的webpack配置,在这个文件里面更并不奏效,这个文件只是输出出来给我们看的 * 使用vue inspect > output.js就可以查看vue脚手架默认配置 * vue脚手架中哪些文件不能更改: * public文件下的内容不能更改,但是可以被同名文件替换 * src文件名字不能更改 * main.js名字不能更改 * 对vue脚手架进行个性化定制:package同文件下创建vue.config.js * vue.config.js(可选择是否使用,如不使用则使用默认配置): * 配置项查询连接:https://cli.vuejs.org/zh/config/#vue-config-js * 使用的暴露方式: * ``` module.exports = defineConfig({ }) ``` * 参考代码: * main.js: * ``` /* * 该文件是整个项目的入口文件 * */ //引入Vue import Vue from 'vue' // 引入App组件,它是所有组件的父组件 import App from "@/App.vue"; // 关闭vue的开发者提示 Vue.config.productionTip = false // 创建Vue的实例对象 new Vue({ render: h => h(App), // render(createElement, hack) { // return createElement('h1', '你好啊') // } }).$mount('#app') ``` * App.vue: * ``` ``` * School: * ```vue ``` * Student: * ``` ``` * vue.config.js: * ``` const {defineConfig} = require('@vue/cli-service') module.exports = defineConfig({ //转es5语法时忽略node_modules transpileDependencies: true, // 停止代码检查 lintOnSave: false }) ``` ## ref属性 * 用来给元素或子组件注册引用信息(id的替代者) * 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc) * 使用方法: * 标识: * ~~~ <组件名字 ref="" /> ~~~ * ~~~

    ~~~ * 获取方式:this.$refs.xxx * 参考代码: * App.vue: * ``` ``` * School: * ``` ``` ## prope配置项 * 功能:让组件接受外部传过来的数据 * 传递数据: * 传递字符串方式 * ~~~ ~~~ * 传递其他类型 * ~~~ ~~~ * 接收数据: * 第一种接收方式(只接收): * ~~~ props:['name'] ~~~ * 第二种方式(限制类型): * ~~~ props:{ name:String } ~~~ * 第三种方式(限制类型、限制必要性、指定默认值) * ~~~ props:{ type:String,//类型 required:true,//必要性 default:'老王'//默认值 } ~~~ * 备注: * props是只读的,Vue底层会检测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data值的数据。 * 参考代码 * App.vue: * ``` ``` * School: * ``` ``` ## mixin(混入) * 功能:可以把多个组件的共用配置提取成一个混入对象 * 使用方式: * 第一步定义混合 * ~~~ { data(){…………}, methods:{}, …… } ~~~ * 第二步使用混入,例如: * 全局混入: * ~~~ Vue.mixin(xxx) ~~~ * 局部混入: * ~~~ mixin:[xxx] ~~~ * 参考代码: * main.js: * ~~~ /* * 该文件是整个项目的入口文件 * */ //引入Vue import Vue from 'vue' // 引入App组件,它是所有组件的父组件 import App from "@/App.vue"; // 导入混合文件并全局配置混合 import {mixin} from "../mixin"; Vue.mixin(mixin) // 关闭vue的开发者提示 Vue.config.productionTip = false // 创建Vue的实例对象 new Vue({ render: h => h(App), }).$mount('#app') ~~~ * School.vue * ~~~ ~~~ * mixin.js: * ~~~ export const mixin = { methods:{ showName() { alert(this.name) } } } ~~~ ## Vue插件 * 功能:用于增强Vue * 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据 * 定义插件: * ~~~ 对象.install = function(Vue,options){ //1.添加全局过滤器 Vue.filter(……) //2.添加全局指令 Vue.directive(……) //3.配置全局混入 Vue.mixin(……) //4.添加实例方法 Vue.prototype.$myHethod = function(){……} Vue.prototype.$myProperty = xxx } ~~~ * 使用插件: * ~~~ Vue.use(插件名字) ~~~ ## scoped样式 * 作用:让样式在局部生效,防止冲突 * 写法: * ~~~