Vue简单基础 + 实例

vue的双向绑定原理:Object.defineProperty()

vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。

Vue简单使用:

<div id="app">
    <h1>{{msg}} {{num+1}}</h1>
</div>    

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
  el:"#app",
  data:{
      msg:"Hello World",
      num:1
  }
})
</script>

v-bind  简写 : 

动态地绑定一个或多个特性,或一个组件 prop 到表达式。

<img v-bind:src="imageSrc">
<!-- 缩写 -->
<img :src="imageSrc">
<a v-bind:href="href">百度</a>
<a :href="href">百度</a>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
  el:"#app",
  data:{
      href:"https://www.baidu.com",
  }
})
</script>
<!-- 通过 prop 修饰符绑定 DOM 属性 -->
<div v-bind:text-content.prop="text"></div>

<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
<my-component :prop="someThing"></my-component>

<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>

动态class 可以绑定对象、数组:

<style>
.isActive{color:green;}
.isError{color:red;}
</style>
<div>
    <a v-bind:href="href" :class="{‘isActive‘:see, ‘isError‘:!see}">百度</a>
</div>
<script>
var app = new Vue({
  el:"#app",
  data:{
      see:true,
  }
})

例子:

<div>
      <a v-bind:href="href" :class="[‘aaa‘,‘msg‘,{‘isActive‘:see}]" :style="[{fontSize:‘20px‘,background:‘yellow‘},{color:‘black‘}]">百度</a>
</div>

//也可以初始化到data里
<div>
    <a v-bind:href="href" :class="[‘aaa‘,‘msg‘,{‘isActive‘:see}]" :style="styles">百度</a>
</div>
<script>
var app = new Vue({
  el:"#app",
  data:{
      styles:[{fontSize:‘20px‘,background:‘yellow‘},{color:‘black‘}],
  }
})

v-if  v-else v-show条件渲染

<div v-if="see">if true</div>
<div v-else>if false</div>
<div v-show="see">show true</div>

<script>
var app = new Vue({
  el:"#app",
  data:{
      see:false,
  }
})
</script>

v-show为false时只是是隐藏了,相当于hidden。

for循环: 

<ul>
      <li v-for="item in person">我是{{item.name}},我{{item.age}}岁了</li>
</ul>
<ul>
      <li v-for="item in obj">{{item}}</li>
</ul>

<script>
var app = new Vue({
  el:"#app",
  data:{
      person:[
        {name:‘111‘,age:‘20‘}, {name:‘222‘,age:‘22‘},{name:‘333‘,age:‘26‘},
      ],
      obj:{name:‘444‘,age:"30"}, //对象循环的是value值
  }
})
</script>

如果要循环key的话:第二参

<ul>
      <li v-for="(item, index) in person">{{index+1}}-我是{{item.name}},我{{item.age}}岁了</li>
</ul>
<ul>
     <li v-for="(item, name) in obj">{{name}}:{{item}}</li>
</ul>

key:标识,禁止复用。当给li添加key后,就不会在出现Dom复用。

例子:上面的例子如果添加一个按钮,点击按钮删除第一条数据,如果不写key的话,实际删除的是Dom里的第三条li,因为Dom复用的原因,加上key,就不会出现Dom复用,删除的就是第一个li

<button @click="person.splice(0,1)">删除</button> <!--点击删除第一条数据-->
<ul>
      <li v-for="(item, index) in person" :key="item.name">
            {{index+1}}-我是{{item.name}},我{{item.age}}岁了
      </li>
</ul>

input例子:

//input也要加key避免复用
<div v-if="see">
      登录:<input type="text" placeholder="登录" key="login" />
</div>
<div v-else>
      注册:<input type="text" placeholder="注册" key="register" />
</div>

//不过一般input都会绑定v-model监听
<div v-if="see">
      登录:<input type="text" placeholder="登录" v-model="login" />
</div>
<div v-else>
      注册:<input type="text" placeholder="注册" v-model="register" />
</div>

v-on 简写@     用到监听

//点击see的值取反,上面条件区域是否显示
<div>
      <h1>条件渲染</h1>
      <div v-if="see">if true</div>
      <div v-else>if false</div>
      <div v-show="see">show true</div>
</div>
<div>
      <h1>v-on</h1>
      <button v-on:click="see = !see">click me</button>
</div>

复杂的功能可以写个方法:

<div>
      <h1>v-on</h1>
      <button @click="click">click me</button>
</div>

<script>
var app = new Vue({
  el:"#app",
  data:{
      see:false,
  },
  methods: {
      click:function(){
          this.see = !this.see; //this指向当前app
      }
  },
})
</script>

传参:

<div>
      <h1>v-on</h1>
      <button @click="click(‘hello‘)">click me</button>
</div>

<script>
var app = new Vue({
  el:"#app",
  data:{
      see:false,
  },
  methods: {
      click:function(val){
          this.see = !this.see; //this指向当前app
          alert(val);
      }
  },
})
</script>

监听input事件:

<input v-on:input="click" />

v-model 双向绑定:

<div><input type="text" v-model="textVal" />{{textVal}}</div>
<script>
var app = new Vue({
  el:"#app",
  data:{
      textVal:"", //初始化

  },
  methods: { //事件监听

  },
})
</script>

单选:

<div>
      <input type="radio" value="0" id="a" v-model="radioVal" /><label for="a">A</label>
      <input type="radio" value="1" id="b" v-model="radioVal" /><label for="b">B</label>
      <input type="radio" value="2" id="c" v-model="radioVal" /><label for="c">C</label>
       {{radioVal}}
</div>

<script>
var app = new Vue({
  el:"#app",
  data:{
      radioVal:"",
  },
})
</script>

复选:

<div>
      <input type="checkbox" value="0" id="aa" v-model="checkboxVal" /><label for="aa">A</label>
      <input type="checkbox" value="1" id="bb" v-model="checkboxVal" /><label for="bb">B</label>
      <input type="checkbox" value="2" id="cc" v-model="checkboxVal" /><label for="cc">C</label>
       {{checkboxVal}}
</div>

<script>
var app = new Vue({
  el:"#app",
  data:{
     checkboxVal:[], //初始化数组
  }
})

下拉选择框:

<div>
      <select v-model="selectVal">
            <option value="0">A</option>
            <option value="1">B</option>
            <option value="2">C</option>
            <option value="3">D</option>
      </select>
      {{selectVal}}
</div>
<script>
var app = new Vue({
  el:"#app",
  data:{
     selectVal:0, //初始为0默认选第一
  }
})
</script>

上面的都可以设置初始值:

data:{
      textVal:"111",
      radioVal:"0",
      checkboxVal:[0],
      selectVal:0,
}

计算属性:computed

<h1>{{msg.split(‘‘).reverse().join(‘‘)}}</h1>
//dlroW olleH  截取反转拼接

//computed实现
<h1>{{msg}}</h1>
<h2>{{reversedMsg}}</h2>
<script>
var app = new Vue({
  el:"#app",
  data:{
      msg:"Hello World",
  },
  computed: { //计算属性
      reversedMsg:function(){
          return this.msg.split(‘‘).reverse().join(‘‘);
      }
  },
})
</script>

//也可以通过方法实现
<h1>{{msg}}</h1>
<h2>{{reversedMsg()}}</h2>
<script>
var app = new Vue({
  el:"#app",
  data:{
      msg:"Hello World",
  },
  methods: { //事件监听
      reversedMsg:function(){
          return this.msg.split(‘‘).reverse().join(‘‘);
      }
  },
})
</script>

不建议用方法的形式,推荐使用计算属性。

结果:

例子:展示年龄大于30岁的数据

<ul>
      <h1>v-for</h1>
      <li v-for="(item, index) in person" v-if="item.age > 30">
          {{index+1}}-我是{{item.name}},我{{item.age}}岁了
      </li>
</ul>
<script>
var app = new Vue({
  el:"#app",
  data:{
      person:[
        {name:‘111‘,age:‘20‘}, {name:‘222‘,age:‘28‘},{name:‘333‘,age:‘36‘},
      ],
  },
})
</script>
//官方推荐用计算属性写法
<ul>
      <li v-for="(item, index) in newPerson">
          {{index+1}}-我是{{item.name}},我{{item.age}}岁了
      </li>
</ul>
<script>
var app = new Vue({
  el:"#app",
  data:{
      person:[
        {name:‘111‘,age:‘20‘}, {name:‘222‘,age:‘28‘},{name:‘333‘,age:‘36‘},
      ],
  },
  computed: { //计算属性
      newPerson:function(){
          return this.person.filter(function(item){return item.age > 30});
      }
  },
})
</script>

监听属性:watch

//输入问题时答案显示waiting,1秒钟后显示404
<div>
      question:<input type="text" placeholder="enter" v-model="question" /><br>
      answer:{{answer}}
</div>
<script>
var app = new Vue({
  el:"#app",
  data:{
      question:"",
      answer:"no answer",
  },
  watch: { //监听属性
    question:function(){
        this.answer = "waiting";
        var _this = this;
        setTimeout(function(){
            _this.answer = "404";
        },1000);
    }
  },
})
</script>

vue检测数组变动:

有两种情况变动的数组,是VUE不能检测到的,也不会触发视图的更新。

  • 通过索引直接设置项   例如: vm.items[indexOfItem] = newValue
  • 修改数组的长度   vm.items.length = newLength

举个例子:

var vm = new Vue({
  data: {
    items: [‘a‘, ‘b‘, ‘c‘]
  }
})
vm.items[1] = ‘x‘ // 不是响应性的
vm.items.length = 2 // 不是响应性的

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

为了解决第二类问题,可以使用 splice

vm.items.splice(newLength)

组件注册:

在注册一个组件的时候,我们始终需要给它一个名字。比如在全局注册的时候我们已经看到了:

Vue.component(‘my-component-name‘, { /* ... */ })

该组件名就是 Vue.component 的第一个参数。

定义组件名的方式有两种:

使用 kebab-case

当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>

Vue.component(‘my-component-name‘, { /* ... */ })

使用 PascalCase

当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

Vue.component(‘MyComponentName‘, { /* ... */ })

全局注册:

到目前为止,我们只用过 Vue.component 来创建组件:

Vue.component(‘my-component-name‘, {
  // ... 选项 ...
})

这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。比如:

Vue.component(‘component-a‘, { /* ... */ })
Vue.component(‘component-b‘, { /* ... */ })
Vue.component(‘component-c‘, { /* ... */ })

new Vue({ el: ‘#app‘ })
<div id="app">
  <component-a></component-a>
  <component-b></component-b>
  <component-c></component-c>
</div>

局部注册:

可以通过一个普通的 JavaScript 对象来定义组件:

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

然后在 components 选项中定义你想要使用的组件:

new Vue({
  el: ‘#app‘,
  components: {
    ‘component-a‘: ComponentA,
    ‘component-b‘: ComponentB
  }
})

对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:

var ComponentA = { /* ... */ }
var ComponentB = {
  components: {
    ‘component-a‘: ComponentA
  },
  // ...
}

或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:

import ComponentA from ‘./ComponentA.vue‘

export default {
  components: {
    ComponentA
  },
  // ...
}

组件通信:

1、props $emit

父组件 A 通过 props 的方式向子组件 B 传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。

(1)父组件给子组件传值:父组件通过 props 向下传递数据给子组件。

//父Home.vue
<Nav :NavActiveIndex="activeIndex"></Nav>
<script>
import Nav from "./Nav.vue";
export default {
  name: "home",
  components: {
    Nav
  },
  data() {
    return {
        activeIndex: ‘/home/buycar‘,
        activeIndex2: ‘1‘
    };
},
</script>

//子Nav.vue
{{NavActiveIndex}} //home/buycar 实现默认绑定购物车
<el-menu
  :default-active="NavActiveIndex"
  class="el-menu-demo"
  mode="horizontal"
  @select="handleSelect"
  background-color="#545c64"
  text-color="#fff"
  router
  active-text-color="#ffd04b">
<script>
export default {
  name: "nav",
  props:{
      NavActiveIndex:String
  },
},
</script>

(2)子组件向父组件传值:

通过触发组件自定义方式来实现给父组件传值

//父组件 Home.vue
//绑定自定义事件fromNavVal
<Nav v-if="NavOpen" :NavActiveIndex="activeIndex" @fromNavVal="fromNavVal"></Nav>
<div v-else>折叠{{activeIndex2}}</div>
<script>
import Nav from "./Nav.vue";
export default {
  name: "home",
  components: {
    Nav
  },
  data() {
    return {
        activeIndex: ‘/home/buycar‘,
        activeIndex2: ‘1‘,
        NavOpen: true, //Nav打开折叠
    };
  },
  methods: {
    fromNavVal(val){ //自定义方法fromNavVal
       this.activeIndex2 = val;
       this.NavOpen = false;
    }
  }
};
</script>

//子组件 Nav.vue
<button @click="click">折叠Nav</button>
<script>
export default {
  name: "nav",
  props:{
      NavActiveIndex:String
  },
  data() {
    return {
        activeIndex: ‘1‘,
        activeIndex2: ‘123‘
    };
  },
  methods: {
    handleSelect(key, keyPath) {
        console.log(key, keyPath);
    },
    click(){
        //$emit(事件名,传出的参数)
        this.$emit(‘fromNavVal‘,this.activeIndex2)
    }
  }
};
</script>

2、event bus 事件处理中心

这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案 vuex。

具体实现方式:

var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});

例子:实现购物车数量。

先建立一个事件处理中心js文件,bus.js:

import Vue from "vue";
const EventBus = new Vue();

export default EventBus;

在Nav.vue里引入bus.js

<el-menu-item index="/home/buycar">购物车{{buycarCount}}</el-menu-item> <!--4展示购物车数量-->

//1首先在Nav.vue里引入bus.js
<script>
import bus from ‘@/assets/bus.js‘;
export default {
  name: "nav",
  props:{
      NavActiveIndex:String
  },
  data() {
    return {
        activeIndex: ‘1‘,
        activeIndex2: ‘123‘,
        buycarCount: 0, //3购物车数量
    };
  },
  created() {
      //2注册组件
      bus.$on("buycarCountChang",(num) =>{ //监听事件buycarCountChang
          this.buycarCount = num;
      })
  },
}

在buycar.vue里引入bus.js

<script>
//1.引入bus.js
import bus from ‘@/assets/bus.js‘;
export default {
   。。。
   watch: {
       //2.监听list改变
       list:{ //list监听:当key是list,值是函数的时候,是不深度遍历的,也就是对象改变的时候不监听,所以用这种写法
           handler:function(){ //handler处理函数
                let count = 0;
                this.list.forEach( item => {
                    count += parseInt(item.count); //item.count累加
                })
                bus.$emit("buycarCountChang",count); //购物车数量改变的时候触发buycarCountChang事件
            },
            deep:true //true的时候深度监听
       }
   }
}

VueX:状态管理

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

核心模块:State、Getters、Mutations、Actions、Module

1、State:

vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state来获取我们定义的数据。

2、Getters:

Getter相当于vue中的computed计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,这里我们可以通过定义vuex的Getter来获取,Getters 可以用于监听、state中的值的变化,返回计算后的结果。

3、Mutations:

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。但是,mutation只允许同步函数

4、Actions:

官方并不建议我们直接去修改store里面的值,而是让我们去提交一个actions,在actions中提交mutation再去修改状态值。可以异步操作

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

5、Module

Vuex 允许我们将store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

例子:购物车数量改为用VueX管理

在store/index.js里

export default new Vuex.Store({
  state: {
    buycarCount: 0 //1初始化buycarCount数量0
  },
  mutations: {
    //2定义同步方法改变count
    changbuycarCount(state, num) {
        state.buycarCount = num;
    }
  },
  actions: {},
  modules: {}
});

Nav.vue:

<el-menu-item index="/home/buycar">购物车{{this.$store.state.buycarCount}}</el-menu-item>
<!--2直接获取值-->

<script>
//import bus from ‘@/assets/bus.js‘; 不用了注释掉
export default {
   。。。
   1.list不需要监听事件了,注释掉
   created() { //生命周期
    //   bus.$on("buycarCountChang",(num) =>{ //监听事件buycarCountChang  购物车数量改变的时候触发事件
    //       this.buycarCount = num;
    //   })
  },

};
</script>

buycar.vue:

<script>
//import bus from ‘@/assets/bus.js‘; 同样注释掉
export default {
   。。。
   watch: {
       list:{ //监听list
           handler:function(){ //handler处理函数
                let count = 0;
                this.list.forEach( item => {
                    count += parseInt(item.count); //item.count累加
                })
                //bus.$emit("buycarCountChang",count); //购物车数量改变时触发buycarCountChang事件
                //1注释上面代码改为下面代码
                this.$store.commit("changbuycarCount", count); //购物车数量改变时触发changbuycarCount方法
            },
            deep:true //true的时候深度监听
       }
   }
};
</script>

OK,这样就实现了VueX改变接收购物车数量。

当然如果觉得{{this.$store.state.buycarCount}}这种获取数据太繁琐,可以用映射函数来实现。

Nav.vue:

<el-menu-item index="/home/buycar">购物车{{buycarCount}}</el-menu-item>
<!--3直接使用{{buycarCount}}-->

<script>
//import bus from ‘@/assets/bus.js‘;
import {mapState} from "vuex"; //1映射函数 结构赋值 映射到计算属性
export default {
  name: "nav",
  props:{
      NavActiveIndex:String
  },
  data() {
    return {
        activeIndex: ‘1‘,
        activeIndex2: ‘123‘,
        //buycarCount: 0, //4注释掉上面定义的购物车数量 重名冲突
    };
  },
  computed: { //计算属性
      ...mapState([‘buycarCount‘]), //2用...展开运算符把buycarCount展开在资源属性里
  },

};
</script>

好了,用映射函数同样实现VueX改变接收购物车数量的功能。

那么我们的mutations也是有映射函数的,在buycar.vue里也用映射函数的方式来实现:

<script>
//import bus from ‘@/assets/bus.js‘;
import {mapMutations} from ‘vuex‘ //1映射函数 映射到方法
export default {
   。。。
   methods: {
        //2...展开运算符,传一个数组映射成同名的方法changbuycarCount
        ...mapMutations([
            "changbuycarCount"
        ]),
        。。。
   },
   watch: { //watch是vue的监听,一旦监听对象有变化就会执行相应操作
       list:{ //监听list  当key是list,值是函数的时候,是不深度遍历的,也就是说对象改变的时候不监听,所以用这种写法
            handler:function(){ //handler处理函数
                let count = 0;
                this.list.forEach( item => {
                    count += parseInt(item.count); //item.count累加
                })
                //bus.$emit("buycarCountChang",count); //购物车数量改变时触发buycarCountChang事件

                //this.$store.commit("changbuycarCount", count); //购物车数量改变时触发changbuycarCount方法
                //3注释上面代码改为下面代码
                this.changbuycarCount(count); //this实例changbuycarCount方法,把count传过来
            },
            deep:true //true的时候深度监听
        }
   }
};
</script>

OK,功能同样实现。

下面action来实现异步操作:

在store/index.js里定义方法:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    buycarCount: 0 //初始化0
  },
  mutations: {
    //定义同步方法改变count
    changbuycarCount(state, num) {
      state.buycarCount = num;
    }
  },
  actions: {
    //异步改变 第1个参数是上下文 第2个接收调用传参
    asyncchangbuycarCount(content, num) {
      //一般实现ajax,这里就不调用接口,实现一个定时器功能
      setTimeout(() => {
        content.commit("changbuycarCount", num); //content对象的commit方法,来触发mutations
      }, 1000);
    }
  },
  modules: {}
});

修改buycar.vue:

<script>
//import bus from ‘@/assets/bus.js‘;
import {mapMutations} from ‘vuex‘ //映射函数 映射到方法
export default {
   。。。
   watch: { //watch是vue的监听,一旦监听对象有变化就会执行相应操作
        list:{ //监听list  当key是list,值是函数的时候,是不深度遍历的,也就是说对象改变的时候不监听,所以用这种写法
            handler:function(){ //handler处理函数
                let count = 0;
                this.list.forEach( item => {
                    count += parseInt(item.count); //item.count累加
                })
                //bus.$emit("buycarCountChang",count); //购物车数量改变时触发buycarCountChang事件

                //this.$store.commit("changbuycarCount", count); //购物车数量改变时触发changbuycarCount方法
                //this.changbuycarCount(count); //this实例changbuycarCount方法,把count传过来
                //1注释上面代码改为下面代码
                this.$store.dispatch("asyncchangbuycarCount", count);
            },
            deep:true //true的时候深度监听
        }
   }
};
</script>

现在实现操作,1秒钟后改变购物车数量。

action同样有映射函数,直接修改buycar.vue:

<script>
//import bus from ‘@/assets/bus.js‘;
import {mapMutations, mapActions} from ‘vuex‘ //1映射函数 添加mapActions
export default {
   。。。
   methods: {
      ...mapMutations(["changbuycarCount"]), //...展开运算符,传一个数组映射成同名的方法changbuycarCount
      ...mapActions(["asyncchangbuycarCount"]), //2展开 asyncchangbuycarCount
   },
   watch: { //watch是vue的监听,一旦监听对象有变化就会执行相应操作
       list:{ //监听list  当key是list,值是函数的时候,是不深度遍历的,也就是说对象改变的时候不监听,所以用这种写法
            handler:function(){ //handler处理函数
                let count = 0;
                this.list.forEach( item => {
                    count += parseInt(item.count); //item.count累加
                })
                //bus.$emit("buycarCountChang",count); //购物车数量改变时触发buycarCountChang事件

                //this.$store.commit("changbuycarCount", count); //购物车数量改变时触发changbuycarCount方法
                //this.changbuycarCount(count); //this实例changbuycarCount方法,把count传过来

                //this.$store.dispatch("asyncchangbuycarCount", count); //异步的改变asyncchangbuycarCount
                //3注释掉上面代码改为下面代码
                this.asyncchangbuycarCount(count);
            },
            deep:true //true的时候深度监听
        }
   }
};
</script>

同样实现1秒钟后改变购物车数量。

下面用getters来实现在导航Nav上显示名字的功能。

在store/index.js里定义:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    buycarCount: 0, //初始化0
    //1建立用户信息
    userinfo: {
      name: "latte",
      age: 20
    }
  },
  mutations: {
    //定义同步方法改变count
    changbuycarCount(state, num) {
      state.buycarCount = num;
    }
  },
  actions: {
    //异步改变 第1个参数是上下文 第2个接收调用传参
    asyncchangbuycarCount(content, num) {
      //一般实现ajax,这里就不调用接口,实现一个定时器功能
      setTimeout(() => {
        content.commit("changbuycarCount", num); //content对象的commit方法,来触发mutations
      }, 1000);
    }
  },
  //2.getters返回计算属性
  getters: {
    userName(state) {
       return state.userinfo.name; //返回用户name
    }
  },
  modules: {}
});

修改Nav.vue:

<div>{{userName}}</div>
<!--3展示在nav-->
<script>
//import bus from ‘@/assets/bus.js‘;
import {mapState, mapGetters} from "vuex"; //1直接用映射函数 添加mapGetters
export default {
   。。。
   computed: { //计算属性
      ...mapState([‘buycarCount‘]), //用...展开运算符把buycarCount展开在资源属性里
      ...mapGetters([‘userName‘]), //2...展开
   },
   。。。
};
</script>

效果实现了。

注意: 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。当然,还是需要您自己来决定。

原文地址:https://www.cnblogs.com/joe235/p/12015420.html

时间: 2024-10-10 03:43:06

Vue简单基础 + 实例的相关文章

Vue.js 基础实例

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue</title> </head> <body> <hr/>声明式渲染1:<br/><br/> <div id="app"> {{message}} </d

SpringMVC 基础教程 简单入门实例

SpringMVC 基础教程 简单入门实例 标签: Spring MVCspringmvcSpringMVC教程基础教程SpringMVC实例 2013-05-09 13:44 170403人阅读 评论(69) 收藏 举报  分类: Java(23)  Spring框架(3)  版权声明:本文为博主原创文章,未经博主允许不得转载. spring MVC 入门教程二: 一个简单的入门实例教程 该实例的源码和实例中的jar 源码:http://download.csdn.net/detail/swi

vue框架:框架简介,基础实例成员,基础指令,js对象方法补充

1.指令 2.实例成员 3.组件 4.项目开发 1)定义:JavaScript渐进式框架 ? 渐进式:可以控制一个页面的一个标签,也可以控制一系列的标签,也可以控制整个页面,甚至可以控制整个前台项目 2)优势: ? 有指令(分支结构,循环结构...) 复用页面结构等 ? 有实例成员(过滤器,监听), 可以对渲染的数据进行二次格式化 ? 有组件(模板的复用或组合),快速搭建页面 ? ? 虚拟dom:所有文件加载到内存中 ? 数据的双向绑定 ? 单页面应用 ? 数据驱动 3)为什么学习vue: ?

Vue组件基础用法

前面的话 组件(Component)是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.根据项目需求,抽象出一些组件,每个组件里包含了展现.功能和样式.每个页面,根据自己所需,使用不同的组件来拼接页面.这种开发模式使前端页面易于扩展,且灵活性高,而且组件之间也实现了解耦.本文将详细介绍Vue组件基础用法 概述 组件是一个自定义元素或称为一个模块,包括所需的模板.逻辑和样式.在HTML模板中,组件以一个自定义标签的形式存在,起到占位符的功能.通过Vue.js的声明式渲染后,

Vue简单知识点

vue生命周期的理解 什么是vue生命周期? Vue 实例从创建到销毁的过程,就是生命周期.从开始创建.初始化数据.编译模板.挂载Dom→渲染.更新→渲染.销毁等一系列过程,称之为 Vue 的生命周期. vue生命周期总共有几个阶段? 总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后 beforeCreate(创建前) : Vue 实例的挂载元素 $el 和 数据对象data都为undefined,还未初始化. created(创建后) :完成数据观测,属性和方法的运算,初始化事件

Vue.js 基础部分

### Vue.js 基础部分 ## 一. Vue.js 简介 ### 1. Vue.js 是什么 **Vue.js**也称为 Vue,读音/vju:/,类似 view,错误读音 v-u-e 版本: v2.6 - 是一个构建用户界面的框架 - 是一个轻量级 MVVM(Model-View-ViewModel)框架,和 angular.react 类似,其实就是所谓的数据双向绑定 - 数据驱动+组件化的前端开发(核心思想) - 通过简单的 API 实现**响应式的数据绑定**和**组合的视图组件*

Vue框架基础

Vue框架基础 1.什么是vue框架 渐进式的JavaScript框架 渐进式:可以控制一个页面的标签,也可以控制一系列标签,也可以控制整个页面,甚至可以控制整个前端项目 2.vue有什么优势 通俗来讲: 有指令(分支结构,循环结构...),复用页面结构等 有实例成员(过滤器,监听),可以对渲染的数据做二次格式化 有组件(模块的复用与组合),快速搭建页面 官方说法: 虚拟DOM,直接加载的到内存中,加载速度更快 数据的双向绑定 单页面应用 数据驱动 3.为什么要学vue 前端框架主要有三种:An

ngnix 部署 vue项目-基础篇

ngnix 部署 vue项目-基础篇 标签(空格分隔): docker ngnix vue Dockerfile 目录 基础知识 主要知识点 ###1.基础知识 image container docker 命令 build run rm rmi exec Dockerfile npm 打包vue项目 ###2.主要知识点 Dockerfile image container 简单来讲,Dockerfile构建出Docker镜像,通过Docker镜像运行Docker容器. Dockerfile

TypeScript进阶开发——ThreeJs基础实例,从入坑到入门

前言 我们前面使用的是自己编写的ts,以及自己手动引入的jquery,由于第三方库采用的是直接引入js,没有d.ts声明文件,开发起来很累,所以一般情况下我们使用npm引入第三方的库,本文记录使用npm,typescript开发threejs3D项目,搭建基础实例,为以后开发具体业务做准备 项目结构   依旧是熟悉的SpringBoot项目,不同以往的是使用了npm管理工具来下载依赖js库,类似maven,同时为了解决typescript编译后引入npm库的路径有问题,导致浏览器报错的问题,我们