前言
Vue 这个东西很强,听说不会js的学完后也能用得飞起?就是有点无脑,本文主要意图是记录自己学习中的流程和各种疑点,总之它提供给我们有一堆相似的操作,但是要把它用成这个语言该有的样子,精确到哪个文件夹该放什么文件,形成一种开发的风格、规约,这样最好不过
刚刚开始学 Vue的时候用的是 传统的开发方式,把一堆东西塞在 html 页面里面,或者链接来链接去的,就像下面这样:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script type="text/javascript">
// ... BODY
Vue.component('Tree', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
// ... 过滤器 等等....
new Vue({
data:{
},
methods:{
}
})
</script>
</body>
</html>
这样在小项目中确实没啥问题,但是东西越来越大就会有烦恼:
- 全局定义 ,强制要求每个
component
中的命名不得重复- 字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑>陋的
\
- 不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
- 没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
然后现在又突然用到 单文件组件
,模块化
,组件化
的开发方式,一时半会有点难受,
但用了一段时间过后:真香
<template>
<div>
</div>
</template>
<script>
export default {
name: 'test',
};
</script>
<style scoped>
</style>
至此组件更加内聚,低耦合
Vue cli 2.x版本构建项目目录一览
以下皆为
Vue cli
命令构建的项目,Vue cli 命令:
vue ui
Vue cli 4.x版本构建项目目录一览
关于static
,assets
文件夹
相同点:资源在html中使用,都是可以的。
不同点:使用assets下面的资源,在js中使用的话,路径要经过webpack中loader编译,路径不能直接写。static里面的文件build
后只是复制一遍,路径要写绝对路径注意:在动态的绑定上面,使用assets中的资源会加载失败,因为webpack使用的是
commenJS
规范,必须使用require
才可以(在运行时动态的决定请求哪一个资源进来)
总结:
static
中放别人的库(建议放一些外部第三方)
assets
中放自己的资源
关于compoents
,views
文件夹
在之前的 vue cli2.x 中我还没有发现有个 views 的文件夹,现在多了一个,所以就百度了下:
然后又扯到了一个
containers
文件夹
总结:
components
中是推荐放常用的一些小组件,这些组件将来可能被复用到很多个地方,
views
中推荐放页面级的组件,按照它的命名,可以想到是各个视图,一般views组件不被复用
containers
属于容器级组件,根据项目大小决定是否使用
关于生命周期函数
我非常好奇的是,为什么要把
outerHTML
翻译成外部的HTML
,不应该是内部的嘛?然后我看了下中文的vue.js文档,看到里面的直接翻译,我惊了!!!
这难到不是对新手理解及其不友好?前辈的直接翻译,是真的
n p
然后我又查了 MDN,还在一些框架中看到outerHTML 的字样,它们的功能都是如此:
outerHTML属性用来设置或者返回元素本身以及其后代HTML内容
这就好像我刚入门编程的时候,接触到的英文教材上面的
context
,直接被翻译成了上下文
,那不分明就是执行调用时,入栈的时候有个执行体么?用来保持里面的结构,数据等等......
Vue 组件的三大组成部分
template 模板:
<template>
<div id="app"> <!--根标签-->
{{mseeage}} <!--插值语句-->
</div>
</template>
每个模板要求有一个
container
容器 (必须要有一个根标签,span
,p
等等内联元素都行)
script 脚本:
<script>
export default {
name:'app',
data(){
return{
arr:[]
}
},
components:{
...
}
...
}
</script>
在模块化编程中 data 需要是一个函数且返回一个对象,而不是单纯的
key
,value
components 中的 组件名称命名请参考 Vue 官方风格指南
style 样式表:
<style>
...
</style>
v-bind 动态绑定标签属性
<div id="app" v-bind:title="titleName">
{{msg}}
</div>
<!--简写为:-->
<div id="app" :title="titleName">
{{msg}}
</div>
Vue 插值语句
<span>Message: {{ msg }}</span>
export default{
data(){
return:{
msg:666
}
}
}
v-on: 事件触发
<div id="app" v-on:click="test">
{{msg}}
</div>
<!--省略为 @click-->
<div id="app" @click="test">
{{msg}}
</div>
可以将
on
缩写为@
,比如@keyup
,@click
,@mousemove
v-model 观察者模式实现的双向绑定
<template>
<input type="text" v-model="name" />
</template>
<script>
export default {
data(){
return{
name:''
}
}
}
</script>
在input 中输入内容,vue组件实例中的属性马上响应发送改变,牵一发而动全身
常用指令
https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4
computed 计算属性(它是属性)
<div id="app-name">
<input type="text" name="" v-model="firstname">
<input type="text" name="" v-model="lastname">
<input type="text" name="" v-model="fullname">
</div>
const vm = new Vue({
el:'#app-name',
data:{
//普通属性
firstname:'Will',
lastname:'Smith',
},
computed:{
// 计算属性
fullname:{
get(){
return this.firstname +' '+ this.lastname;
},
set(value){
const names = value.split(' ');
this.firstname = names[0];
this.lastname = names[1];
}
}
}
});
被初始化的时候调用一次 参考生命周期示意图
不定义
get()
,set()
时fullname
中的执行体(context
)为get
时触发计算属性内部与 data 中有相关联的值也会触发(当相关联的值发送改变的时候)
vue 知道 计算属性
fullname
依赖于 普通属性firstname
,lastname
,当它们两个中的任意一个发生改变时,``fullname的
set`被触发
想观察值发生的变动并且及时作出反应时,使用 computed,适合将普通属性中复杂一点的逻辑写在里面
watch 侦听器(是一个监视者)
<template>
<div>
<el-input v-model="demo"></el-input>
{{value}}
</div>
</template>
<script>
export default {
name: 'index',
data() {
return {
demo: '',
value: ''
};
},
watch: {
demo(newval,oldval) {
this.value = this.demo;
}
}
};
</script>
watch 是一个属性,用来监视 (
data
)列表中的普通属性
一旦被检测的
普通属性
的值发生变化,watch 可以捕获到修改还可以用来监视 路由的变化 (
'$route'(to,from){ }
)
computed、watch、methods 比较
大佬文章 https://blog.csdn.net/zhouzy539/article/details/96340814
vue.js 官网给出 computed 与 methods 的答案是:computed 会缓存结果
普通函数中这样定义:
methods:{
now:function(){
return Date.now()
}
}
我稍微将官网的例子修改了下,这样方便我理解,对比一下下面的 computed 中的计算属性 now:
每次手动调用都是新的 Date 值
在计算属性中这样定义:
computed: {
now: function () {
return Date.now()
}
}
$vm.now 始终返回了初始化完成时候的值,既缓存了结果
假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
w3plus上的总结:
methods
:正如他的名字一样,它们是挂载在对象上的函数,通常是Vue实例本身或Vue组件。computed
:属性最初看起来像一个方法,但事实却又不是方法。在Vue中,我们使用data
来跟踪对特定属性的更改,得到一定的反应。计算属性允许我们定义一个与数据使用相同方式的属性,但也可以有一些基于其依赖关系的自定义逻辑。你可以考虑计算属性的另一个视图到你的数据。watchers
:这些可以让你了解反应系统(Reactivity System)。我们提供了一些钩子来观察Vue存储的任何属性。如果我们想在每次发生变化时添加一些功能,或者响应某个特定的变化,我们可以观察一个属性并应用一些逻辑。这意味着观察者的名字必须与我们所观察到的相符。对于w3plus的总结我的理解:
methods
:和computed写得一样的功能来用完全没毛病,自己手动调用computed
:可以在数据变化的时候自己调用,处理复杂的逻辑,上面的加粗关键词[自定义]watchers
: 把它用成它改有的样子,比如 实现特定的功能、产生特定的逻辑,newvalue
与oldvalue
比较,反应系统一词,我理解为,我们可以把
watchers
定义为普通属性
的钩子函数
,在它数据发送改变后,我们做点什么
小小总结:
watch
擅长处理的场景:一个数据影响多个数据
computed
擅长处理的场景:一个数据受多个数据影响相比于watch/computed,
methods
不处理数据逻辑关系,只提供可调用的函数
class 与 style 动态绑定
<div id="app-name" class="per" :class="a"></div>
<script>
const vm = new Vue({
el:'#app-name',
data:{
a:'aClass'
}
});
</script>
在浏览器中显示为:
<div id="app-name" class="per aClass"></div>
可取值为:String
,Object
,Array
<div id="app-name">
<p :class="a">class is string </p>
<p :class="{aClass:true , bClass:false}">class is string </p>
<p :class="['aClass','bClass']">class is array </p>
</div>
字符串值会在组件实例的 普通属性和计算属性中查找
对象值为
key:value
,value 标识为true
时才起作用数组值:按照排列顺序起作用,
注意:即使是 <p :class="['a','b']" class="c"> 这样写
还是 显示为 <p class="c a b"> 的覆盖顺序。
另外 <p :class="['a','b']" class="a"> 是不会报错的
:style=
用法一致,不过表现为这样:
data(){
return{
newStyle:{
color:'red',
border:'1px solid blue'
}
}
}
Vue 条件渲染 ,v-if/else
, v-show
先看v-if/else
:
<div id="app-name">
<p v-if="isLive">存活</p>
<p v-else="isLive">死亡</p>
<button @click="isLive=!isLive">switch</button>
</div>
const vm = new Vue({
el:'#app-name',
data:{
isLive:false
}
});
改写成 v-show
<div id="app-name">
<p v-show="isShow">显示</p>
<p v-show="isShow">不显示</p>
<button @click="show">switch</button>
</div>
const vm = new Vue({
el:'#app-name',
data:{
isShow:false
},
methods:{
show(){
this.isShow = !(this.isShow)
}
}
});
两者相同点:
- 功能一样
两者不同点:
v-if else
是 移除与创建元素,需要通过内存来创建v-show
是在页面中 决定该元素的display
来进行切换的
总结:频繁切换的情况下使用
v-show
比较好
Vue 列表渲染
以前是通过先在页面上写好静态的 布局,然后设置
css
,class
,然后再在js中用语句动态的循环data.length
次,使劲的createElement
,setAttribute
,appendChild
, 现在舒服了
<div id="test">
<ul>
<li v-for="(p,index) in filterPersons)" :key="index">{{p.name}}--{{p.age}}</li>
</ul>
</div>
new Vue({
el:'#test',
data:{
persons:[
{name:'Bob',age:18},
{name:'Jack',age:22},
{name:'Anna',age:23}
],
}
}
固定的搞法,
v-for="(p,index) in filterPersons)" :key="index"
for...in
是用key
来遍历的,遍历对象合适不过index
为附加定义的一个唯一下标值:key
作为该元素的唯一标识,注意key
相同时会抛出错误,(可能会引起更新错误)
Vue 单个组件的调试
先安装
npm install -g @vue/cli-service-global
再使用命令 vue serve
后面是具体的路径下的组件
vue serve src/components/Test.vue