更改订单功能加载会意外中断代码

时间:2013-11-29 20:44:56

标签: javascript jquery

我有一个看起来像这样的脚本:

function autoCorrect(searchString, replaceString) {
    $("body").on("keyup", "textarea", function() {
        // finds current cursor position
        var pos = $(this).prop("selectionStart");
        // this turns the textarea in a string
        var text = $(this).val();
        //only search for strings just typed
        var stringToSearch = text.substring(pos - searchString.length, pos);
        if (searchString == stringToSearch) {
            //if there is a match put the replaceString in the right place
            var newText = text.substring(0, pos - searchString.length) + replaceString + text.substring(pos);
            $(this).val(newText);
            //adjust the cursor position to the new text
            var newpos = pos - searchString.length + replaceString.length;
            this.setSelectionRange(newpos, newpos);
        }
    });
}
autoCorrect("=>", '⇒');
autoCorrect("->", "→");
autoCorrect("+-", "±");
autoCorrect("<=", "≤");
autoCorrect(">=", "≥");

现在,我想稍微改变它,我想改变函数运行的顺序。像这样:

$("body").on("keyup", "textarea", function() {
    function autoCorrect(searchString, replaceString) {
        // finds current cursor position
        var pos = $(this).prop("selectionStart");
        // this turns the textarea in a string
        var text = $(this).val();
        //only search for strings just typed
        var stringToSearch = text.substring(pos - searchString.length, pos);
        if (searchString == stringToSearch) {
            //if there is a match put the replaceString in the right place
            var newText = text.substring(0, pos - searchString.length) + replaceString + text.substring(pos);
            $(this).val(newText);
            //adjust the cursor position to the new text
            var newpos = pos - searchString.length + replaceString.length;
            this.setSelectionRange(newpos, newpos);
        }
    }
    autoCorrect("=>", '⇒');
    autoCorrect("->", "→");
    autoCorrect("+-", "±");
    autoCorrect("<=", "≤");
    autoCorrect(">=", "≥");
});

但是这个脚本不再像这样了。我只是不明白为什么这会破坏我的代码。

这是我的jsfiddle:http://jsfiddle.net/4SWy6/4/

3 个答案:

答案 0 :(得分:2)

新功能会创建一个新范围:

$("body").on("keyup", "textarea", function () {
    autoCorrect("=>", '⇒', this);
    autoCorrect("->", "→", this);
    autoCorrect("+-", "±", this);
    autoCorrect("<=", "≤", this);
    autoCorrect(">=", "≥", this);
});

function autoCorrect(searchString, replaceString, elem) {
    var acList = {
        "=>": '⇒',
        "->": "→",
        "+-": "±",
        "<=": "≤",
        ">=": "≥"
    },
        pos = elem.selectionStart,
        text = elem.value,
        stringToSearch = text.substring(pos - searchString.length, pos);

    if (searchString == stringToSearch) {
        var newpos = pos - searchString.length + replaceString.length;
        elem.value = text.substring(0, pos - searchString.length) + replaceString + text.substring(pos);
        this.setSelectionRange(newpos, newpos);
    }
}

FIDDLE

修改

基于评论,询问你是否可以传递一个键/值对的对象与元素一起被替换,我做了这个,这应该适用于你传递的任何对象:

$("body").on("keyup", "textarea", function () {
    var acList = {
        "=>": '⇒',
        "->": "→",
        "+-": "±",
        "<=": "≤",
        ">=": "≥"
    };
    autoCorrect(acList, this);
});

function autoCorrect(acList, elem) {
    var regstr = Object.keys(acList).join("|").replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$]/g, "\\$&"),
        reg    = new RegExp('('+ regstr +')', "gi"),
        pos    = elem.selectionStart,
        diff   = 0;

    elem.value = elem.value.replace(reg, function(x) {
        diff += x.length - acList[x].length;
        return acList[x];
    });

    elem.setSelectionRange(pos-diff, pos-diff);
}

FIDDLE

作为旁注,这不是真正的跨浏览器,因为selectionStartsetSelectionRange在所有浏览器中都不起作用,Object.keys也不起作用,因此根据您的浏览器而定需要支持,你可能需要填充这些方法。

答案 1 :(得分:1)

在内部函数中,$(this)实际上并不是您正在寻找的jQuery对象。那是因为this被设置为窗口对象。观察:

function outer() {
  function inner() {
    return this;
  }
  console.log(this, inner());
}

outer.call({ this: "is an object" });

这将记录:

{ this: "is an object" }
[Object Window]

JS的范围界定行为很奇怪。 this非常神奇,你只能在它设置的地方真正信任它的价值。否则,它可能是window

函数上的

.call调用函数,并将this设置为第一个参数,在本例中为{ this: "is an object" }。这称为“绑定”。 这就是为什么在outer中,this指的是我们的对象。我们说outer绑定到该对象。在inner中,我们应该不信任this,因为它没有明确地绑定到任何东西 - 所以它可能是window

与该例子类似:

$('body').on('click', function clickCallback() {
  // `this` refers to the element that jQuery set it to,
  // as it called the `clickCallback` function with .call(element)
  $(this).css({ 'background-color': '#f00' });
  // We now have a bright red background!
  function changeColor() {
    // `this` refers to `window`!!!
    // We didn't bind it :(
    $(this).css({ color: '#0f0' });
    // Text color will not be changed!
  }
  changeColor();
});

在内部,jQuery使用.call方法调用clickCallback,将回调的this绑定到被单击的元素。因此,我们面临与outerinner函数完全相同的情况。

问题的解决方案是:1)将内部函数绑定到外部this或2)保存外部this以便在内部函数中使用。

通常你想要选择后者。首先,您需要始终.call您的函数(autoCorrect.call(this, "=>", '⇒');),这是丑陋的,或者使用.bind一次(autoCorrect = autoCorrect.bind(this);),但是也不酷,因为并非所有浏览器都支持函数的.bind方法,而且它看起来更慢。

在你的情况下,选择后一种选择:

$("body").on("keyup", "textarea", function() {
    // Store `this` for use in the inner function
    var self = this;
    function autoCorrect(searchString, replaceString) {
        // `self` will now be the element we're looking for!
        // finds current cursor position
        var pos = $(self).prop("selectionStart");
        // this turns the textarea in a string
        var text = $(self).val();
        // [...]
    }
    autoCorrect("=>", '⇒');
    autoCorrect("->", "→");
    autoCorrect("+-", "±");
    autoCorrect("<=", "≤");
    autoCorrect(">=", "≥");
});

答案 2 :(得分:0)

$("body").on("keyup", "textarea", function () {
    $(this).val($(this).val()
        .replace(/=>/g, "⇒")
        .replace(/=>/g, "⇒")
        .replace(/->/g, "→")
        .replace(/\+-/g, "±")
        .replace(/<=/g, "≥")
        .replace(/>=/g, "≥"));
});

DEMO