vue点滴yan

Vue router-link 对比a标签
Vue 中,为什么不能用 index 作为 key?
react/vue用index作为key可能会引发的问题
打印:

vue3和vue2对比
vue通信方式
全面总结 Vue 3.0 的新特性
vue计算属性和watch属性
computed和watch的区别是什么?
组件中 data 为什么是一个函数?
$nextTick 用法与原理
导航解析流程
keep-alive
Vue中的路由

服务端渲染
proxy api都可以做啥
vue3 diff和vue2 diff有啥区别

[vue常用的考点]

2022最新前端vue面试题
Vue学习之从入门到神经(两万字收藏篇)
vue面试题整理(2022-持续更新中…)
2022Vue经典面试题及答案汇总(持续更新)
2021年Vue最常见的面试题以及答案(面试必过)
【面试题】2021最新Vue面试题汇总

vue通信方式
浅析我们为什么要上Vue3?
vue3和vue2对比

------Vue2不好的地方
对TypeScript支持不友好(所有属性都放在了this对象上,难以推倒组件的数据类型)
大量的API挂载在Vue对象的原型上,难以实现TreeShaking。
架构层面对跨平台dom渲染开发支持不友好
CompositionAPI。受ReactHook启发
更方便的支持了 jsx
Vue 3 的 Template 支持多个根标签,Vue 2 不支持
对虚拟DOM进行了重写、对模板的编译进行了优化操作...
------Vue3 api
1.更强的性能,更好的 tree shaking
2. Composition API + setup
3. 更好地支持 TypeScript
------Vue3  性能方面提升
1. 编译阶段。对 diff 算法优化、静态提升等等
2. 响应式系统。Proxy()替代Object.defineProperty()监听对象。监听一个对象,不需要再深度遍历,Proxy()就可以劫持整个对象
3. 体积包减少。Compostion API 的写法,可以更好的进行 tree shaking,减少上下文没有引入的代码,减少打包后的文件体积
4. 新增片段特性。Vue 文件的<template>标签内,不再需要强制声明一个的<div>标签,节省额外的节点开销

v-cloak 防止抖动
@Prop() 后边的!后对进行非空断言

https://www.leevii.com/2018/10/what-does-the-exclamation-point-behind-the-ts-attribute-mean.html

v-model也可以和.lazy、.trim和.number这些修饰符一起使用
provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
打印打印打印打印
具名插槽和作用域插槽(就是把vue的子元素的属性给父使用)
// 爸爸
<YanSlotSon>
   <template v-slot:header="context">
       fffffff
       {{context.aaa}}
   </template>
</YanSlotSon>
// 儿子
<template>
    <div>
        <slot name="header" :aaa="'kkkkk'"></slot>
    </div>
</template>
通信方式
Prop(常用)包含方法通过props传递
$emit (组件封装用的较多)
.sync语法糖 (较少)
$attrs & $listeners (组件封装用的较多)
provide & inject (高阶组件/组件库用的较多)
slot-scope & v-slot (vue@2.6.0+)新增
v-model 与 value 和 input一样
<YanSyncSon :value="parentinfo" @input="data => (this.parentinfo = data) "></YanSyncSon>
<YanSyncSon v-model="parentinfo"></YanSyncSon>
.sync语法糖
<YanSyncSon :value="parentinfo" @update:value="data => (this.parentinfo = data) "></YanSyncSon>
 <YanSyncSon :value.sync="parentinfo"></YanSyncSon>
form组件
// 使用 
<k-form :model="model" :rules="rules" ref="loginForm">
      <k-form-item label="用户名" prop="username">
        <k-input v-model="model.username" autocomplete="off" placeholder="输入用户名"></k-input>
      </k-form-item>
      <k-form-item label="确认密码" prop="password">
        <k-input type="password" v-model="model.password" autocomplete="off"></k-input>
      </k-form-item>
      <k-form-item>
        <button @click="submitForm('loginForm')">提交</button>
      </k-form-item>
    </k-form>
    
submitForm(form) {
  this.$refs[form].validate(valid => {
    const notice = this.$create(Notice, {
      title: "社会你杨哥喊你来搬砖",
      message: valid ? "请求登录!" : "校验失败!",
      duration: 1000
    });
    notice.show();
  });
}
// form 的
<template>
  <div>
    <slot></slot>
  </div>
</template>
<script>
export default {
  provide() {
    return {
      form: this
    };
  },
  props: {
    model: {
      type: Object,
      required: true
    },
    rules: {
      type: Object
    }
  },
  methods: {
    validate(cb) {
      const tasks = this.$children
        .filter(item => item.prop)
        .map(item => item.validate());

      // 所有任务都通过才算校验通过
      Promise.all(tasks)
        .then(() => cb(true))
        .catch(() => cb(false));
    }
  }
};
</script>
// form-item
<template>
  <div>
    <label v-if="label">{{label}}</label>
    <slot></slot>
    <p v-if="errorMessage">{{errorMessage}}</p>
  </div>
</template>

<script>
import Schema from 'async-validator'
export default {
  inject: ["form"],
  props: {
    label: {
      type: String,
      default: ""
    },
    prop: {
      type: String
    }
  },
  data() {
    return {
      errorMessage: ""
    };
  },
  mounted() {
      this.$on('validate', this.validate)
  },
  methods: {
      validate() {
          // 做校验
          const value = this.form.model[this.prop]
          const rules = this.form.rules[this.prop]
          // npm i async-validator -S
          const desc = {[this.prop]: rules};
          const schema = new Schema(desc);
          // return的是校验结果的Promise
          return schema.validate({[this.prop]: value}, errors => {
              if (errors) {
                  this.errorMessage = errors[0].message;
              }else {
                  this.errorMessage = ''
              }
          })
      }
  },
};
</script>
// input
<template>
  <div>
    <input :value="value" @input="onInput" v-bind="$attrs">
  </div>
</template>

<script>
export default {
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      default: ""
    }
  },
  methods: {
    onInput(e) {
      this.$emit("input", e.target.value);

      this.$parent.$emit('validate');
    }
  }
};
</script>
tree
<template>
  <li>
    <div @click="toggle">
      {{model.title}}
      <span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
    </div>
    <ul v-show="open" v-if="isFolder">
      <item class="item" v-for="model in model.children" :model="model" :key="model.title"></item>
    </ul>
  </li>
</template>

<script>
export default {
  name: "Item",
  props: {
    model: {
      type: Object,
      required: true
    }
  },
弹窗组件的使用
const notice = this.$create(Notice, {
   title: "社会你杨哥喊你来搬砖",
   message: valid ? "请求登录!" : "校验失败!",
   duration: 1000
 });
 
export default function create(Component, props) {
    // 先创建实例
    const vm = new Vue({
        render(h) {
            // h就是createElement,它返回VNode
            return h(Component, {props})
        }
    }).$mount();

    // 手动挂载
    document.body.appendChild(vm.$el);

    // 销毁方法
    const comp = vm.$children[0]; // 这个就是Notice组件
    comp.remove = function() {
        document.body.removeChild(vm.$el);
        vm.$destroy();
    }
    return comp;
}
vuex
dispatch 对应 commit
Actions 对应 mutations
// 页面中使用store
computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}
// 使用kstore.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: { count: 0 },
  mutations: {
    increment(state, n = 1) {
      state.count += n;
    }
  },
  getters: {
    score(state) {
      return `共扔出:${state.count}`
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit("increment", 2);
      }, 1000);
    }
  }
});
// ======== kvuex
let Vue;

class Store {
  constructor(options) {
    this.state = new Vue({
      data: options.state
    });

    this.mutations = options.mutations;
    this.actions = options.actions;

    options.getters && this.handleGetters(options.getters)
  }

  // 声明为箭头函数,why?
  commit = (type, arg) => {
    this.mutations[type](this.state, arg);
  };

  dispatch(type, arg) {
    this.actions[type]({
      commit: this.commit,
      state: this.state
    }, arg);
  }

  handleGetters(getters) {
    this.getters = {};
    // 遍历getters所有key
    Object.keys(getters).forEach(key => {
        // 为this.getters定义若干属性,这些属性是只读的
        // $store.getters.score
        Object.defineProperty(this.getters, key, {
            get: () => {
                return getters[key](this.state);
            }
        })
    })
  }
}

function install(_Vue) {
  Vue = _Vue;

  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    }
  });
}

export default { Store, install };

krouter.js
import Home from "./views/Home";
import About from "./views/About";
import Vue from "vue";

class VueRouter {
  constructor(options) {
    this.$options = options;
    this.routeMap = {};

    // 路由响应式
    this.app = new Vue({
      data: {
        current: "/"
      }
    });
  }

  init() {
    this.bindEvents(); //监听url变化
    this.createRouteMap(this.$options); //解析路由配置
    this.initComponent(); // 实现两个组件
  }

  bindEvents() {
    window.addEventListener("load", this.onHashChange.bind(this));
    window.addEventListener("hashchange", this.onHashChange.bind(this));
  }
  onHashChange() {
    this.app.current = window.location.hash.slice(1) || "/";
  }
  createRouteMap(options) {
    options.routes.forEach(item => {
      this.routeMap[item.path] = item.component;
    });
  }
  initComponent() {
    // router-link,router-view
    // <router-link to="">fff</router-link>
    Vue.component("router-link", {
      props: { to: String },
      render(h) {
        // h(tag, data, children)
        return h("a", { attrs: { href: "#" + this.to } }, [
          this.$slots.default
        ]);
      }
    });

    // <router-view></router-view>
    Vue.component("router-view", {
      render: h => {
        console.log(this.routeMap[this.app.current]);
        const comp = this.routeMap[this.app.current];
        return h(comp);
      }
    });
  }
}
VueRouter.install = function(Vue) {
  // 混入
  Vue.mixin({
    beforeCreate() {
      // this是Vue实例
      if (this.$options.router) {
        // 仅在根组件执行一次
        Vue.prototype.$router = this.$options.router;
        this.$options.router.init();
      }
    }
  });
};

Vue.use(VueRouter);

export default new VueRouter({
  routes: [{ path: "/", component: Home }, { path: "/about", component: About }]
});

vue计算属性和watch属性

导航解析流程
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子
v-pre

不会解析直接输出

常用的标签
v-for /v-bind(😃 /v-if/ v-show/ v-else-if /v-else/ v-model / v-on(@) / v-text / v-html / v-once /
v-prev / v-cloak

vue指令v-if和v-show的区别

原理 2. 性能 3. 场景

computed和watch的区别是什么?

computed 一对多, 多次调用时,会把第一次调用的结果放入缓存,节约性能
定义的函数必须要写 return,不然会报错
调用的时候不能加括号,不然会报错
在computed中定义一个函数(看起来是一个函数,其实是一个属性)
watch 多对一 只监听,不会产生新的函数名,watch也可以渲染数据,但是和computed比较就比较复杂。

组件中 data 为什么是一个函数?

组件上的data是函数的情况下,组件每次调用data里面的数据,都是由data这个独有的函数返回过来的数据,
所以不会造成这个组件更改data的数据,另一个在使用这个数据的组件也会更改这个数据

$nextTick 用法与原理
在数据变化后要执行某个回调函数,而这个操作需要使用随数据改变而改变的DOM结构的时候, 这个操作都应该放进Vue.nextTick () 回调函数中。
在Vue 内部尝试对异步队列使用原生的promise.then 和 MessageChange,如果执行环境不支持, 会采用setTime(()=> {} , 0)代替。
Vue - v-for 中为什么不能用 index 作为 key
Vue中 keep-alive 详解
Vue中的路由
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值