渐进式框架(数据驱动)
vue.js 是一套用于构建用户界面的渐进式框架
vue使用
-
通过 <script> 的方式来引入 vue,开发版及生产版本
```html <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> ``` -
通过cli来构建项目
-
栗子
<body>
<div id="app">
<!--
app 内:作用域
{{ }}:插值表达式,内部是一个类js环境,可以做简单的逻辑运算;if else 不可以写
-->
{{message}}
<br>
{{message + '这里'}}
<br>
{{'message'}}
<br>
{{flag? 'yes': 'no'}}
</div>
<script>
let app = new Vue({
el: '#app',
// el 挂载点, 不能挂载html/body上
// css 选择器
data: {
message: 'test',
flag: false
}
})
// 修改数据则视图会发生改变
// app.message = '修改'
// app.$data.message = '修改'
// $ / _ 开头的为预定义的属性和方法
// app.$data 做了代理proxy,循环app.$data这里的数据,并添加到app上
// 延迟挂载
// 不想在实例化的时候挂载,想要在后面挂载
// app.$mount("#app");
</script>
</body>
- 运行结果
vue 组件
全局注册
- 组件没有挂载点,挂载点是在实例里面
- 组件里的data一定要是返还函数;(传值)(实例里用不用返还函数都可以)
<body>
<div id="app">
<!-- 调用组件 -->
<!-- 单标签、双标签都可以,区别在于要不要传参 -->
<my-component ></my-component>
<hr>
{{mydata}}
<hr>
{{arr}}
<hr>
{{obj}}
</div>
</body>
全局注册组件
Vue.component("MyComponent",{
data:function(){
return {
message:"组件里的数据"
}
},
// 最外层一定 要 一个 标签容器包裹 ;
template:`<div>我是my-component里的内容</div>`
render优先渲染;
// render(createElement){
// // 渲染视图 (虚拟dom:vdom)
// let Vdom = createElement("div","我是div里的内容");
// // console.log(Vdom);
// // 有特殊标识的对象
// return Vdom;
// }
})
局部注册
let ComponentA = {
template:`<div>我是A组件</div>`
}
// 局部组件
let MyComponent = {
components:{
ComponentA
},
data:function(){
return {
message:"MyComponent内容"
}
},
template:`<div>我是MyComponent里的内容{{message}} <component-a /> </div>`
}
// vue实例
let app = new Vue({
el:"#app",
components:{
myComponent:MyComponent
},
data:{
mydata:"数据",
arr:["张三","李四","王五"],
obj:{
name:"王二",
age:23
}
}
})
// 数据渲染Object.defineProperty (数据观察):更新视图;
// 几种情况不能更新视图;
// 组件和实例中的data都会有同样的问题
// 1. 数组操作不能更新(length)
// 2. 对象的新增属性
// 强制更新视图 Vue.set
setTimeout(()=>{
console.log("....");
// 重写数组方法(变异方法);
// 数组方法:push、pop、shift、unshift、splice、sort、reverse
// app.arr.push("王小二");
// 数组不能更新视图,强制更新
// Vue.set(app.arr,1,"王小二");
// app.arr[1] = "王小二";
// console.log(app.arr);
// 对象可以更改;
// app.obj.name = "修改的名字";
// 对象新增属性不能更改;
// app.obj.height = "178cm";
// 强制更改
// Vue.set(app.obj,"height","178cm");
},1000)
// let that = this;
// that
指令
vue 动画
transition 组件
通过 transition 组件包裹的元素或组件,会在上面定义的几个场景中触发过渡,并添加指定的 class 样式
过渡类名
v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter被移除),在过渡/动画完成之后移除v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave被删除),在过渡/动画完成之后移除
原生js实现动画
<style>
.box{
width: 100px;
height: 100px;
background: red;
transition: all 3s;
position: absolute;
left: 0px;
}
</style>
body>
<button class="btn">点击</button>
<div class="box">
</div>
</body>
<script>
document.querySelector(".btn").onclick = function(){
document.querySelector(".box").style.left = "500px";
}
</script>
vue实现css动画
<style>
.box{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 300px;
}
<!--name = move-->
.move-enter{
left: 0px;
opacity: 0;
}
.move-enter-to{
left: 300px;
opacity: 1;
}
.move-enter-active,.move-leave-active{
transition: all 3s;
}
.move-leave{
left: 300px;
opacity: 1;
}
.move-leave-to{
left: 600px;
opacity: 0;
}
</style>
<body>
<div id="app">
<button @click="judge=!judge">点击我显示隐藏div</button>
<transition name="move">
<div class="box" v-show="judge"></div>
</transition>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
judge:true
}
})
</script>
组件切换动画
<style>
.box{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 300px;
}
.move-enter{
left: 0px;
opacity: 0;
}
.move-enter-to{
left: 300px;
opacity: 1;
}
.move-enter-active,.move-leave-active{
transition: all 1s;
}
.move-leave{
left: 300px;
opacity: 1;
}
.move-leave-to{
left: 600px;
opacity: 0;
}
</style>
<body>
<!--模式:先进后出还是先出后进,不给的时候是同时的
mode="out-in" / "in-out"-->
<div id="app">
<button @click="changeCom">点击我切换</button>
<transition name="move" mode="out-in">
<div :is="comName"></div>
</transition>
</div>
</body>
<script>
let ComA = {
template: `<div class="box">我是Coma组件</div>`
}
let ComB = {
template: `<div class="box">组件Comb</div>`
}
new Vue({
el: "#app",
data: {
comName: 'com-a'
},
components: {
ComA,
ComB
},
methods: {
changeCom() {
if(this.comName=="com-a"){
this.comName = "com-b";
}else{
this.comName = "com-a";
}
}
},
})
</script>
vue实现js动画
<style>
.box{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 300px;
}
</style>
<body>
<div id="app">
<button @click="judge=!judge">点击切换</button>
<transition
:css="false"
// transition会优先走css动画,如果用js动画,可以跳过检测,提高性能
@before-enter="beforeEnter"
@enter="enter"
@leave="leave"
>
<div class="box" v-if="judge">
</div>
</transition>
</div>
</body>
<script>
new Vue({
el:"#app",
data:{
judge:true
},
methods: {
beforeEnter(el){
console.log(el);
$(el).css({
left:"0px",
opacity:0
})
},
enter(el,done){
<!--通过done 转交到下一个-->
// 异步情况要把done放在回调里
$(el).animate({left:"300px",opacity:1},done);
//done() 不能在这里写,因为animate是异步的
},
leave(el,done){
$(el).animate({left:"600px",opacity:0},done);
}
// https://cn.vuejs.org/v2/guide/transitions.html
// leave/enter 都有done
},
})
</script>
vue 插件
html:
body>
<div id="app">
</div>
</body>
<script type="module">
import Fn from './myfn.js';
// Vue.prototype.fn = Fn;
Vue.use(Fn);
// 用use 加入,不会影响原型
new Vue({
el:"#app",
data:{
message:"数据"
},
created(){
// Fn();
this.fn();
},
mounted(){
console.log("mounted");
}
})
</script>
myfn:
// 用了use 具体做了什么事
function fn(){
console.log("一些逻辑");
}
export default function install(_Vue){
// console.log(_Vue);
_Vue.prototype.fn = fn;
_Vue.mixin({
mounted(){
console.log("混入的mounted逻辑");
}
})
};
vue-cli
安装
npm install -g @vue/cli
# OR
yarn global add @vue/cli
package.json
// 运行时命令:npm run server / yarn server
// 上线前: npm run build 打包到dist目录,可以不仅仅在node环境下运行
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
// 开发时需要用,上线后也需要 --save/-S
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.3.3"
},
// 开发时需要,上线后不需要 --save-dev/-D
"devDependencies": {
"@vue/cli-plugin-babel": "~4.4.0",
"@vue/cli-service": "~4.4.0",
"vue-template-compiler": "^2.6.11"
},
vue文件
<template>
// 最外层容器——根元素
<div>
<my-com></my-com>
// <MyCom></MyCom> 也会被容错
</div>
</template>
<script>
export default {
data () {
return {
}
},
components: {
MyCom
}
}
</script>
<style scoped>
</style>
注意:
- template 也可以用src引入
<template src="">
</template>
- lang
<template lang="pug/ejs">
</template>
- scope
// scope不加会影响全局
<style scoped>
</style>
<template>
<div>
我是mycom组件
<span>内容</span>
<!--@ 相对于路径src-->
<!-- <img src="@/assets/logo.png" /> -->
<!--用相对路径-->
<!-- <img src="../assets/logo.png" /> -->
<!-- <img src="./assets/logo.png" /> -->
<!--找不到路径,默认会向前拼接服务器地址-->
<!-- <img src="/assets/logo.png" /> -->
</div>
</template>
<script>
// spa 单页面应用
export default {
data () {
return {
}
},
components: {
}
}
</script>
<style scoped>
/* span{
color:red
} */
</style>
注意:
@ -> webpack resolve 编译 -> /src 方便不同地方引用
hash history 都不会往服务器发请求
vue-router
/* router.js */
import Vue from 'vue'
import VueRouter from 'vue-router'
import AddNews from '@/components/AddNews'
import NewsShow from '@/components/NewsShow'
Vue.use(VueRouter)
let router = new VueRouter({
mode:"history", // hash
routes:[
{
path:'/',
redirect:'/addNews'
},
{ name:"addnews",
path:"/addNews",
component:AddNews
},{
name:"newshow",
path:"/newsShow",
component:NewsShow
}
],
linkActiveClass:"myActive"
})
export default router;
router-link
:to='" "' / {name: '', params: {id: item.id}}
默认生成a标签 tag= 指定生成标签
拦截点击 click 事件,内部哈希跳转/hsitory