Vue简单知识点(上)
vue-loader
const docsLoader = require.resolve('./doc-loader')
module.exports = (isDev) => {
return {
preserveWhitepace: true, // 去除html中多余的空格
extractCSS: !isDev, // 讲css单独打包到一个文件
cssModules: {
localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]', // 避免class命名冲突,而且可以定义class名称
camelCase: true // 横杠式命名转化成小驼峰命名,帮助JS更容易解析
},
// hotReload: false, // 根据环境变量生成,热重载 (样式热重载是通过vue-style-loader来实现的,而不是vue-loader给component进行热重载的功能。但是html更新就是通过刷新更新)
loaders: { // 给自定义的模块指定loader,更多用在给组件库指定文档的时候使用
'docs' : docsLoader,
'js': 'cooffe-loader' // 也可以给js,html,css指定不同的loader
},
preLoader: { // 解析loader之前的解析,也就是先解析},
postLoader: {// 之后解析}
}
}
css属性添加module,然后调用的使用使用:class="$style.cssName" 其实这种使用方式相当于,
<script>
export default {
computed: {
$style() {
return {
calssName:''
}
}
}
}
</script>
"precommit": "npm run lint-fix",
为了缩短 Lint 的反馈链条,把 Lint 挪到本地是最有效的办法。常见做法是使用 husky 或者 pre-commit 在本地提交之前做 Lint。不过要保证项目已经git init ,否则git hook无法生效
Vue Instance
- $data
- $props
- $el
$options
当我创建vue对象所有的options,还有默认的options,但是不是同一个对象,也就是无法修改$options
上的值,但是我们可以这样调用$options.render
- root === app) 通过这种方式挂载
- $chiildren
- $slots 插槽
- $scopedSlots 插槽
- $refs 模板的引用,快速定位模板中的某一个节点或者是组件,如果是html,他会返html中的对象,如果是组件,返回实例
- $isServer 判断服务端渲染
- $watch
$once
(多次调用$once
)- $forceUpdate 强制组件重新渲染,小心使用,容易影响性能
$set
赋值app.$set(app.obj, 'a', i)
- $delete 删除元素
- $nextTick 将回调延迟到下次DOM更新循环之后执行。调用callback
- 更新值,但是DOM节点没有变化的时候调试
不过只有在下一次渲染的时候才会生效
app.$options.render = (h) => {
return h('div',{},'new render function')
}
const unWatch = app.$watch('text', (newText, oldText) => {
console.log(`${newText} : ${oldText}`)
})
unWatch() 注销,防止内存溢出
不冒泡,必须绑定到同一个对象上
app.$once('test', (a, b) => {
console.log(`test emited ${1} ${b}`)
})
app.$emit('test', 1, 2)
Vue lifecycle
- beforeCreate和create肯定会执行(如果没有绑定节点或者是mounted,绑定节点 ),拿不到
$this.$el
- beforeCreate,事件OK,但是reactivity还没有ok
- update beforeUpdate需要等到数据更新时执行
- beforeDestory destroyed解除所有的事件监听和watch
- renderError() 开发时更方便的进行调错
- errorCapured 帮助我们收集线上的错误,可以冒泡
render (h) {
throw new TypeError('render error')
},
renderError (h, err) {
return h('div', {}, err.stack)
},
data-binding
new Vue({
el: '#root',
// template: `
// <div :id="aaa" @click="handleClick">
// <p v-html="html"></p>
// </div>
// `,
template: `
<div
:class="[{ active: isActive }]"
:style="[styles, styles2]"
>
<p>{{getJoinedArr(arr)}}</p>
</div>
`,
data: {
isActive: false,
arr: [1, 2, 3],
html: '<span>123</span>',
aaa: 'main',
styles: {
color: 'red',
appearance: 'none' // 自动加兼容前缀
},
styles2: {
color: 'black'
}
},
methods: {
handleClick () {
alert('clicked') // eslint-disable-line
},
getJoinedArr (arr) {
return arr.join(' ')
}
}
})
computed and watch
- computed相比方法的性能开销比较小
- 有缓存
- 只有依赖的值变化,他才会重新计算并且缓存起来
- 不到万不得已,不要使用set方法
- 改变变量时,整个DOM要重新渲染,如果我们使用了方法,该方法就会被重新调用,但是computed不会
- watch 最初绑定的时候不会执行,当然可以使用handler+immediate:true解决
- 适合监听数据变化,然后执行指定操作,但是不适用于显示某个数据,这个时候,computed就比较合适了
- 当我们修改内部属性时,无法触发handler,但是我们加deep参数,深入观察,当然,这样性能开销就很大了
- 不要在computed和watch 中修改你依赖的值,无限循环
import Vue from 'vue'
new Vue({
el: '#root',
template: `
<div>
<p>Name: {{name}}</p>
<p>Name: {{getName()}}</p>
<p>Number: {{number}}</p>
<p>FullName: {{fullName}}</p>
<p><input type="text" v-model="number"></p>
<p>FirstName: <input type="text" v-model="firstName"></p>
<p>LastName: <input type="text" v-model="lastName"></p>
<p>Name: <input type="text" v-model="name"></p>
<p>Obj.a: <input type="text" v-model="obj.a"></p>
</div>
`,
data: {
firstName: 'Jokcy',
lastName: 'Lou',
number: 0,
fullName: '',
obj: {
a: 0
}
},
computed: {
name: {
get () {
console.log('new name')
return `${this.firstName} ${this.lastName}`
},
set (name) {
const names = name.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
},
watch: {
'obj.a': {
handler () {
console.log('obj.a changed')
this.obj.a += 1
},
immediate: true
// deep: true
}
},
methods: {
getName () {
console.log('getName invoked')
return `${this.firstName} ${this.lastName}`
}
}
})
directive
new Vue({
el: '#root',
template: `
<div>
<div>Text: {{text}}</div>
<div v-if="text === 0">Else Text: {{text}}</div>
<div v-else>else content</div>
<div v-html="html"></div>
<input text="text" v-model="text">
<input type="checkbox" v-model="active">
<div>
<input type="checkbox" :value="1" v-model="arr">
<input type="checkbox" :value="2" v-model="arr">
<input type="checkbox" :value="3" v-model="arr">
</div>
<div>
<input type="radio" value="one" v-model="picked">
<input type="radio" value="two" v-model="picked">
</div>
<ul>
<li v-for="(item, index) in arr" :key="item">{{item}}:{{index}}</li>
</ul>
<ul>
<li v-for="(val, key, index) in obj">{{val}}:{{key}}:{{index}}</li>
</ul>
</div>
`,
data: {
arr: [2, 3],
obj: {
a: '123',
b: '456',
c: '789'
},
picked: '',
text: 0,
active: false,
html: '<span>this is html</span>'
}
})
- v-on
- v-bind
- v-model 一般用在input等交互标签
- 可以在后面加上number,trim,lazy等修饰符
- v-pre不解析
- v-cloak 防止页面加载时出现 vuejs 的变量名
- v-once 数据只绑定一次,节省性能(不更新数据)
- v-props 作为一个子节点不应该主动去修改主节点的值
- 数据经常变化,如果每次变化,view会重新渲染列表,再把它放进Dom中去,性能开销就会比较大
- :key减少性能开销,变化,如果在缓存列表中拿到同样的key,就把这行的dom节点复用了,就不用生成新的dom节点
- 一般不推荐使用index,一般用item,唯一值
vue原生指令
- v-show
- v-html
- v-text
- v-if 如果只是单纯的控制隐藏显示,推荐使用v-show.因为v-if是会动态增删节点,性能差很多(Dom重绘和重新排版)
- v-for="(item,index) in arr"
- v-for="(val,key) in obj"
- :key 数据中唯一ID值 因为数据经常变化,性能开销大 ,但是如果定义key之后,如果key没有变化,直接复用Dom节点,不建议用index做
- @click
- v-model.number .lazy(在 “change” 而不是 “input” 事件中更新)
- v-pre
- v-cloak
- v-once 数据绑定内容只执行一次
component
const compoent = {
props: {
active: {
// type: Boolean,
// required: true,
validator (value) {
return typeof value === 'boolean'
}
},
propOne: String
},
template: `
<div>
<input type="text" v-model="text">
<span @click="handleChange">{{propOne}}</span>
<span v-show="active">see me if active</span>
</div>
`,
data () { // data必须是通过function定义,不能是全局的
return {
text: 0
}
},
methods: {
handleChange () {
this.$emit('change')
}
}
}
// Vue.component('CompOne', compoent) 全局注册组件
new Vue({
components: {
CompOne: compoent
},
data: {
prop1: 'text1'
},
methods: {
handleChange () {
this.prop1 += 1
}
},
mounted () {
console.log(this.$refs.comp1) 拿到vue的实例
},
el: '#root',
template: `
<div>
<comp-one ref="comp1" :active="true" :prop-one="prop1" @change="handleChange"></comp-one>
<comp-one :active="true" propOne="text2"></comp-one>
</div>
`
})
Component extend
const compoent = {
props: {
active: Boolean,
propOne: String
},
template: `
<div>
<input type="text" v-model="text">
<span @click="handleChange">{{propOne}}</span>
<span v-show="active">see me if active</span>
</div>
`,
data () {
return {
text: 0
}
},
mounted () {
console.log('comp mounted')
},
methods: {
handleChange () {
this.$emit('change')
}
}
}
const parent = new Vue({
name: 'parent'
})
const componet2 = {
extends: compoent,
data () {
return {
text: 1
}
},
mounted () {
console.log(this.$parent.$options.name)
}
}
// const CompVue = Vue.extend(compoent)
// new CompVue({
// el: '#root',
// propsData: {
// propOne: 'xxx'
// },
// data: { 合并或覆盖
// text: '123'
// },
// mounted () { components mounted先被调用,然后该mounted被调用
// console.log('instance mounted')
// }
// })
// 第二种方式 ,可以在子组件内部通过$partent直接调用父组件(子组件必须是通过new出来的,而不是模板编译)
new Vue({
parent: parent,
name: 'Root',
el: '#root',
mounted () {
console.log(this.$parent.$options.name)
},
components: {
Comp: componet2
},
data: {
text: 23333
},
template: `
<div>
<span>{{text}}</span>
<comp></comp>
</div>
`
})
Component 自定义双向绑定
import Vue from 'vue'
const component = {
model: {
prop: 'value1',
event: 'change'
},
props: ['value1'],
template: `
<div>
<input type="text" @input="handleInput" :value="value1">
</div>
`,
methods: {
handleInput (e) {
this.$emit('change', e.target.value)
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
template: `
<div>
<comp-one v-model="value"></comp-one>
</div>
`
})
这里的<comp-one v-model="value"></comp-one>也可以这样写
<comp-one :value="value" @input="value = araguments[0]"></comp-one>
组件高级属性
import Vue from 'vue'
const ChildComponent = {
template: '<div>child component: {{data.value}}</div>',
inject: ['yeye', 'data'],
mounted () {
// console.log(this.yeye, this.value)
}
}
const component = {
name: 'comp',
components: {
ChildComponent
},
// template: `
// <div :style="style">
// <div class="header">
// <slot name="header"></slot>
// </div>
// <div class="body">
// <slot name="body"></slot>
// </div>
// </div>
// `,
template: `
<div :style="style">
<slot :value="value" aaa="111"></slot>
<child-component />
</div>
`,
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
},
value: 'component value'
}
}
}
new Vue({
components: {
CompOne: component
},
provide () { // 解决跨层级关系,提供上下文的关系
const data = {}
// provide默认不提供Reactive (Hack方法)
Object.defineProperty(data, 'value', {
get: () => this.value,
enumerable: true
})
return {
yeye: this,
data
}
},
el: '#root',
data () {
return {
value: '123'
}
},
mounted () {
console.log(this.$refs.comp.value, this.$refs.span)
},
template: `
<div>
<comp-one ref="comp">
<span slot-scope="props" ref="span">{{props.value}} {{props.aaa}} {{value}}</span>
</comp-one>
<input type="text" v-model="value" />
</div>
`
})
Vue render
import Vue from 'vue'
const component = {
props: ['props1'],
name: 'comp',
// template: `
// <div :style="style">
// <slot></slot>
// </div>
// `,
render (createElement) {
return createElement('div', {
style: this.style
// on: {
// click: () => { this.$emit('click') }
// }
}, [
this.$slots.header,
this.props1
])
},
data () {
return {
style: {
width: '200px',
height: '200px',
border: '1px solid #aaa'
},
value: 'component value'
}
}
}
new Vue({
components: {
CompOne: component
},
el: '#root',
data () {
return {
value: '123'
}
},
mounted () {
console.log(this.$refs.comp.value, this.$refs.span)
},
methods: {
handleClick () {
console.log('clicked')
}
},
// template: `
// <comp-one ref="comp">
// <span ref="span">{{value}}</span>
// </comp-one>
// `,
render (createElement) {
return createElement(
'comp-one',
{
ref: 'comp',
props: {
props1: this.value
},
// on: {
// click: this.handleClick
// },
nativeOn: {
click: this.handleClick
}
},
[
createElement('span', {
ref: 'span',
slot: 'header',
// domProps: {
// innerHTML: '<span>345</span>'
// }
attrs: {
id: 'test-id'
}
}, this.value)
]
)
}
})
Vue Router
服务端渲染
报错解决
解决 https://github.com/vuejs/vue-loader/issues/470
npm install vue-template-compiler --save-dev
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦