前端框架基础 vue
前端开发的变化过程
1、html js css 导入
2、构建工具(编译工具 webpack,vite2) + 新语言(ES6,typescript) + 前端框架(vue,react,agular,flutter…)(数据驱动视图、路由机制)
xxx.vue
3、脚手架 CLI
4、SPA: single page application
5、MPA : multiple page application
6、模块化 node require Import
.js css 都会被模块化
二、VUE CLI 使用
-
主流版本 cli2 cli3.x != vue版本
安装
安装完成后,就可以使用vue指令来创建和管理一个脚手架项目
npm i -g vue-cli // "2.x" npm i -g @vue/cli // "默认安装的是最新版本(一般不要安装最新版,防止各个插件版本不匹配)" npm i -g @vue/cli@4.x //"安装指定版本 安装4.x" npm uninstall -g vue-cli //"删除 2.x" npm uninstall -g @vue/cli //"删除3.x以上" npm i 模块名@版本号 一般在安装命令行(cli)模块时,我们采用 -g 全局安装,为的是保证安装出来的命令行指令在系统的每个 目录都可以使用,相当于配置了该指令的"环境变量"
创建项目
先在cmd中进入要创建项目目录,然后再执行以下指令 cli3.x+
vue create 项目名 vue ui 项目的可视化管理工具, 类似于 phpmyadmin
Cli2 创建方式
vue init webpack 项目名称
三、项目架构说明
-
public 目录
+. 该目录中,存放的是htmlwebpackPlugin的模版文件 index.html
+ 该目录也是devserver的开发服务根目录
-
src. 目录
项目代码目录:所有的业务代码都写在该目录中
-
main.js :webpack打包入口文件,所有代码都从该文件开始执行
import Vue from 'vue'; import App from 'App.vue' ; //创建了 vue实例 new Vue({ render : h => h(App) //将App.vue中的结构渲染到#app中 }).$mount('#app') //该Vue是以模版文件index.html。div#app作为挂载点
-
App.vue : 挂载到div#app中的母板,这里面一般只放一个标签
<template> <div class="app"> <router-view> </div> </template>
-
assets : 静态资源目录(本地所使用一些静态文件 js,css,图片,字体)
- img
- font
- css
- Js
-
剩余的目录都可以根据工程需要,自行创建,但原则上还要按照同一类型用一个文件目录存放
例如: views目录:存放所有的页面.vue
-
##### 页面架构
-
.vue文件基本构成
- 页面vue命名规范 大驼峰命名法
- Home.vue
html部分 <template> <div> 必须要有一对div包裹 </div> </template> js部分 <script> export default { } </script> css部分 <style scoped> /*样式隔离*/ //scoped属性添加以后有,编译生成的样式会带有一个随机的hash属性选择器,用于隔离区分不同 //vue组件中的css选择器 //编译的效果如下 .box[data-v-bcc8ec6a] { color: blue; background: green; } </style>
-
基本路由配置
vue+webpack做的是单页面 SPA应用,因此内部页面跳转,本质上是标签容器的切换。这种切换需要利用前端的路由概念来实现,因此我们需要安装一个别人已经写好的路由跳转插件 vue-router
//main.js
import RouterVue from 'router-vue' ; //导入
//挂载到Vue原型
Vue.use(RouterVue);
//创建路由对象
const router = new RouterVue({
//配置路由表
routes : [
{
path : "/home",
componet : () => import('@/views/Home.vue')
},
{
path : "/work",
componet : () => import('@/views/Work.vue')
}
]
})
//注入vue实际例
new Vue({
router
})
-
.editorconfig 文件(编辑配置文件,用于设置编辑器的编写特性)
charset = utf-8 //文件编码格式 style_indent = tab //缩进方式 indent_size = 2 //缩进大小 //vscode必须安装对应的 .editorconfig插件才能生效以上配置
-
.gitignore git提交是忽略文件配置
-
babel-config.js babel配置文件
-
Vue.config.js
// vue.config.js是webpack配置的一个包装后的配置对象文件 module.exports = { lintOnSave : false , //关闭eslint检查 chainWebpack : config=> { //可以通过config来访问配置原始的webpack配置对象 config .resolve .alias .set('v', path.resolve(__dirame, './src/views')) } }
数据驱动视图
-
MustAche语法 模板语法
<template> <div> {{city}} 北京 {{city + "ddd"}} 北京dd {{city == "北京" ? "111" : "222"}} 111 {{表达式}} <div class="box" :data-id="city"></div> data-id="北京" </div> </template> <script> export default { data(){ return { city : "北京" } } } </script>
-
写在标签行间外 {{表达式}}
<div>{{表达式}}</div>
-
写在标签行间属性内 :属性名=“表达式”
<div :src="表达式" :data-id="表达式"></div>
-
默认都是渲染的是文本,如果渲染html字符串 v-html=“标签字符串变量”
<div v-html="标签字符串变量"></div>
-
-
计算属性(computed)
计算属性常常用在,要被渲染的变量是需要经过复杂的数据处理过程后才显示结果的场景。写在 computed : {},以函数的形式的进行定义。 函数名,就是计算属性名。函数的返回值就是计算属性的值
<template> <div>{{con}}</div> //由于content变量的处理,需要有一个复杂过程(需要多个表达式处理),因此,不能直接给在{{}}中写,此时需要计算属性con </template> <script> export default{ data(){ return { content : "你TMD的可以G了" } }, computed: { con(){ return this.content.replace(/TMD|G/g,argu=> "*".repeat(argu.length)) }, aa : function(){ //可以传参的计算后属性 return (char)=>{ return this.content.replace(/TMD|G/g,argu => char.repeat(argu.length)); } } } } </script>
-
条件渲染
v-if v-else v-else-if
根据不同的表达式结果,来显示不同的组件:特点是如果条件为假,组件都不会被创建
```vue
<template>
<h1 v-if="num > 90">优秀</h1> //num = 200 显示优秀
<h2 v-else-if="num > 80">良好</h2> //num 80-90 显示良好
<h2 v-else-if="num > 60">及格</h2> // num 60-80 显示及格
<h2 v-else>挂科</h2> // num < 60 显示挂科
</template>
<script>
export defalut {
data(){
return {
num : 200
}
}
}
</script>
```
- v-show : 写在组件行间,如果表达式的结果为真,就给该组件设置display:block 如果条件表达式结果为false就给该组件设置display:none
v-show与v-if的区别,v-if条件为假不会创建组件,v-show总会创建组件,因此加载过程v-if要比v-show要快,运行过程,v-if条件变化,需要重新创建DOM,因此执行速度没有v-show快,一般v-if总是用于多显一状态 v-show用于单个盒子显示和隐藏
-
列表渲染
遍历数组
<template> <div v-for="(item,index) in pds" :key="item.id" class="cell"> <h1>{{index + 1}}</h1> <h2>id:{{item.id}}</h2> <h2>书名:{{item.name}}</h2> <h2>作者:{{item.author}}</h2> </div> </template> <script> export default{ data(){ return { pds : [ { id : "001", name : "三国演义", author : "罗贯中" }, { id : "002", name : "红楼梦", author : "曹雪芹" }, { id : "003", name : "西游记", author : "吴承恩" }, { id : "004", name : "水浒传", author : "施耐庵" } ], } } } </script>
遍历对象
<template>
<div v-for="(value,key) in person" :key="key">
{{key}} : {{value}}
</div>
</template>
<script>
export default{
data(){
return {
person : {
name : "张三",
age : 12
}
}
}
}
</script>
遍历数值
<template>
<div class="box" v-for="n in 10">{{n}}</div>
</template>
手动安装vue-router默认安装出来的版本是4.x版本,4.x版本是为vue3.x匹配制作的,导致我们vue2.x核心的项目无法使用
warning in ./node_modules/vue-router/dist/vue-router.esm-bundler.js
"export 'computed' was not found in 'vue'
解决方案:重装低版本的vue-router
npm un vue-router //删除已经安装的
npm i vue-router@3.x. //安装指定版本 3.x
采用构建编译的方式开发项目,经常会遇到依赖与依赖之间版本匹配的问题,特征是代码不报错,项目报错出在依赖中。解决方案是尝试更换不同的依赖版本,一般是降版本
列表渲染
- 基本渲染 普通arr
- item 是数组元素,命名可以是任意,底层代码是数组遍历内部函数形参
- i 是数组元素下标
- key 属性用于表示当前列表元素的唯一性,一般动态传入数组下标。或者元素ID
<div class="item" v-for="(item,i) in listData" :key="i">
{{item}}
</div>
<script>
export default {
data(){
return {
listData : [ "中国队进不了世界杯","中国女足没问题","中国国少还可以"],
}
}
}
</script>
- 固定次数重复渲染
<button v-for="i in 5" :key="i">{{i}}</button>
+ i 是从1开始
+ 5 表示重复渲染结构多少次
- 复合数据渲染
<div class="item" v-for="item in prolist" :key="item.id">
<h1>{{ item.id }}</h1>
<p>{{ item.name }}</p>
</div>
<script>
export default {
data(){
return {
prolist : [
{"id":"001","name": "网球"},
{"id":"002","name": "篮球"},
{"id":"003","name": "棒球"}
]
}
}
}
</script>
:key=“item.id” 原因是这次遍历没有放入下标i,因此需要从item中找一个不重复的属性来代替,一般选item.id
- 嵌套渲染
<div class="item" v-for="item in prolist" :key="item.id">
<h1>{{ item.id }}</h1>
<p>{{ item.name }}</p>
<div class="comments">
<span v-for="(co,i) in item.comment" :key="i">
{{ co }}
</span>
</div>
</div>
<script>
export default {
data(){
return {
prolist : [
{
"id":"001",
"name": "网球",
comment: ["质量好","价格低廉"]},
{
"id":"002",
"name": "篮球",
comment: ["质量好","价格低廉"]},
{ "id":"003",
"name": "棒球",
comment: ["质量好","价格低廉"]}
]
}
}
}
</script>
- 列表选中的行操作
- 跟v-for一同写入行间点指令,均表示每行都使用该指令
<div @click="fn(i)" v-for="i in 5"></div>
效果: 生成5行div,点击哪行,调用fn(行号)
样式操作
<div :class="{active : index == i}" v-for="i in 5">
- v-if 与 v-for混合使用的问题
<!-- v-if 与 v-for混合
一般不允许 v-if 和 v-for同时写在一个标签的行间
原因是:v-if做的DOM增删操作,v-for又是创建动作
这个在性能上有一定冲突,可能导致运行缓慢。
所以如果在遍历时,选择性显示 一般使用v-show来替换
v-if
-->
<div class="wrap5">
<div v-show="index == i" v-for="i in 3" :key="i">{{ i }}</div>
</div>
<h1 v-show="show1">show</h1>
<h1 v-show="!show1">eles</h1>
<button @click="show1 = !show1">dd</button>
```# Vu03
+## 计算属性 Computed
*计算属性主要是用于对各个状态之间进行运算,数据过滤的一种处理*
```Vue
<input v-model="name">
<input v-model="version">
<h1>{{ name + version }}</h1> //运算结果直接拼接
<h1>{{ getFullAppVersionName() }}</h1> //函数
<h1>{{ fullAppVersionName }}</h1> //计算属性
<script>
export default {
data(){
return {
name : "",
version : ""
}
},
methods : {
getFullAppVersionName(){
return this.name + this.version
},
fn(){
//方法内部可以直接通过this.访问计算属性
console.log(this.fullAppVersionName)
}
},
computed : {
fullAppVersionName(){
return this.name + this.version
}
}
}
</script>
计算属性 VS 方法&视图表达式
计算属性是具有数据缓存的,当其依赖的状态没有发生变化时,计算属性是不会调用求值的。方法&视图表达式每次都会进行求值,并更新视图
计算属性的完整写法
<input v-model="name">
<input v-model="version">
<input v-model="fullAppVersionName">
<script>
export default {
data(){
return {
name : "",
version : ""
}
},
computed : {
fullAppVersionName:{
get(){
//计算属性被读取时调用
return this.name + this.version ;
},
set(val){
//计算属性被赋值时调用
this.name = val.split('v')[0]
this.version = val.split('v')[1]
}
}
}
}
</script>
watch 数据监听
允许我们对任意一个已经注册过的状态,进行监听,如果状态值发生变化,可以进行回调处理
<span>价格: {{ price }}</span>
<input v-model.number.lazy="count">
<span>总价格:{{ totalPrice }} </span>
<script>
export default {
data(){
return {
price : 123,
count : 0,
totalPrice : 0,
}
},
watch : {
count(){
//当count值发生变化时,该方法就会被回调
this.totalPrice = this.price * this.count
}
}
}
</script>
watch VS computed
- 共同点: 都是在基于状态的变化,而触发一个函数的回调
- 区别
- watch 是一个单纯的监听回调函数,因此内部可以写异步操作,而computed是利用函数的返回值作为计算属性值的。只能是同步过程
export default {
data(){
return {
count : 10
}
},
watch : {
//监听count变化
count(){
setTimeout(()=>{
this.count++
},3000)
}
},
computed : {
//新增计算属性
countA(){
setTimeout(()=>{
//这样写是无法实现的
this.countA = this.count++
},3000)
}
}
}
- watch一次是只能监听一个值的变化, 计算属性任何一个状态变化,都会触发运算
- 面对复杂多状态运算结果的情况下,使用计算属性代码更简洁
<span>价格:<input v-model.number.lazy="price"> </span>
<input v-model.number.lazy="count">
<span>总价格:{{ totalPrice }} </span>
<span>总价格:{{ cTotalPrice }} </span>
<script>
export default {
data(){
return {
price : 123,
count : 0,
totalPrice : 0,
}
},
watch : {
count(){
//当count值发生变化时,该方法就会被回调
this.totalPrice = this.price * this.count
},
price(){
//当count值发生变化时,该方法就会被回调
this.totalPrice = this.price * this.count
}
},
computed: {
//计算属性更简洁
cTotalPrice(){
return this.price * this.count
}
}
}
</script>
对于多状态变化且同步的运算,使用计算属性
对于单状态,或监听状态变化后有异步操作业务的,使用watch
watch 完整写法 & 深度监听
export default {
data(){
return {
obj : {
name : "李雷",
age : 12
}
}
},
watch : {
//监听obj的name属性
"obj.name" : {
handler(newVal, oldVal){
//newVal:是变化后的值
//oldVal: 是变化前的值
}
},
//直接监听对象
obj : {
handler(newVal,oldVal){
},
deep : true //开启深度监听
}
}
}