组件的认识:
- 组件是可复用的
- 把组件当做一种标签使用 使用一次 它内部的代码就会完整的执行一次
- 类比函数 使用组件就相当于调用函数 实参就相当于组件的属性传值
- 不用把数据全部放在数据源中,会变化更新或网络请求的数据才放在data中,固定的数据直接写在模板标签中
关于项目的资源打包问题:
热更新服务:将打包后的静态项目在内存中托管起来
项目中的本地资源打包时:
- 引用文件的资源(import)、标签中引入的资源(img-src)会启用loder去加载资源 会被webpack打包
- 放在data数据源中的网址对应的资源(如把图片等本地资源的路径放在data中) webpack不会读取data 所以webpack不打包
- data数据源中的图片应该放网络图片
编辑器写代码有波浪线
v-for:不写key会有警告
解决:绑定一个key 如果没有id就绑定for循环的下标 或者忽略不管没影响
标签的其他地方 命令窗口报错
解决:关闭webpack中配置的eslint的严格检测模式:lintOnSave:false
v-slot:插槽名 是具名插槽的用法
#s1 是插槽的语法糖
没有指定插槽名就是默认插入到插槽,不给插槽插入数据的话,就会使用组件的slot中的数据
插槽名不用使用引号引起来,直接写变量名
插入的内容必须是template标签或者组件 不能是原生的元素eg:
设计组件里面:
- 默认槽位:< slot> < /slot>
- 具名槽位:< slot name="s1"> < /slot>
使用组件时:
< 组件名> 尖括号中的东西插入默认槽位 < /组件名>
< 组件名>
< template v-slot:s1>插入内容必须放在这个标签中,老版本不用< template>
< template #s1>插入内容必须放在这个标签中,老版本不用< template>
< /组件名>
App.vue文件:
Box1.vue文件:
{{title}}
{{msg}}
结果显示:
父组件使用子组件时要在子组件中插入内容 在子组件中就要用插槽来装 否则不会显示出来
插槽的位置在哪 插入的内容就在哪
App.vue文件:
app组件的插槽数据
6666
Box2.vue文件:
{{title}}
{{msg}}
Box3.vue文件:
box3
结果显示:
App.vue文件:
111111
2222
222222
111111
222222
111111
Box4
222222
111111
Box4.vue文件:
{{title}}
不传数据到s2插槽中 就会默认显示这段文本出来
结果显示:
如:
事件源target:box组件
事件类型type:myevent
使用组件时 绑定监听器,内部触发事件时 监听器就会调用
如:点我
App.vue文件:
结果显示:
绑定事件:
- Box组件是事件源
- myevent是Box组件绑定的事件类型
- fn是Box组件上面绑定的监听器
事件设计:
在Box组件内部,可以在想要的条件下去触发事件以下代码放在想触发自定义事件的地方
this.$emit("myevent","要给触发的事件的函数传入的参数")
App.vue文件:
Box.vue文件:
{{count}}
结果显示:
App.vue文件:
Box2.vue文件:
结果显示:
给事件绑定事件修饰符 .native
点我 //事件名必须是系统存在的事件
App.vue文件:
Box3.vue文件:
box3
结果显示:
配置代理(解决跨域问题):vue的8080服务器请求egg的7001服务器
vue.config.js中:
devServer: {
//代理配置,这里只是配置,不用写代理服务器的代码(配置好了它帮我们实现)
// proxy: {
// '/xxxx': 'http://localhost:7001',
// },
proxy: {
'/xxxx': {
target: 'http://ip:7001',
secure: true, //如果代理的target是https接口,需要配置它
pathRewrite: {
'^/xxxx': '/'
}, //请求时重写pathname
//如果项目中实际请求的是:http://ip:8080/xxxx/ajax1
//8080服务器就会帮我们代理 请求:http://ip:7001/ajax1
},
},
}
App.vue文件:
{{obj.title}}
{{obj.info}}
结果显示:
main.js中:
在组件的原型链上配置axios工具,并配置公共网址:
import axios from "axios"
Vue.prototype.$axios=axios
axios.defaults.baseURL="http://ip:8001/xxxx"
//配置公共url 如果这个axios去请求 ajax1 实际网址是:http://ip:8001/xxxx/ajax1
//做网络请求都是基于baseURL
//代理去请求:http://ip:7001/ajax1
App.vue文件:
{{obj.title}}
{{obj.info}}
显示结果同上
1.组件被复用时,data数据源才不会被共用 设计成对象就会被共用 调函数调一次生成一次
2.函数的设计就像懒加载一样 当组件使用时,数据源的对象才会创建 这样设计性能更好
this组件对象有很多属性和方法 都是劫持“别人”的:如 data methods props
给this设置成员(初始化)的顺序:属性props>方法methods>数据源data>计算属性computed>对属性监听watch
数据由 根组件-->父组件-->子组件 ,单向修改,不能反向修改
父组件通过属性传值给子组件,子组件内部修改数据,父组件的数据不改变;父组件修改数据,会重新传值给子组件,子组件的数据更新改变
即:
- 在父传子的前提下,父组件的数据发生会通知子组件自动更新
- 子组件内部,不能直接修改父组件传递过来的props => props是只读的
每一个组件在加载时都会调用vue内部的render函数把这个组件的template选项的模板解析为一个js对象,这个对象和DOM节点对象“长得一模一样”,就是为了后面的渲染。调render生成虚拟模板VNode.
然后是数据劫持代理监听等等:
底层设计:发布着/订阅者设计 其实就是写了一个watcher函数去订阅(监听)数据的改变(底层js语法就是Obj.defineproperty,vue3是proxy)
当数据变化以后:
当数据变更的时候,重新构造一颗新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树的差异。当第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图更新。(DIFF算法)
比较的过程是 一层一层的比较 父组件和父组件比较 并不会把父组件和子组件比较 同层级时 从两边到中间
比较的过程中 发现差异(组件/标签类型,文本,属性值。注释等) 就会异步地给DOM打补丁(操作页面)
什么是DIFF?
用JavaScript对象结构表示DOM树的结构,然后用这个树构建一个真正的DOM树,插到文档中
当状态变更的时候,重新构建一颗新的对象树。然后用新的树和就的树进行比较(diff),记录两棵树的差异
当第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图更新。
DIFF算法的过程
当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
通过sameVnode进行判断,相同则调用patchVnode方法
patchVnode做了以下操作:
找到对应的真实dom,称为el
如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
如果oldVnode有子节点而VNode没有,则删除el子节点
如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点
updateChildren主要做了以下操作:
设置新旧VNode的头尾指针
新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作
1.引入外部写的Sass编译后的css文件
2.配置sass的加载器
在里面写scss代码