参数:(对象名,key, 配置项)
直接添加
结论: 三个属性都可以遍历
借助 defineProperty
Object.defineProperty(person,'age',{
value:18
})
结果: age 颜色较浅。说明 age 属性不会参与遍历
Object.defineProperty(person,'age',{
value:18,
enumerable:true // 控制属性是否可以枚举。默认为false
})
虽然age可以遍历了。但是age属性不能修改值。需要再添加一个配置项:writable:true
控制属性是否可以修改。configurable:true
控制属性是否可以被删除
1、get方法
介绍:当有人读取 person 的 age 属性时,会触发调用get函数,其返回值就是访问到的 age 属性值
Object.defineProperty(person,'age',{
get:function(){
return 12
}
})
2、set方法
介绍:当修改person的age属性值,set函数就会被调用,且接收到要新修改的值
let number = 12
var person = {
name:'ss'
}
Object.defineProperty(person,'age',{
get(){
return number
},
set(newVal){
number = newVal
}
})
通过 Object.defineProperty的set和get方法 将 person的age属性和number变量做了双向关联
概念
数据代理:通过一个对象代理对另一个对象的读写操作
举例
let obj_a = {x:100}
let obj_b = {y:200}
// obj_a 对象代理对 obj_b 对象的操作
Object.defineProperty(obj_a,'y',{
get(){
return obj_b.y
},
set(newVal){
obj_b.y = newVal
}
})
Vue 中的数据代理模式:
视频地址:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通_哔哩哔哩_bilibili
简易模仿vue监测数据
function Observer(obj) {
const keys = Object.keys(obj)
keys.forEach((k)=>{
Object.definePropety(this,k,{
get() {
return obj[k]
},
set(newVal) {
// k 被改了,下一步解析模板,生成虚拟dom
obj[k] = newVal
}
})
})
}
let data = {
name:'',
address:''
}
const obs = new Observer(data);
let vm = {}
vm._data = data = obs
作用:后添加的属性,也能有响应式功能
注意:set() 方法仅可以向 data :{} 中的某一个子对象追加属性,而不能直接向 data 追加属性
// 方式一: 向data的子对象student添加sex属性并赋值
Vue.set(this.student,sex,'man')
// 方式二
this.$set(this.student,sex,'man')
默认 vue 是不会给 数组元素 添加 get和set方法的,所以是不会检测到元素的 改变
原型
每个函数function都有一个prototype,即显示原型属性
每个实例对象都有一个__proto__,即隐式原型属性
对象实例的隐式原型的值 == 对应构造函数的显示原型的值
函数的prototype属性:在定义函数时自动添加的。默认值是一个空Object对象
对象的__proto__属性:创建对象时自动添加的。默认值为构造函数的prototype属性值 其是显示原型的引用
B站视频尚硅谷JavaScript高级教程(javascript实战进阶)_哔哩哔哩_bilibili
可以直接操作 显示原型,但不能直接操作 隐式原型【es6之前】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WYZCgB3u-1653806579434)(imgs/image-20220121194652513.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IW6AfNLC-1653806579435)(imgs/image-20220121200510569.png)]
原型链 / 隐式原型链
访问一个对象的属性/方法流程优先级:
一个重要的内置关系:VueComponent.prototype._proto__ === Vue.prototype
const component1 = Vue.extend({})
new Vue({
})
console.log(component1.prototype._proto__ === Vue.prototype)// true
为什么要有这个关系?: 目的是让组件实例对象vc可以访问到Vue原型上的属性、方法。
minxin.js
局部混合
mixins:['xxx']
全局混合
Vue.mixin(xxx)
插件本质是一个对象,需要有 install 方法
功能:用于增强 Vue
编写插件
plugin.js
export default {
install(Vue){
...
}
}
引入插件
Vue.use()
main.js
import xx from xxx
Vue.use(xx)
常见应用:
cookie
在Http请求发送 set-cookie
HTTP头作为响应头一部分
cookie构成:通过 name=value 形式存储
失效时间:默认浏览器关闭失效(可自定义失效时间)
安全标志:设置安全标志后,只有是SSL连接才会发送到服务器
作用:主用于保存登录信息
存储大小:4KB否则被截掉 每个站点个数一般不超过20个
http通信:每次与服务端交互,都会携带在HTTP头。所以如果cookie臃肿会出现性能问题
sessionStorage
1)sessionStorage是Storage类型的一个对象,拥有clear(),getItem(name),key(index),removeItem(name),setItem(name,value)方法
2)sessionStorage对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭
3)将数据保存在session对象中。所谓session,是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。session对象可以用来保存在这段时间内所要求保存的任何数据
4)sessionStorage为临时保存
localStorage
1)localStorage也是Storage类型的一个对象
2)在HTML5中localStorage作为持久保存在客户端数据的方案取代了globalStorage(globalStorage必须指定域名)
3)localStorage会永久存储会话数据,除非removeItem,否则会话数据一直存在
4)将数据保存在客户端本地的硬件设备(通常指硬盘,也可以是其他硬件设备)中,即使浏览器被关闭了,该数据仍然存在,下次打开浏览器访问网站时仍然可以继续使用
5)localStorage为永久保存
存储空间
cookie 为4KB;LocalStrage和SessionStorage为5MB
相关API
仅支持存储字符串类型数据 【复杂类型需要使用JSON对象的Stringfy和parse进行转化处理】
作用域不同:
不同浏览器:无法共享localStorage和sessionStorage信息
相同浏览器-不同页面:仅可共享 localStorage [页面属于相同域名和端口]
安全性问题:
webStorage 不会随着 Http Header 发送到服务端,不会担心截获/伪造问题,所以安全性相对于cookie高一些
特点:浏览器关闭后,仍不消失
特点:关闭浏览器后,自动清除
操作API和LocalStorage相同
cookie、session、token的区别 - www.pu - 博客园 (cnblogs.com)
应用于:任意组件通信
消息订阅发布机制:可以运用在任意组件之间,忽略组件层级关系,只关心:消息发布&消息订阅
作用:方便组件之间传值和事件处理
npm install pubsub-js --save
import PubSub from 'pubsub-js'
//引入第三方库PubSub.subscribe('delete', function(msgName,data){ })
; //订阅PubSub.publish('delete', data)
//发布消息beforeDestroy
中取消订阅 PubSub.unsubscribe(this.pubId)
跨域
浏览器端 存在 同源策略(协议、域名、端口号必须完全一致)
特点:跨域仅存在于 浏览器端
代理服务器:使用webpack配置代理服务器
原理:本身服务就跑在一个开发服务器 webpack-dev-server, 这个server附带有一个 http-proxy-middleware, 该中间件支持我们将 浏览器请求 转换为 服务器向服务器的请求。
方式一:
module.exports = {
devServer:{
proxy:"http://localhost:5000"
}
}
方式二:
module.exports = {
devServer: {
proxy:{
'/api':{
target:"http://localhost:5000",
pathRewrite:{'^/api';''},
changeOrigin:true
/*
changeOrigin 设置为true,服务器收到请求头的host为 localhost:5000
changeOrigin 设置为false,host为localhost:8080
changeOrigin 默认为 true
*/
},
'/api2':{
target:"http://localhost:6000",
pathRewrite:{'^/api2';''}
}
}
}
}
反向代理:使用 nginx 开启一个代理服务器
原理:页面请求发送给nginx服务器,nginx根据配置路径动态匹配将要请求的服务器地址,最终的请求由nginx服务器发出解决跨域
尚硅谷Nginx教程由浅入深(一套打通丨初学者也可掌握)_哔哩哔哩_bilibili
跨域资源共享:服务端开启跨域资源共享,通过设置一个响应头告诉浏览器该请求允许跨域
hash
hash值不会包含到http请求中,即hash不会带给服务器
history
地址干净
项目部署上线后,刷新页面可能会出现404问题。
方式一:后端人员做路径分类出静态资源请求
方式二:使用Nginx做动静请求分离
nginx 各种应用场景
尚硅谷Nginx教程由浅入深(一套打通丨初学者也可掌握)_哔哩哔哩_bilibili
- 反向代理
- 负载均衡
- 动静分离
- 高可用配置
const router = new VueRouter({
mode: 'history',
routes:[{},{}]
})
时间:2020 9 发布
性能:快
、小
源码升级:
响应式
更好支持 TypeScript
新特性
需要检查 vue-cli 版本在 4.5.0 以上
# 查看版本
vue --Version
# 安装升级
npm install -g @vue/cli
# 创建工程
vue create xx
现阶段 vue脚手架 创建的工程,是仍然采用 webpack 做构建工具。
由于西 团队打造
新一代的前端构建工具
。之前是 webpack
vite 特点优势
可以使用 vite 直接创建工程。当然也会采用 vite做为构建工具
# 创建工程
npm init vite-app
# 安装依赖[即生成 node-modules 文件夹]
npm install
# 运行
npm run dev
创建的工程结构和 vue-cli 一样。区别在于没有采用 webpack 作为构建工具。
HubilderX 现在只提供 vite 项目模板
这里采用的是 vue3 + webpack + js
工厂函数直接调用即可创建对象,无需new创建对象
app比vue2中的vm更“轻”【即没有那么多属性、方法】
// 引入的不是 Vue构造函数;而是一个工厂函数
// 工厂函数特点是直接调用即可创建对象,无需new创建对象
import {createApp} from 'vue' // 引入 createApp 工厂函数
import App from './App.vue'
/* vue2写法
new Vue({
render:h=>h(App)
}).$mount('#app')
*/
// 创建应用实例对象app.app比vue2中的vm更“轻”【即没有那么多属性、方法】
const app = createApp(App)
app.mount('#app')// 挂载
...
...
vue2中,组件必须有一个根标签
vue3中,组件可以没有根标签,内部会将多个标签包含在一个 Fragment 虚拟元素中
Fragment 好处:减少内存占用
理解:Vue3 中一个新的配置项
,是一个函数
干什么:setup 是所有 compostion API 的表演舞台
怎么用:组件中用到的数据、方法
等,均要配置到setup
中
vue3 向下兼容,所以 data、method 目前均仍可使用 【但开发中不建议出现任何vue2的代码】
export default {
name:'',
// 新的配置项
setup(){
// 1、对象
let name = 'zzl'
// 2、方法
function sayHello(){}
// 3、返回【所有需要响应式的数据/方法都需要return出去】
return {name,sayHello}
}
}
setup函数有两种返回值
注意
作用:定义一个响应式的数据
1、语法:const name = ref('zzl')
:创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
2、js操作数据[需要value]:JS 中操作响应式数据 name.value
3、界面渲染数据[不要value]:从模板中读取数据,不需要value,直接{{name}}
4、接受类型:基本数据类型、对象类型
Object.defineProperty()
的 get 和 set 方法完成的 [即同Vue2]reactive
函数 [vue3]作用:定义一个对象类型的响应式数据(基本类型使用ref函数)
1、语法:const proxy代理对象 = reactive(源对象)
接受一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
2、操作 和 渲染 数据,都不需要 .value
3、reactive 定义的响应式数据是 ”深层次的“
底层:内部基于 ES6 的 Proxy 实现,通过代理对象proxy,操作元对象内部数据进行操作
1、toRef 函数
我没打算将整个对象交给响应式,我只需要name属性做响应式
作用:创建一个 ref 对象
,其 value 值指向另一个对象中的某个属性
语法:const name = toRef(person,'name')
// 一个 ref 对象name 指向 person的name属性
应用:将响应式对象中的某个属性单独提供给外部使用, template中可以不用 {{person.name}}
,换成 {{name}}
2、toRefs 函数
作用:toRefs
可以批量将一个 reactive对象
转变为多个 ref对象
,语法toRefs(person)
应用:const person_refs = toRefs(person)
// 一个对象,内部包含多个 ref对象 属性
3、常见编码形式
{{show}}
{{companys}}
{{user}}
{{tmp}}
实现原理:
对象类型:通过 Object.defineProperty()
对属性的读取,修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法
来实现拦截,(对数组的变更方法进行了包裹)
存在问题:
上述两个问题,vue2都给了解决方案
实现原理:
Proxy 代理
:拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、删除等Reflect 反射
:对源对象的属性进行操作// proxy 代理
new Proxy(data,{
// 拦截读取属性
get(target,prop) {
return Reflect.get(target,prop)// 读取源对象
},
// 拦截设置属性或添加新属性
set(target,prop,value) {
return Reflect.set(target,prop,value)// 操作源对象
},
// 拦截删除属性
deleteProperty(target,prop) {
return Reflect.deleteProperty(target,prop)// 操作源对象
}
})
开发中大量使用 reactive,基本不使用 ref。
开发中会用一个 大对象 将用到的基本数据类型的数据包裹起来,使用 reactive。即
对象嵌套
1、setup 执行时机:在 beforeCreate 之前执行一次
2、this: setup 中的 this 是 undefined
3、setup 的参数:
import {computed} from 'vue'
setup() {
// 简写【单向】
person.fullName = computed((=>{
return Person.firstName + '-' + person.lastName
}))
// 完整【双向】
person.fullName = computed({
get(){
return Person.firstName + '-' + person.lastName
},
set(value) {
const nameArr = value.split('-')
Person.firstName = nameArr[0]
Person.lastName = nameArr[1]
}
})
}
import {watch} from 'vue'
setup() {
let sum = ref(0)
// 监视 ref 所定义的一个响应式数据 sum
watch(sum,(newVal,oldVal)=>{
...
})
// 监视多个 ref 所定义的数据 sum msg
watch([sum,msg],(newVal,oldVal)=>{
... sum或msg变化了
})
// 监视 reactive 定义的数据 person. 这里不能拿到oldvalue
// 默认强制开启了深度监视(deep配置无效)
watch(person,(newVal)=>{ })
// 常用----------------------------------------
// 监视 reactive定义的一个响应式数据中的 某个属性!! 【用的多一点】
watch(()=>person.name,(newVal,oldVal)=>{})
// 常用----------------------------------------
// 监视多个属性!!
watch([()=>person.age,()=>person.name],(newVal,oldVal)=>{ })
// 监视 reactive定义的对象中的 某个对象属性[这里默认不开启深度监视]
watch(()=>person.job,(newVal)=>{ },{deep:true})
}
let person = ref({
name:
age:
})
//方式一 监视 ref 定义的对象的属性变化 [默认强制开启deep]
watch(person.value,(newVal,oldVal)={})
// 方式二:需要手动开启深度监视
watch(person,(newVal,oldVal)=>{},{deep:true})
watch: 既要指明监视的属性,也要指明监视的回调函数
watchEffect: 仅仅需要指明回调函数,回调中用到哪些属性,就监视哪些属性
watchEffect 有点像 computed,都是有点监视数据变化的作用。但
- computed 注重对是计算出来的值,即必须要写返回值
- watchEffect 注重的是逻辑处理过程,即不需要返回值
import {watchEffect} from 'vue'
watchEffect(()=>{
const myname = Person.name // 使用了Person.name
})
本质是一个函数,把 setup 函数中使用的 compositionAPI 进行了封装
1、类似于 vue2 中的 mixin
2、目的:复用代码,分离功能代码,提高维护度
甚至,日后大型项目,可以单独独立出一个hooks文件夹,编写各种业务js文件。开发中可以引入共享
setup() {
// 拿到响应式数据
const person_data = usePerson() // 需要定义一个变量,接受一下响应式数据
const company_data = useCompany()
// 返回
return {
person_data,
company_data
}
}
// 独立出 person 业务模块
function usePerson() {
// 定义
const person = reactive({
name:'',
age:
})
// 返回
return person
}
// 独立出 company 业务模块
function useCompany() {
// 定义
const company = reactive(()=>{
name:'',
address:''
})
// 返回
return company
}
options API -> VUE2
composition API -> VUE3
把某个HTML代码领出来,类似 模态框 的效果
<Teleport to="body">
Teleport>
v-on.native
修饰符,需要在子组件中使用 emits
配置项声明自定义事件名移除掉了 filter
过滤器,建议使用 computed
或 method
去实现过滤器
每次 npm run build
手动将 dist
文件夹传到 server
,再配置 nginx
使用 github actions
实现 ci/cd
过程
Github Actions:
作用:可以让我们在 giuhub 仓库中 创建 自定义的软件开发生命周期工作流程
【全网首发】Vue3.0光速上手「持续更新中」_哔哩哔哩_bilibili
1、配置 workflow
下面配置,在我们 push 代码后,github会自动打包我们应用进行部署
需要在项目根目录创建层级目录 .github/workflows/publish.yml
name: 任务打包应用上传服务器
on:
push:
branches:
- master
#任务详情
jobs:
build:
# 指定自动打包时运行的虚拟机环境
runs-on: ubuntu-latest
#步骤
steps:
- name: 迁出源码到虚拟机
uses: actions/checkout@master
- name: 安装node
uses: actions/setup-node@v1
with:
node-version:14.0.0
- name: 安装依赖
run: npm run build
- name: 打包项目
run: npm run build
- name: 上传到 server
uses: easingthemes/ssh-[email protected]
env:
#私钥[让虚拟机模拟自己机器和server连接]
SSH_PRIVATE_KEY:
${{secrets.PRIVATE_KEY}}
#scp参数
ARGS:"-avzr --delete"
#源目录
SOURCE:"dist"
#服务器IP
REMOTE_HOST:""
#用户
REMOTE_USER:"root"
#server目标目录地址
TARGET:"/root/xxx"
**3、**查看发布过程
4、在 server 配置 NGINX
进入 nginx 安装目录下
配置 nginx.conf 文件,将配置内容分割出去
server {
# 项目端口
listen 8080;
# 服务器IP
server_name 47.58.365.36;
location / {
# 项目打包后的文件夹
root /root/vue-in-action/dist/;
# 默认入口文件
index index.html index.htm;
}
}
重启NGINX,生效配置
# 重启nginx
nginx -s reload
5、浏览器查看网站