<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script src="./vue.js"></script>
<body>
<!-- v-bind动态传递prop -->
<!-- v-bind 动态赋值 -->
<div id="blog-post-demo">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
></blog-post>
<!-- 重构blog-post让它变成接受一个单独的 post prop -->
<!--通过 v-on 监听子组件实例的任意事件-->
<div :style="{ fontSize: postFontSize1 + 'em' }">
<blog-posts
v-on:enlarge-texts="postFontSize1 += 0.1"
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-posts>
</div>
<!-- <blog-pos> 组件决定它的文本要放大多少 -->
<div :style="{ fontSize: postFontSize2 + 'em' }">
<blog-pos
v-on:enlarge-tex="postFontSize2 += $event"
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-pos>
</div>
<!-- fontsize写在一个方法里 -->
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-po
v-on:enlarge-text="onEnlargeText"
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-po>
</div>
<div>
<input v-model="searchText">
<span>{{searchText}}</span>
<!-- 上面等价于下面 -->
<input
v-bind:value="searchText2"
v-on:input="searchText2 = $event.target.value"
><span>{{searchText2}}</span>
</div>
<!-- 组件上v-modle -->
<custom-input
v-bind:value="searchTex"
v-on:input="searchTex = $event"
></custom-input>
<span>{{searchTex}}</span>
<custom-input v-model="searchTex"></custom-input>
</div>
<!-- 插槽 -->
<div>
<alert-box>
Something bad happened.
</alert-box>
</div>
<!-- <div id="#transition-components-demo">
<transition name="component-fade" mode="out-in">
<component v-bind:is="view"></component>
</transition>
</div> -->
</body>
<script>
// new Vue({
// el: '#transition-components-demo',
// data: {
// view: 'v-a'
// },
// components: {
// 'v-a': {
// template: '<div>Component A</div>'
// },
// 'v-b': {
// template: '<div>Component B</div>'
// }
// }
// })
Vue.component('blog-post', {
props: ['title','content'],//多个属性就有点复杂了,下面(blog-posts)进行了优化
template: `<div class="blog-post"><h3>{{ title }}</h3><div v-html="content">{{content}}</div></div>`
//每个组件必须只有一个根元素
})
Vue.component('blog-posts', {//调用内建的 $emit 方法 并传入事件名称来触发一个事件(事件名称在父组件中)
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button v-on:click="$emit('enlarge-texts')">enlarge-texts</button>
<div v-html="post.content"></div>
</div>
`
})
Vue.component('blog-pos', {//使用事件抛出一个值
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button v-on:click="$emit('enlarge-tex', 0.1)">使用事件抛出一个值</button>
<div v-html="post.content"></div>
</div>
`
})
Vue.component('blog-po', {//事件是一个方法
props: ['post'],
template: `
<div class="blog-post">
<button v-on:click="$emit('enlarge-text',0.1)">方法</button>
<div v-html="post.content"></div>
</div>
`
})
// v-modle组件上
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
// 插槽
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
//动态组件???? <component v-bind:is="currentTabComponent"></component><!-- 组件会在 `currentTabComponent` 改变时改变 -->
//组件规范:
//组件名称:推荐-字母全小写且必须包含一个连字符;
// 两种命名方式-使用 kebab-case,引用这个自定义元素时使用 kebab-case ;使用 PascalCase,引用这个自定义元素时两种命名法都可以使用
// 用入口文件 (比如 src/main.js) 中全局导入基础组件的示例代码:
// import Vue from 'vue'
// import upperFirst from 'lodash/upperFirst'
// import camelCase from 'lodash/camelCase'
// const requireComponent = require.context(
// // 其组件目录的相对路径
// './components',
// // 是否查询其子目录
// false,
// // 匹配基础组件文件名的正则表达式
// /Base[A-Z]\w+\.(vue|js)$/
// )
// requireComponent.keys().forEach(fileName => {
// // 获取组件配置
// const componentConfig = requireComponent(fileName)
// // 获取组件的 PascalCase 命名
// const componentName = upperFirst(
// camelCase(
// // 剥去文件名开头的 `./` 和结尾的扩展名
// fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
// )
// )
// 全局注册组件
// Vue.component(
// componentName,
// // 如果这个组件选项是通过 `export default` 导出的,
// // 那么就会优先使用 `.default`,
// // 否则回退到使用模块的根。
// componentConfig.default || componentConfig
// )
// })
// prop
// camelCase的 prop 名需要使用其等价的 kebab-case命名:props: ['postTitle']----<blog-post post-title="hello!"></blog-post>
// 传入一个对象 两种方式
// 1.<blog-post
// v-bind:author="{
// name: 'Veronica',
// company: 'Veridian Dynamics'
// }"
// ></blog-post>
// 2.<blog-post v-bind:author="post.author"></blog-post>用一个变量进行动态赋值
//传入一个对象所有属性
//<blog-post v-bind="post"></blog-post>等价于<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>
// prop验证:
// 那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。
// 非 Prop 的特性:
/*替换/合并已有的特性:对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。庆幸的是,class 和 style 特性会稍微智能一些,即两边的值会被合并起来
禁用特性继承:如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false,但不会影响 style 和 class 的绑定。
ps:$attrs 属性包含了传递给一个组件的特性名和特性值
*/
//自定义事件
/*
1.推荐使用 kebab-case 的事件名。
2.在一个组件的根元素上直接监听一个原生事件:使用 v-on 的 .native 修饰符,v-on:focus.native="onFocus"
3.Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器(可解决native失效问题)
4.带有 .sync 修饰符的 v-bind 不能和表达式一起使用
// 插槽
1.如果 <navigation-link> 没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃
2.编译作用域:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
3.在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称,
v-slot 只能添加在一个 <template> 上
4.默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确;
只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template> 的语法
5.v-slot缩写#,该缩写只在其有参数的时候才可用,eg: #="{ user }"无效, #default="{ user }"
// 动态组件、异步组件
1.多标签的界面中使用 is 特性来切换不同的组件
2.标签的组件实例要第一次被创建的时候缓存下来,可以用一个 <keep-alive> 元素将其动态组件包裹起来;
<keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
// 处理边界情况
1.在每个 new Vue 实例的子组件中,其根实例可以通过 $root 属性进行访问(小型项目中少量组件可以),一般情况下用Vuex
2.和 $root 类似,$parent 属性可以用来从一个子组件访问父组件的实例
3.$refs 只会在组件渲染完成之后生效,避免在模板或计算属性中访问 $refs
4.provide 选项允许我们指定我们想要提供给后代组件的数据/方法;使用 inject 选项来接收指定的我们想要添加在这个实例上的属性;
如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了
5.$emit、$on, 和 $off 并不是 dispatchEvent、addEventListener 和 removeEventListener 的别名。
6.inline-template 会让模板的作用域变得更加难以理解。所以作为最佳实践,请在组件内优先选择 template 选项或 .vue 文件里的一个 <template> 元素来定义模板
7.一个组件包含了大量静态内容,可以在根元素上添加 v-once 特性以确保这些内容只计算一次然后缓存起来(不要过度使用这个模式)
// 进入/离开 & 列表渲染
1.
*/
new Vue({
el:'#blog-post-demo',
data:{
posts:[
{id:1,title:'My journey with Vue1',content:'<span>js</span>'},
{id:2,title:'My journey with Vue2',content:'<span>js</span>'},
{id:31,title:'My journey with Vue3',content:'<span>js</span>'}
],
postFontSize: 1,
postFontSize1: 1,
postFontSize2: 1,
searchText:'',
searchText2:'',
searchTex:''
},
methods: {
onEnlargeText: function (enlargeAmount) {//这个值将会作为第一个参数传入这个方法:
this.postFontSize += enlargeAmount
}
}
})
/*
可复用性&组合
混入:1.基础-当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
2.选项合并-数据对象在内部会进行递归合并,在和组件的数据发生冲突时以组件数据优先。
同名钩子函数(created)将混合为一个数组,因此都将被调用。
值为对象的选项,例如 methods, components 和 directives,将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对。
3.全局混入-谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例
4.自定义选项合并策略:如果想让自定义选项以自定义逻辑合并,可以向 Vue.config.optionMergeStrategies 添加一个函数,对于大多数对象选项,可以使用 methods 的合并策略。
自定义指令
钩子函数参数:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
*/
</script>
</html>

1573

被折叠的 条评论
为什么被折叠?



