vue3.0 简单笔记

// 项目初始化

转换网址: https://vue-next-template-explorer.netlify.app

// 安装cli

npm install -g @vue/cli

// 初始化vue

vue create vue-next-test

// 使用 vite 快速创建

npm init @vitejs/app hello-vue3 

*** 推荐使用 ·vite· vite 是vue3中专用! 打包加载更快

vue源码转换网址: https://vue-next-template-explorer.netlify.app

// watch 跟coumputed

    watch(() => count.value, 
      val => {
        console.log(`count is ${val}`)
      })

** 第一个参数是监听的值,count.value 表示当 count.value 发生变化就会触发监听器的回调函数,即第二个参数,第二个参数可以执行监听时候的回调

// getCurrentInstance 获取当前的路由

import  { getCurrentInstance } from 'vue'
export default {
    setup () {
        const {ctx} = getCurrentInstance()
        console.log(ctx.$router.currentRoute.value)
    }

// Vuex的集成

// 定义vuex
import  Vuex from 'vuex'
export default Vuex.ceeateStore({
    state: {
        test: {
            a: 1
        }
    },
    mutations: {
        // 添加了修改 state.test.a 状态的方法: setTestA
        setTestA(state, value) {
            state.test.a = value
        }
    },
    actions: {
    },
    modules: {
    }
})
// vuex引用


// 更新vuex的状态

更新 Vuex 状态仍然使用 commit 方法



// vue3.0优化点:
// diff方法的优化
DOM渲染时,仅更新变化的DOM
// hoistStatic 静态提升 和 cacheHandlers 事件侦听存储
    对于不更新的元素,只会创建一次!

Hello World!
{{msg}}
点击
/* vue2.0 */ export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createBlock(_Fragment, null, [ _createVNode("div", null, "Hello World!"), _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */), _createVNode("div", { onClick: $event => (_ctx.fn()) }, "点击", 8 /* PROPS */, ["onClick"]) ], 64 /* STABLE_FRAGMENT */)) } /* vue3.0 */ const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "Hello World!", -1 /* HOISTED */) export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createBlock(_Fragment, null, [ _hoisted_1, _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */), _createVNode("div", { onClick: _cache[1] || (_cache[1] = $event => (_ctx.fn())) }, "点击") ], 64 /* STABLE_FRAGMENT */)) } // 静态提升即: 将未变化的进行变量提升 `_hoisted_1`
    **附录:** PathFlags vue装换状态
export const enum PatchFlags {
    TEXT = 1, // 动态文本节点
    CLASS = 1 << 2, // 2 // 动态 class
    STYLE = 1 << 2, // 4 // 动态 style
    PROPS = 1 << 3, // 8 // 动态属性,但不包含类名和样式
    FULL_PROPS = 1 << 4, // 16 // 具有动态 key 属性,当 key 改变时,需要进行完整的 different 比较
    HYDRATE_EVEBNTS = 1 << 5, // 32 // 带有简体昂是案件
    STABLE_FRAGMENT = 1 << 6, // 64 // 一个不会改变子节点顺序的 fragment
    KEYED_FRAGMENT = 1 << 7, // 128 // 带有 key 属性的 fragment 或部分子节点带有 key
    UNKEYED_FRAGMENT = 1 << 8, // 256 // 子节点没有 key 的 fragment
    NEED_PATCH = 1 << 9, // 512 // 一个节点只会进行非 props 比较
    DYNAMIC_SLOTS = 1 << 10, // 1024 // 动态 slot
    HOISTED = -1, // 静态节点 
    BAIL = -2 // 指令在 diff 过程应该要退出优化模式
}

// Vite 项目管理

安装: `npm install -g create-vite-app`

创建: `create-vite-app projectName`

安装依赖运行项目:

        `cd projectName`

        `npm install`

        `npm run dev`

// 组合api

**`ref:`**  ref 函数系只能监听简单的类型数据的变化(单个值的)
  • *所有的变量和方法都需要通过 return 暴露出去,才能使用
// 引入:
import {ref} from 'vue'
export default {
    name: 'app',
    setup () {
        // 表示声明了一个 count 的变量,并赋值为 2
        let count = ref(2)
        return {ref}
    }
}

reactive: reactive 函数系能监听复杂的类型数据的变化(object, array)

import { reactive } from "vue";
export default {
  name: "App",
  // setup 是组合API的入口函数 setup 是在 beforecreate 钩子之前完成的
  setup() {
    // 定义一个 count 的变量
    let stuList = reactive({
      stus: [
        { age: 19, name: "小明", id: "s1" },
        { age: 16, name: "小憨憨", id: "s2" },
        { age: 18, name: "小涵", id: "s3" },
      ],
    });
    let addStu = reactive({
      newStu: {
        age: "",
        name: "",
        id: "",
      },
    });
    function del(id) {
      stuList.stus = stuList.stus.filter((ele) => ele.id !== id);
    }
    function add() {
      let obj = Object.assign({}, addStu.newStu);
      stuList.stus.push(obj);
      addStu.newStu.age = "";
      addStu.newStu.name = "";
      addStu.newStu.id = "";
    }
    // 组合API中定义的方法与变量都需要 return 暴露出去
    return { stuList, del, addStu, add };
  },
};

// Composition API 和 Option API

1、 Composition API 和 Option API 的混合使用

import {ref} from 'vue'
export default {
    // option  API
    name: "HelloWorld",
    props: {
        msg: String,
    },
    data() {
        return {
            count: 0,
        };
    },
    methods: {
        add() {
            count++;
        },
        // Composition API 中的方法与属性 相当于 在 option 中添加新的属性和 方法
        //  comit () {
        //      count ++  // Composition API 插入的
        //  }
        // 
    },
    setup () {
        // 表示声明了一个 count 的变量,并赋值为 2
        let count = ref(2)
        let function comit () {
            count ++ 
        }
        return {ref, comit}
    }
}      
2、 Composition API 的本质(组合API / 注入API)
    Composition api的本质是将其代码 注入到 Option API 中

// setup 函数

1、 setup 执行时机
     `setup`  函数的执行 是在  `beforecreate` 之前就已经完成 
2、 setup注意点
  • 由于在 setup 函数创建的时候 datamethods 还没创建,故而 无法使用; 因此 在 setup 函数中的 thisundefined
  • setup 函数不能包含异步函数

// reactive 函数

**` reactive:`** 

    **作用:**是vue3种提供实现响应式数据的方法;

    **原理:**在vue2中 响应数据是通过 `defineProperty` 来实现的,vue3是通过而是ES6中的 `Proxy` 来实现的;
  • 注意点 :

    • reactive 的参数传递 必须是一个对象(json / array)
    import { reactive } from "vue";
    export default {
      name: "App",
      // setup 是组合API的入口函数 setup 是在 beforecreate 钩子之前完成的
      setup() {
        let addStu = reactive({
          newStu: {
            age: "",
            name: "",
            id: "",
          },
        });
        return { addStu };
      },
    };
    
    • 如果给 reactive 传递了其他对象(指: 非 json 和 array 对象),此时,修改对象则 不更新,需要通过重新赋值的方式。
    import { reactive } from "vue";
    export default {
      name: "App",
      // setup 是组合API的入口函数 setup 是在 beforecreate 钩子之前完成的
      setup() {
        let state = reactive({
          time: new Date()
          },
          function comitFn () {
             // 获取时间    
             let newTime = new Date(state.time.getTime())
             //     
             newTime.setDate(state.time.getDate + 1)
             state.time = newTime
          }
        });
        return { state, comitFn };
      },
    };
    

// ref 函数

**`ref:`** 是veu3用于响应简单数据的方法;

**特点:** 是对原始数据进行复制 ,修改时并不修改原始数据
let per = {
      name: "ls",
      age: 12,
    };
    let data = ref(per);
    data.name = "ww";
    console.log(data, per);
    // data => RefImpl {_rawValue: {…}, _shallow: false, __v_isRef: true, _value: Proxy, name: "ww"}
    // per => {name: "ls", age: 12}
**本质:** `ref`  的底层仍是 `reactive` 系统会根据我们 `ref` 传入的值转换成 `ref(xx) => reactive({value: xx})`
  • 注意点:

    在vue中使用 ref 的值不用通过 value 获取;在 JS 中使用 ref 的值必须通过value获取

      即: 在DOM 中  ref 设置的值  不需要用value来获取, 但在修改时需要用valuel来进行设置
    
// 引入:
import {ref} from 'vue'
export default {
   name: 'app',
   setup () {
       // 表示声明了一个 count 的变量,并赋值为 2
       let count = ref(2)
       function change () {
           // 在DOM 中  ref 设置的值  不需要用value来获取, 但在修改时需要用valuel来进行设置
           count.value = 111
       }
       return {ref, count}
   }
}
// ref 和 reactive 的区别:
`ref` 在给DOM赋值时,是不需要添加 `.value` ;

`rective` 在给DOM赋值时,必须添加 `.value`

Vue中 是通过 __v_reftrue 则为 ref

// 判断 ref 和 reactive 的类型
**`ref:`**  isRef()
import {ref} from 'vue'
export default {
    name: 'app',
    setup () {
        // 表示声明了一个 count 的变量,并赋值为 2
        let count = ref(2)
        function change () {
            // 在DOM 中  ref 设置的值  不需要用value来获取, 但在修改时需要用valuel来进行设置
            count.value = 111
            console.log(isRef(count)) // => true
        }
        return {ref, count}
    }
}
**`reactive:`** isReactive()
import {reactive} from 'vue'
export default {
    name: 'app',
    setup () {
        // 表示声明了一个 count 的变量,并赋值为 2
        let count = reactive({
            num: 1
        })
        function change () {
            // 在DOM 中  ref 设置的值  不需要用value来获取, 但在修改时需要用valuel来进行设置
            count.num = 111
            console.log(isReactive(count)) // => true
        }
        return {ref, count}
    }
}

// 递归监听

**递归监听:** 监听所有层级的数据,并依层级 依次修改,断层则断层后的数据不变。

**非递归监听:** 仅监听第一层级的修改

默认情况下, refreactive 都是进行递归监听的

即是外到内依次监听





// 劣势
数据大时,损耗性能

    原由: 在vue3中总共的数据渲染是由 `Proxy`  对象

        [`Proxy:`](https://www.jianshu.com/p/8b0834b51183)

// 非递归监听

**特点:**

`reactive 由 shallowReactive 进行创建`   **只能监听第一层,不监听其它层**

`ref 由 shallowRef 进行创建` **`但 shallowRef 监听的是 .value ,因此需要修改时是修改其 .value 的值`**

`triggerRef 是修改某一个值的变化` 只有 `ref` 才有 `triggerRef` 的方法
state.value.gf.f.s.d = 4
triggerRef(state)




// shallowRef 的本质
`shallowRef` 是通过 `shallowReactive` 的方式进行创建的 故而 是 通过修改 value 的值才能修改

// toRaw 追踪数据(不改DOM)

特点: 是修改原始数据,但不更新 DOM
  • **toRaw: ** 用于获取 ref 中的数据的时候,由于其底层是通过 reactive 的方式来获取的,故而是需要通过 .value 的方式来获取

    let per = {
          name: "ls",
          age: 12,
        };
    let state = reactive(per);
    let data = ref(per);
    let per1 = toRaw(state);
    let per2 = toRaw(per1.value);
    

// markRaw 标记后永不追踪

let per = {
      name: "ls",
      age: 12,
    };
let per1 = markRaw(per);
let state = reactive(per);
state.name = 'ww'
console.log(per) // { name: "ls", age: 12, };
console.log(state) // 此时 state 追踪不到 per

// toRef

**特点:** 通过 `toRef`  修改的数据, 不能修改DOM, 但会修改原始引用数据; 跟 `ref` 一样都需要通过  `.value` 的形式来修改值
let per = {
      name: "ls",
      age: 12,
    };
let data = toRef(per, "name");
data.value = "xx";
console.log(data, per);
    // data => (_v_isRef: true;_key: "name";_object: {name: "xx", age: 12, __v_skip: true};value: (...);__proto__: Object)
    // per => {name: "xx", age: 12, __v_skip: true}

// toRefs

toRef 的升级版,可以修改多个属性

let per = {
      name: "ls",
      age: 12,
    };
let data = toRefs(per);
data.name.value = "xx";
data.name.age = 25;
console.log(data, per);
// data => name: xx age: 25
// per => {name: "xx", age: 12, __v_skip: true}

// customRef 自定义ref

**作用:** 由于 `setup`  函数无法使用异步函数,用于获取异步数据




// readonly、shallowReadonly、isReadonly

**readonly:  ** 只能用于读取不可修改 , 并且是递归只读

**shallowReadonly:**    非递归只读,只读第一层!

**isReadonly:** 返回 `boolean`  是只读返回 `true`
import { readonly, shallowReadonly, isReadonly  } from "vue";
setup() {
   let state1 = readonly({ name: "小樱", attr: { age: 18, id: "sw2" } });
    let state2 = shallowReadonly({
      name: "小瑛",
      attr: { age: 18, id: "sw2" },
    });
    state1.name = "小志";
    state1.attr.age = 17;
    console.log(state1); // Proxy {name: "小樱", attr: {…}} attr => age: 18
    state2.name = "小志";
    state2.attr.age = 17;
    console.log(state2); // Proxy {name: "小樱", attr: {…}} attr => age: 17
    console.log(isReadonly(state1), isReadonly(state2)); // true  true
}
// const 与 readonly 的区别
**相同点:** 

        都是不能修改值
报错: 
let a = readonly({ num: 2 });           
    const b = { num: 3 };
    a = {age: 2};
    b = {age: 2};
    console.log(a, b);
**不同点:**

    cosnt 的属性值可以被修改 readonly 的属性和值均不能修改
let a = readonly({ num: 2 });
    const b = { num: 3 };
    a.num = 0;
    b.num = 5;
    console.log(a, b); // a: Proxy {num: 2} b: {num: 5}
// 手写 shallowReactive 和 shallowRef
function shallowRef(val) {
  return shallowReactive({ value: val });
}
function shallowReactive(obj) {
  return new Proxy(obj, {
    get(obj, key) {
      return obj[key];
    },
    set(obj, key, val) {
      console.log(obj, key, val);
      return (obj[key] = val);
    },
  });
}
let obj = {
  a: "a",
  gf: {
    b: "b",
    f: {
      c: "c",
      s: {
        d: "d",
      },
    },
  },
};
let newObj = shallowReactive(obj);
let newObj1 = shallowRef(obj);
newObj.a = 1;
newObj.gf.b = 2;
newObj1.value = {
  a: 1,
  gf: {
    b: "2",
    f: {
      c: "c",
      s: {
        d: "d",
      },
    },
  },
};
console.log(newObj, newObj1);

// 手写 reactive ,ref

// reactive ref
function ref(val) {
  return reactive({ value: val });
}
function reactive(obj) {
  // 查找出所有的对象并调用 reactive 没找到继续遍历
  if (typeof obj === "object") {
    // 内层有数组
    if (obj instanceof Array) {
      obj.forEach((ele, i) => {
        if (typeof ele === "object") {
          obj[i] = reactive(ele);
        }
      });
    } else {
      for (let key in obj) {
        let ele = obj[key];
        if (typeof ele === "object") {
          obj[key] = reactive(ele);
        }
      }
    }
    return new Proxy(obj, {
      get(obj, key) {
        return obj[key];
      },
      set(obj, key, val) {
        console.log(obj, key, val);
        return (obj[key] = val);
      },
    });
  } else {
    console.warn(`${obj} is not object`);
  }
}
let obj = {
  a: "a",
  gf: {
    b: "b",
    f: {
      c: "c",
      s: {
        d: "d",
      },
    },
  },
};
let arr = [
  { id: "s1", name: "小樱" },
  {
    id: "s2",
    name: "小埋",
    attr: [{ nickName: "干物妹!", title: "不吃辣椒酱" }],
  },
];
let newObj = reactive(obj);
newObj.a = 1;
let newObj1 = ref(obj);
newObj1.value = {
  a: 2,
  gf: {
    b: 222,
    f: {
      c: "c",
      s: {
        d: "d",
      },
    },
  },
};
console.log(newObj, newObj1);
let newArr = reactive(arr);
arr[1].attr[0].title = "资深宅女";
console.log(newArr);

// 手写 isReactive / isRef

根据 `ref`  的赋值 `.value`  的特性进行判断


// 手写 Readonly / shallowReadonly

function ref(val) {
  return reactive({ value: val });
}
// 注释掉的加上是 readonly
function shallowReadonly(obj) {
  // 查找出所有的对象并调用 reactive 没找到继续遍历
  // if (typeof obj === "object") {
  //   // 内层有数组
  //   if (obj instanceof Array) {
  //     obj.forEach((ele, i) => {
  //       if (typeof ele === "object") {
  //         obj[i] = shallowReadonly(ele);
  //       }
  //     });
  //   } else {
  //     for (let key in obj) {
  //       let ele = obj[key];
  //       if (typeof ele === "object") {
  //         obj[key] = shallowReadonly(ele);
  //       }
  //     }
  //   }
  return new Proxy(obj, {
    get(obj, key) {
      return obj[key];
    },
    set(obj, key, val) {
      // console.log(obj, key, val);
      // return (obj[key] = val);
      return console.warn(`${obj} 仅支持只读,无法赋值`);
    },
  });
  // } else {
  //   console.warn(`${obj} is not object`);
  // }
}
let obj = {
  a: "a",
  gf: {
    b: "b",
    f: {
      c: "c",
      s: {
        d: "d",
      },
    },
  },
};
let newObj = shallowReadonly(obj);
newObj.gf.b = 1;
// newObj.a = 2; // => 仅支持只读,无法赋值
console.log(newObj);

// 手写 isReadonly

根据  `readonly`  中的不返回值的输出 `true`


你可能感兴趣的:(vue3.0 简单笔记)