当前位置:   article > 正文

Vue知识点汇总学习_vue学习资料

vue学习资料

一、知识点汇总

1.vue原理

在这里插入图片描述
1、建立虚拟DOM Tree,通过document.createDocumentFragment(),遍历指定根节点内部节点,根据{{ prop }}、v-model等规则进行compile(编译);
2、通过ES5 Object.defineProperty()进行数据变化拦截;
3、截取到的数据变化,通过发布者-订阅者模式,触发Watcher,从而改变虚拟DOM中的具体数据;
4、通过改变虚拟DOM元素值,从而改变最后渲染dom树的值,完成双向绑定

完成数据的双向绑定在于Object.defineProperty()

2.Vue 修饰符有哪些

1.事件修饰符

.stop 阻止事件继续传播
.prevent 阻止标签默认行为
.capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理
.self 只当在 event.target 是当前元素自身时触发处理函数
.once 事件将只会触发一次
.passive 告诉浏览器你不想阻止事件的默认行为
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.v-model 的修饰符

lazy 通过这个修饰符,转变为在 change 事件再同步
number 自动将用户的输入值转化为数值类型
trim 自动过滤用户输入的首尾空格
  • 1
  • 2
  • 3

3.键盘事件的修饰符

.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.系统修饰键

.ctrl
.alt
.shift
.meta
  • 1
  • 2
  • 3
  • 4

5.鼠标按钮修饰符

.left
.right
.middle
  • 1
  • 2
  • 3

3.Vue 模板编译原理

Vue 的编译过程就是将 template 转化为 render 函数的过程 分为以下三步

第一步是将 模板字符串 转换成 element ASTs(解析器)
第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)

export function compileToFunctions(template) {
  // 我们需要把html字符串变成render函数
  // 1.把html代码转成ast语法树  ast用来描述代码本身形成树结构 不仅可以描述html 也能描述css以及js语法
  // 很多库都运用到了ast 比如 webpack babel eslint等等
  let ast = parse(template);
  // 2.优化静态节点
  // 这个有兴趣的可以去看源码  不影响核心功能就不实现了
  //   if (options.optimize !== false) {
  //     optimize(ast, options);
  //   }

  // 3.通过ast 重新生成代码
  // 我们最后生成的代码需要和render函数一样
  // 类似_c('div',{id:"app"},_c('div',undefined,_v("hello"+_s(name)),_c('span',undefined,_v("world"))))
  // _c代表创建元素 _v代表创建文本 _s代表文Json.stringify--把对象解析成文本
  let code = generate(ast);
  //   使用with语法改变作用域为this  之后调用render函数可以使用call改变this 方便code里面的变量取值
  let renderFn = new Function(`with(this){return ${code}}`);
  return renderFn;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4.自定义指令, 原理

指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素增加自定义功能。vue 编译 DOM 时,会找到指令对象,执行指令的相关方法。

自定义指令有五个生命周期(也叫钩子函数),分别是 bind、inserted、update、componentUpdated、unbind

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
unbind:只调用一次,指令与元素解绑时调用。
  • 1
  • 2
  • 3
  • 4
  • 5

原理
1.在生成 ast 语法树时,遇到指令会给当前元素添加 directives 属性
2.通过 genDirectives 生成指令代码
3.在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子
4.当执行指令对应钩子函数时,调用对应指令定义的方法

5.Vue.mixin 的使用场景和原理

在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立,可以通过 Vue 的 mixin功能抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

6.keep-alive 使用场景和原理

keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

  • 常用的两个属性 include/exclude,允许组件有条件的进行缓存。
  • 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。
  • keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。

*补充:LRU 的核心思想是如果数据最近被访问过,那么将来被访问的几率也更高,所以我们将命中缓存的组件 key 重新插入到 this.keys 的尾部,这样一来,this.keys 中越往头部的数据即将来被访问几率越低,所以当缓存数量达到最大值时,我们就删除将来被访问几率最低的数据,即 this.keys 中第一个缓存的组件。

7.Vue.set 方法原理

Vue 响应式原理 在两种情况下修改数据 Vue 是不会触发视图更新的

  • 在实例创建之后添加新的属性到实例上(给响应式对象新增属性)
  • 直接更改数组下标来修改数组的值

Vue.set 或者说是$set 原理如下
因为响应式数据 我们给对象和数组本身都增加了__ob__属性,代表的是 Observer 实例。当给对象新增不存在的属性 首先会把新的属性进行响应式跟踪 然后会触发对象__ob__的 dep 收集到的 watcher 去更新,当修改数组索引时我们调用数组本身的 splice 方法去更新数组

8.Vue.extend 作用和原理

官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
其实就是一个子类构造器 是 Vue 组件的核心 api 实现思路就是使用原型继承的方法返回了 Vue 的子类 并且利用 mergeOptions 把传入组件的 options 和父类的 options 进行了合并

9.函数式组件使用场景和原理

函数式组件与普通组件的区别

1.函数式组件需要在声明组件是指定 functional:true
2.不需要实例化,所以没有this,this通过render函数的第二个参数context来代替
3.没有生命周期钩子函数,不能使用计算属性,watch
4.不能通过 $emit 对外暴露事件,调用事件只能通过context.listeners.click的方式
调用外部传入的事件 
5.因为函数式组件是没有实例化的,所以在外部通过ref去引用组件时,实际引用的是HTMLElement
6.函数式组件的props可以不用显示声明,所以没有在props里面声明的属性都会被自动隐式解析为prop,
而普通组件所有未声明的属性都解析到$attrs里面,并自动挂载到组件根元素上面(可以通过inheritAttrs属性禁止)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

优点 1.由于函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件 2.函数式组件结构比较简单,代码结构更清晰

一个简单的展示组件,作为容器组件使用 比如 router-view 就是一个函数式组件

10.监听watch

    watch: {
      '$store.getters.permissionMenus': {
        // 立即监听
        immediate: true,
        // 深度监听
        deep: true,
        handler (val) {
          this.topMenuList = this.$store.getters.permissionMenus
        }
      }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

11.计算属性computed

computed 适用计算一些属性,内存消耗较小依赖值不变,这个也不会变。

computed : {
	changeMes: {
		get: () => {
			return this.mes.split('').reverse().join('')
		},
		set: () => {
			this.mes = '123'
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

12.v-model 的修饰符(自定义v-model实现数据的双向绑定)

在这里插入图片描述
在这里插入图片描述

13. $on $emit 自定义事件进行vue组件通信(eg:兄弟组件间的通信)

调用自定义事件(发送消息) ==> 绑定自定义事件(接收消息)
在这里插入图片描述
在这里插入图片描述
**及时销毁自定义事件:否则会造成内存泄漏
在这里插入图片描述

14 路由 $router

this.$route: 表示当前正在用于跳转的路由器对象,可以调用其name、path、query、params等方法
this.$router: 是VueRouter的一个对象,表示全局路由器对象,项目中通过router路由参数注入路由之后,在任何一个页面都可以通过此方法获取到路由器对象,并调用其push(), go()等方法

$router.push({path:'home'});本质是向history栈中添加一个路由,在我们看来是切换路由,但本质是在添加一个history记录
$router.replace({path:'home'});替换路由,没有历史记录,点击返回,会跳转到上上一个页面

$router.addRoutes(routes: Array<RouteConfig>) 动态添加更多的路由规则,可实现用户权限
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

调用 this.$router.push进行连接跳转:传参的两种方式:

 this.$router.push({name:xx, params:{a:xx, b:xx}})//a, b是我们要传递给另一个页面的参数
       目标页面通过this.$route.params.a或this.$route.params.b来获取参数
  • 1
  • 2
this.$router.push({path:xx, query:{a:xx, b:xx}}) //a, b是我们要传递给另一个页面的参数
   目标页面通过this.$route.query.a或this.$route.query.b来获取参数
  • 1
  • 2

不同点:
1、获取参数的方式不同
2、使用name-params的方式传递,参数不会显示到地址栏,而path-query则会,这个区别类似于post与get。

前置全局守卫beforeEach的使用
使用场景: 一般用在跳转前需要做校验的地方,如:进入首页前做登录校验,如果已登录则跳转首页,否则跳转登录页

使用的地方:
如果是做跳转首页前做登录校验,需要写在main.js文件中,表示在所有路由被访问之前做校验;

import Vue from 'vue'
import App from './App'
import router from './router'
import config from './util/config'
import axios from 'axios'
import Cookies from 'js-cookie'
import iView from 'iview';
import 'iview/dist/styles/iview.css';
 
 
import Home from './components/Home'
import Login from './components/login/login'
 
Vue.use(iView);
 
Vue.config.productionTip = false;
Vue.prototype.baseUrl = config.baseUrl;
Vue.prototype.$http = axios;
Vue.prototype.Cookies = Cookies;  
 
//路由跳转前做判断
router.beforeEach((to, from, next) => {
  let hasLogin = Cookies.get('hasLogin'); //从cookies中获取是否已登陆过的信息
  if(hasLogin){ //如果已经登录,则直接跳转
    next()
  } else if(to.path == '/Home'){ //如果未跳转,且访问的是首页,则重定向到登录页
      next({
        replace:true,
        name:'login',
      })
    }else{
    	next()
    }
  }
})
 
 
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • next() 表示路由成功,直接进入to路由,不会再次调用router.beforeEach()
  • next(‘login’) 表示路由拦截成功,重定向至login,会再次调用router.beforeEach()
    也就是说beforeEach()必须调用next(),否则就会出现无限循环,next() 和 next(‘xxx’) 是不一样的,区别就是前者不会再次调用router.beforeEach(),后者会!

15. vue-router实现懒加载的方式

vue异步组件:vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 。但是,这种情况下一个组件生成一个js文件

/* vue异步组件技术 */
{
  path: '/home',
  name: 'home',
  component: resolve => require(['@/components/home'],resolve)
},{
  path: '/index',
  name: 'Index',
  component: resolve => require(['@/components/index'],resolve)
},{
  path: '/about',
  name: 'about',
  component: resolve => require(['@/components/about'],resolve)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

es提案的import()

// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
/* const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about') */
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
{
  path: '/about',
  component: About
}, {
  path: '/index',
  component: Index
}, {
  path: '/home',
  component: Home
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

webpack的require.ensure()
vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。

/* 组件懒加载方案三: webpack提供的require.ensure() */
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
  path: '/index',
  name: 'Index',
  component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
  path: '/about',
  name: 'about',
  component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

16. 父子组件生命周期

父组件:beforeCreate
父组件:created
父组件:beforeMount
子组件:beforeCreate
子组件:created
子组件:beforeMount
子组件:mounted
父组件:mounted

17. 组件之间通信

父子组件 props和emits
跨级访问父组件的数据,多层组件嵌套 inject和provide
自定义事件 event.$on event.$emit event.$off
所有组件都可以使用,可持久化存储数据 vuex

18.路由守卫三种类型

全局路由守卫(全局前置守卫、全局后置守卫),组件内路由守卫,路由独享守卫(是在路由配置页面单独给路由配置的一个守卫)
一.全局守卫
router.beforeEach((to,from,next)=>{}) 回调函数中的参数,to:进入到哪个路由去,from:从哪个路由离开,next:函数,决定是否展示你要看到的路由页面
如下例:main.js中设置全局守卫

router.beforeEach((to,from,next)=>{
  if(to.path == '/login' || to.path == '/register'){
    next();
  }else{
    alert('您还没有登录,请先登录');
    next('/login');
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

router.afterEach((to,from)=>{}) 全局后置钩子,只有两个参数,to:进入到哪个路由去,from:从哪个路由离。
如下,每次切换路由时,都会弹出alert,点击确定后,展示当前页面

router.afterEach((to,from)=>{
  alert("after each");
})
  • 1
  • 2
  • 3

二.组件内的守卫
到达这个组件时,beforeRouteEnter:(to,from,next)=>{}
如下例,data 组件内守卫有特殊情况,如果我们直接以
beforeRouteEnter:(to,from,next)=>{ alert(“hello” + this.name);}进行访问admin页面,会发现alert输出hello undefined。这是因为,现在访问不到我们的data属性,执行顺序是不一致,这与的声明周期有关。在执行完之前,data数据还未渲染。所以这里,next()会给一个对应的回调,帮助完成。

<script>
export default {
    data(){
        return{
            name:"Arya"
        }
    },
    beforeRouteEnter:(to,from,next)=>{
        next(vm=>{
            alert("hello" + vm.name);
        })
    }
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

离开这个组件时,beforeRouteLeave:(to,from,next)=>{}
点击其他组件时,判断是否确认离开。确认执行next();取消执行next(false),留在当前页面。

beforeRouteLeave:(to,from,next)=>{
        if(confirm("确定离开此页面吗?") == true){
            next();
        }else{
            next(false);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、路由独享的守卫
beforeEnter:(to,from,next)=>{},用法与全局守卫一致。只是,将其写进其中一个路由对象中,只在这个路由下起作用。

19.部署后首次加载较慢的原因,及解决方案

方案一:
1,去掉编译文件中map文件。在编译好后,我们会看到文件夹下有特别多的.map文件,这些文件主要是帮助我们线上调试代码,查看样式。所以为了避免部署包过大,通常都不生成这些文件。
在 config/index.js 文件中将productionSourceMap 的值设置为false. 再次打包就可以看到项目文件中已经没有map文件 (文件大小 35MB–>10.5MB)
2,vue-router 路由懒加载

  • vue异步组件
 /* vue异步组件技术 */
{
  path: '/index',
  name: 'index',
  component: resolve => require(['@/views/index'],resolve)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • import()
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')

// router
{
  path: '/about',
  component: About
}, {
  path: '/index',
  component: Index
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • webpack的require.ensure()
 /* 组件懒加载方案三: webpack提供的require.ensure() */
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
  path: '/index',
  name: 'Index',
  component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

方案二: 使用CDN减小代码体积加快请求速度

二、vue3.0新特性

在性能方面,对比Vue2.x,性能提升了1.3~2倍左右;打包后的体积也更小了,如果单单写一个HelloWorld进行打包,只有13.5kb;加上所有运行时特性,也不过22.5kb

1.setup

可替代beforeCreate,created生命周期
同时为了命名的统一,将beforeDestroy改名为beforeUnmount,destroyed改名为unmounted
vue3新增了生命周期钩子,我们可以通过在生命周期函数前加on来访问组件的生命周期,我们可以使用以下生命周期钩子:

onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted
onErrorCaptured
onRenderTracked
onRenderTriggered
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
import { onBeforeMount, onMounted } from "vue";
export default {
  setup() {
    console.log("----setup----");
    onBeforeMount(() => {
      // beforeMount代码执行
    });
    onMounted(() => {
      // mounted代码执行
    });
  },
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.Tree-shaking

Tree-Shaking带来的bundle体积更小
在Vue3中,所有的API都通过ES6模块化的方式引入,这样就能让webpack或rollup等打包工具在打包时对没有用到API进行剔除,最小化bundle体积

3.Composition API(组合API)

export default {
  setup() {
    const { networkState } = useNetworkState();
    const { user } = userDeatil();
    const { list } = tableData();
    return {
      networkState,
      user,
      list,
    };
  },
};
function useNetworkState() {}
function userDeatil() {}
function tableData() {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

三、vue-javaScript / vue-typeScript

TypeScript的优势

  • 静态类型化,允许开发人员编写更健壮的代码并对其进行维护。
  • 大型的开发项目,使用TypeScript工具来进行重构更容易、便捷。
  • 类型安全,在编码期间检测错误的功能,而不是在编译项目时检测错误。
  • 干净的ECMAScript6代码,自动完成和动态输入等因素有助于提高开发人员的工作效率。

JavaScript的优势

  • JavaScript的开发者社区仍然巨大而活跃,在社区可以很容易找到大量成熟的开发项目和可用资源。
  • JavaScript语言发展较早,也较为成熟。
  • TypeScript代码需要被编译(成JavaScript)
  • 不需要注释
  • JavaScript的灵活性更高

灵活选择
在开发大型开发项目时,使用TypeScript更加合适。如果有一个相对较小的编码项目,似乎没有必要使用TypeScript,只需使用JavaScript。

写法区别 代码

<template>
  <div class="home">
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, PropSync, Model, Watch, Provide, Inject, Emit, Ref } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src

const symbol = Symbol('baz');

@Component({
  components: {
    HelloWorld,
  },
})
export default class Home extends Vue {
  @Prop(Number) readonly propA: number | undefined;
  @Prop({ default: 'default value' }) readonly propB!: string;
  @Prop([String, Boolean]) readonly propC: string | boolean | undefined;

  @PropSync('name', { type: String }) syncedName!: string;

  @Model('change', { type: Boolean }) readonly checked!: boolean;

  @Watch('child')
  onChildChanged(val: string, oldVal: string) {}

  @Watch('person', { immediate: true, deep: true })
  onPersonChanged1(val, oldVal) {}

  @Watch('person')
  onPersonChanged2(val, oldVal) {}

  @Inject() readonly foo!: string;
  @Inject('bar') readonly bar!: string;
  @Inject({ from: 'optional', default: 'default' }) readonly optional!: string;
  @Inject(symbol) readonly baz!: string;

  @Provide() foo1 = 'foo';
  @Provide('bar') baz1 = 'bar';

  count = 0;

  @Emit()
  addToCount(n: number) {
    this.count += n;
  }

  @Emit('reset')
  resetCount() {
    this.count = 0;
  }

  @Emit()
  returnValue() {
    return 10;
  }

  @Emit()
  onInputChange(e) {
    return e.target.value;
  }

  @Emit()
  promise() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(20)
      }, 0)
    })
  }

  @Ref() readonly anotherComponent;
  @Ref('aButton') readonly button!: HTMLButtonElement;

  mounted() {
    console.log('mounted');
  }
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
<template>
  <div class="home">
  </div>
</template>
<script lang="js">
import HelloWorld from '@/components/HelloWorld.vue';

const symbol = Symbol('baz');

export default {
  components: {
    HelloWorld,
  },
  props: {
    propA: {
      type: Number,
    },
    propB: {
      default: 'default value',
    },
    propC: {
      type: [String, Boolean],
    },

    // @PropSync
    name: {
      type: String,
    },

    // @Model
    checked: {
      type: Boolean,
    },
  },

  // @Model
  model: {
    prop: 'checked',
    event: 'change',
  },

  inject: {
    foo: 'foo',
    bar: 'bar',
    optional: { from: 'optional', default: 'default' },
    [symbol]: symbol
  },
  data() {
    return {
      foo: 'foo',
      baz: 'bar'
    }
  },
  provide() {
    return {
      foo1: this.foo,
      bar1: this.baz
    }
  },

  computed: {
    // @PropSync
    syncedName: {
      get() {
        return this.name;
      },
      set(value) {
        this.$emit('update:name', value);
      }
    },

    // @Ref
    anotherComponent: {
      cache: false,
      get() {
        return this.$refs.anotherComponent;
      }
    },
    button: {
      cache: false,
      get() {
        return this.$refs.aButton as HTMLButtonElement;
      }
    },
  },

  watch: {
    child: [
      {
        handler: 'onChildChanged',
        immediate: false,
        deep: false
      }
    ],
    person: [
      {
        handler: 'onPersonChanged1',
        immediate: true,
        deep: true
      },
      {
        handler: 'onPersonChanged2',
        immediate: false,
        deep: false
      }
    ]
  },
  methods: {
    // @Watch
    onChildChanged(val, oldVal) {},
    onPersonChanged1(val, oldVal) {},
    onPersonChanged2(val, oldVal) {},

    // @Emit
    addToCount(n) {
      this.count += n;
      this.$emit('add-to-count', n)
    },
    resetCount() {
      this.count = 0;
      this.$emit('reset')
    },
    returnValue() {
      this.$emit('return-value', 10)
    },
    onInputChange(e) {
      this.$emit('on-input-change', e.target.value, e)
    },
    promise() {
      const promise = new Promise(resolve => {
        setTimeout(() => {
          resolve(20)
        }, 0)
      });

      promise.then(value => {
        this.$emit('promise', value)
      })
    }
  },
  
  mounted() {
    console.log('mounted');
  }
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/269467
推荐阅读
相关标签
  

闽ICP备14008679号